Browse Source

Merge branch 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm

Pull ARM updates from Russell King:
 "The major updates included in this update are:

   - Clang compatible stack pointer accesses by Behan Webster.
   - SA11x0 updates from Dmitry Eremin-Solenikov.
   - kgdb handling of breakpoints with read-only text/modules
   - Support for Privileged-no-execute feature on ARMv7 to prevent
     userspace code execution by the kernel.
   - AMBA primecell bus handling of irq-safe runtime PM
   - Unwinding support for memset/memzero/memmove/memcpy functions
   - VFP fixes for Krait CPUs and improvements in detecting the VFP
     architecture
   - A number of code cleanups (using pr_*, removing or reducing the
     severity of a couple of kernel messages, splitting ftrace asm code
     out to a separate file, etc.)
   - Add machine name to stack dump output"

* 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm: (62 commits)
  ARM: 8247/2: pcmcia: sa1100: make use of device clock
  ARM: 8246/2: pcmcia: sa1111: provide device clock
  ARM: 8245/1: pcmcia: soc-common: enable/disable socket clocks
  ARM: 8244/1: fbdev: sa1100fb: make use of device clock
  ARM: 8243/1: sa1100: add a clock alias for sa1111 pcmcia device
  ARM: 8242/1: sa1100: add cpu clock
  ARM: 8221/1: PJ4: allow building in Thumb-2 mode
  ARM: 8234/1: sa1100: reorder IRQ handling code
  ARM: 8233/1: sa1100: switch to hwirq usage
  ARM: 8232/1: sa1100: merge GPIO multiplexer IRQ to "normal" irq domain
  ARM: 8231/1: sa1100: introduce irqdomains support
  ARM: 8230/1: sa1100: shift IRQs by one
  ARM: 8229/1: sa1100: replace irq numbers with names in irq driver
  ARM: 8228/1: sa1100: drop entry-macro.S
  ARM: 8227/1: sa1100: switch to MULTI_IRQ_HANDLER
  ARM: 8241/1: Update processor_modes for hyp and monitor mode
  ARM: 8240/1: MCPM: document mcpm_sync_init()
  ARM: 8239/1: Introduce {set,clear}_pte_bit
  ARM: 8238/1: mm: Refine set_memory_* functions
  ARM: 8237/1: fix flush_pfn_alias
  ...
Linus Torvalds 11 năm trước cách đây
mục cha
commit
26ceb127f7
92 tập tin đã thay đổi với 1592 bổ sung850 xóa
  1. 1 1
      Documentation/arm/memory.txt
  2. 4 0
      Documentation/power/runtime_pm.txt
  3. 2 0
      arch/arm/Kconfig
  4. 6 7
      arch/arm/common/sa1111.c
  5. 10 0
      arch/arm/include/asm/cacheflush.h
  6. 14 17
      arch/arm/include/asm/fixmap.h
  7. 1 0
      arch/arm/include/asm/hw_irq.h
  8. 17 0
      arch/arm/include/asm/mcpm.h
  9. 2 2
      arch/arm/include/asm/percpu.h
  10. 9 1
      arch/arm/include/asm/pgalloc.h
  11. 2 0
      arch/arm/include/asm/pgtable-2level-hwdef.h
  12. 1 0
      arch/arm/include/asm/pgtable-3level-hwdef.h
  13. 51 11
      arch/arm/include/asm/pgtable.h
  14. 2 3
      arch/arm/include/asm/ptrace.h
  15. 7 2
      arch/arm/include/asm/thread_info.h
  16. 5 0
      arch/arm/include/asm/vfp.h
  17. 3 1
      arch/arm/kernel/Makefile
  18. 2 4
      arch/arm/kernel/atags_compat.c
  19. 2 3
      arch/arm/kernel/atags_parse.c
  20. 2 2
      arch/arm/kernel/atags_proc.c
  21. 1 1
      arch/arm/kernel/bios32.c
  22. 2 2
      arch/arm/kernel/dma-isa.c
  23. 11 15
      arch/arm/kernel/dma.c
  24. 0 235
      arch/arm/kernel/entry-common.S
  25. 243 0
      arch/arm/kernel/entry-ftrace.S
  26. 6 6
      arch/arm/kernel/etm.c
  27. 1 1
      arch/arm/kernel/fiq.c
  28. 19 0
      arch/arm/kernel/ftrace.c
  29. 2 3
      arch/arm/kernel/io.c
  30. 4 4
      arch/arm/kernel/irq.c
  31. 13 0
      arch/arm/kernel/iwmmxt.S
  32. 1 1
      arch/arm/kernel/jump_label.c
  33. 29 0
      arch/arm/kernel/kgdb.c
  34. 8 7
      arch/arm/kernel/machine_kexec.c
  35. 1 1
      arch/arm/kernel/module.c
  36. 73 19
      arch/arm/kernel/patch.c
  37. 11 1
      arch/arm/kernel/patch.h
  38. 2 2
      arch/arm/kernel/process.c
  39. 1 2
      arch/arm/kernel/return_address.c
  40. 1 0
      arch/arm/kernel/setup.c
  41. 0 1
      arch/arm/kernel/signal.c
  42. 6 9
      arch/arm/kernel/smp.c
  43. 2 2
      arch/arm/kernel/smp_twd.c
  44. 1 3
      arch/arm/kernel/stacktrace.c
  45. 1 1
      arch/arm/kernel/swp_emulate.c
  46. 1 1
      arch/arm/kernel/thumbee.c
  47. 2 2
      arch/arm/kernel/topology.c
  48. 21 21
      arch/arm/kernel/traps.c
  49. 1 2
      arch/arm/kernel/unwind.c
  50. 19 0
      arch/arm/kernel/vmlinux.lds.S
  51. 3 4
      arch/arm/kernel/xscale-cp0.c
  52. 5 0
      arch/arm/lib/copy_from_user.S
  53. 30 0
      arch/arm/lib/copy_template.S
  54. 5 0
      arch/arm/lib/copy_to_user.S
  55. 5 0
      arch/arm/lib/memcpy.S
  56. 28 0
      arch/arm/lib/memmove.S
  57. 12 0
      arch/arm/lib/memset.S
  58. 12 0
      arch/arm/lib/memzero.S
  59. 36 7
      arch/arm/mach-sa1100/clock.c
  60. 7 48
      arch/arm/mach-sa1100/collie.c
  61. 0 41
      arch/arm/mach-sa1100/include/mach/entry-macro.S
  62. 51 51
      arch/arm/mach-sa1100/include/mach/irqs.h
  63. 130 99
      arch/arm/mach-sa1100/irq.c
  64. 21 0
      arch/arm/mm/Kconfig
  65. 1 1
      arch/arm/mm/Makefile
  66. 5 5
      arch/arm/mm/alignment.c
  67. 3 3
      arch/arm/mm/cache-feroceon-l2.c
  68. 6 6
      arch/arm/mm/cache-tauros2.c
  69. 34 24
      arch/arm/mm/context.c
  70. 1 1
      arch/arm/mm/copypage-v6.c
  71. 3 3
      arch/arm/mm/fault-armv.c
  72. 15 16
      arch/arm/mm/fault.c
  73. 1 1
      arch/arm/mm/flush.c
  74. 8 7
      arch/arm/mm/highmem.c
  75. 149 4
      arch/arm/mm/init.c
  76. 64 63
      arch/arm/mm/mmu.c
  77. 91 0
      arch/arm/mm/pageattr.c
  78. 3 2
      arch/arm/mm/proc-v7.S
  79. 4 4
      arch/arm/nwfpe/fpmodule.c
  80. 6 0
      arch/arm/vfp/vfphw.S
  81. 56 46
      arch/arm/vfp/vfpmodule.c
  82. 1 1
      arch/arm/vfp/vfpsingle.c
  83. 11 4
      drivers/amba/bus.c
  84. 95 4
      drivers/dma/pl330.c
  85. 1 0
      drivers/pcmcia/sa1100_generic.c
  86. 7 0
      drivers/pcmcia/sa1111_generic.c
  87. 12 2
      drivers/pcmcia/sa11xx_base.c
  88. 4 0
      drivers/pcmcia/soc_common.c
  89. 23 7
      drivers/video/fbdev/sa1100fb.c
  90. 1 0
      drivers/video/fbdev/sa1100fb.h
  91. 10 0
      include/linux/amba/bus.h
  92. 6 0
      include/linux/pm_runtime.h

+ 1 - 1
Documentation/arm/memory.txt

@@ -41,7 +41,7 @@ fffe8000	fffeffff	DTCM mapping area for platforms with
 fffe0000	fffe7fff	ITCM mapping area for platforms with
 fffe0000	fffe7fff	ITCM mapping area for platforms with
 				ITCM mounted inside the CPU.
 				ITCM mounted inside the CPU.
 
 
-ffc00000	ffdfffff	Fixmap mapping region.  Addresses provided
+ffc00000	ffefffff	Fixmap mapping region.  Addresses provided
 				by fix_to_virt() will be located here.
 				by fix_to_virt() will be located here.
 
 
 fee00000	feffffff	Mapping of PCI I/O space. This is a static
 fee00000	feffffff	Mapping of PCI I/O space. This is a static

+ 4 - 0
Documentation/power/runtime_pm.txt

@@ -468,6 +468,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
     - set the power.irq_safe flag for the device, causing the runtime-PM
     - set the power.irq_safe flag for the device, causing the runtime-PM
       callbacks to be invoked with interrupts off
       callbacks to be invoked with interrupts off
 
 
+  bool pm_runtime_is_irq_safe(struct device *dev);
+    - return true if power.irq_safe flag was set for the device, causing
+      the runtime-PM callbacks to be invoked with interrupts off
+
   void pm_runtime_mark_last_busy(struct device *dev);
   void pm_runtime_mark_last_busy(struct device *dev);
     - set the power.last_busy field to the current time
     - set the power.last_busy field to the current time
 
 

+ 2 - 0
arch/arm/Kconfig

@@ -687,7 +687,9 @@ config ARCH_SA1100
 	select CPU_SA1100
 	select CPU_SA1100
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_CLOCKEVENTS
 	select HAVE_IDE
 	select HAVE_IDE
+	select IRQ_DOMAIN
 	select ISA
 	select ISA
+	select MULTI_IRQ_HANDLER
 	select NEED_MACH_MEMORY_H
 	select NEED_MACH_MEMORY_H
 	select SPARSE_IRQ
 	select SPARSE_IRQ
 	help
 	help

+ 6 - 7
arch/arm/common/sa1111.c

@@ -282,8 +282,8 @@ static int sa1111_retrigger_lowirq(struct irq_data *d)
 	}
 	}
 
 
 	if (i == 8)
 	if (i == 8)
-		printk(KERN_ERR "Danger Will Robinson: failed to "
-			"re-trigger IRQ%d\n", d->irq);
+		pr_err("Danger Will Robinson: failed to re-trigger IRQ%d\n",
+		       d->irq);
 	return i == 8 ? -1 : 0;
 	return i == 8 ? -1 : 0;
 }
 }
 
 
@@ -384,8 +384,8 @@ static int sa1111_retrigger_highirq(struct irq_data *d)
 	}
 	}
 
 
 	if (i == 8)
 	if (i == 8)
-		printk(KERN_ERR "Danger Will Robinson: failed to "
-			"re-trigger IRQ%d\n", d->irq);
+		pr_err("Danger Will Robinson: failed to re-trigger IRQ%d\n",
+		       d->irq);
 	return i == 8 ? -1 : 0;
 	return i == 8 ? -1 : 0;
 }
 }
 
 
@@ -740,9 +740,8 @@ static int __sa1111_probe(struct device *me, struct resource *mem, int irq)
 		goto err_unmap;
 		goto err_unmap;
 	}
 	}
 
 
-	printk(KERN_INFO "SA1111 Microprocessor Companion Chip: "
-		"silicon revision %lx, metal revision %lx\n",
-		(id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK));
+	pr_info("SA1111 Microprocessor Companion Chip: silicon revision %lx, metal revision %lx\n",
+		(id & SKID_SIREV_MASK) >> 4, id & SKID_MTREV_MASK);
 
 
 	/*
 	/*
 	 * We found it.  Wake the chip up, and initialise.
 	 * We found it.  Wake the chip up, and initialise.

+ 10 - 0
arch/arm/include/asm/cacheflush.h

@@ -487,6 +487,16 @@ int set_memory_rw(unsigned long addr, int numpages);
 int set_memory_x(unsigned long addr, int numpages);
 int set_memory_x(unsigned long addr, int numpages);
 int set_memory_nx(unsigned long addr, int numpages);
 int set_memory_nx(unsigned long addr, int numpages);
 
 
+#ifdef CONFIG_DEBUG_RODATA
+void mark_rodata_ro(void);
+void set_kernel_text_rw(void);
+void set_kernel_text_ro(void);
+#else
+static inline void set_kernel_text_rw(void) { }
+static inline void set_kernel_text_ro(void) { }
+#endif
+
 void flush_uprobe_xol_access(struct page *page, unsigned long uaddr,
 void flush_uprobe_xol_access(struct page *page, unsigned long uaddr,
 			     void *kaddr, unsigned long len);
 			     void *kaddr, unsigned long len);
+
 #endif
 #endif

+ 14 - 17
arch/arm/include/asm/fixmap.h

@@ -2,27 +2,24 @@
 #define _ASM_FIXMAP_H
 #define _ASM_FIXMAP_H
 
 
 #define FIXADDR_START		0xffc00000UL
 #define FIXADDR_START		0xffc00000UL
-#define FIXADDR_TOP		0xffe00000UL
-#define FIXADDR_SIZE		(FIXADDR_TOP - FIXADDR_START)
+#define FIXADDR_END		0xfff00000UL
+#define FIXADDR_TOP		(FIXADDR_END - PAGE_SIZE)
 
 
-#define FIX_KMAP_NR_PTES	(FIXADDR_SIZE >> PAGE_SHIFT)
+#include <asm/kmap_types.h>
 
 
-#define __fix_to_virt(x)	(FIXADDR_START + ((x) << PAGE_SHIFT))
-#define __virt_to_fix(x)	(((x) - FIXADDR_START) >> PAGE_SHIFT)
+enum fixed_addresses {
+	FIX_KMAP_BEGIN,
+	FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * NR_CPUS) - 1,
 
 
-extern void __this_fixmap_does_not_exist(void);
+	/* Support writing RO kernel text via kprobes, jump labels, etc. */
+	FIX_TEXT_POKE0,
+	FIX_TEXT_POKE1,
 
 
-static inline unsigned long fix_to_virt(const unsigned int idx)
-{
-	if (idx >= FIX_KMAP_NR_PTES)
-		__this_fixmap_does_not_exist();
-	return __fix_to_virt(idx);
-}
+	__end_of_fixed_addresses
+};
 
 
-static inline unsigned int virt_to_fix(const unsigned long vaddr)
-{
-	BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
-	return __virt_to_fix(vaddr);
-}
+void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
+
+#include <asm-generic/fixmap.h>
 
 
 #endif
 #endif

+ 1 - 0
arch/arm/include/asm/hw_irq.h

@@ -8,6 +8,7 @@ static inline void ack_bad_irq(int irq)
 {
 {
 	extern unsigned long irq_err_count;
 	extern unsigned long irq_err_count;
 	irq_err_count++;
 	irq_err_count++;
+	pr_crit("unexpected IRQ trap at vector %02x\n", irq);
 }
 }
 
 
 void set_irq_flags(unsigned int irq, unsigned int flags);
 void set_irq_flags(unsigned int irq, unsigned int flags);

+ 17 - 0
arch/arm/include/asm/mcpm.h

@@ -219,6 +219,23 @@ void __mcpm_outbound_leave_critical(unsigned int cluster, int state);
 bool __mcpm_outbound_enter_critical(unsigned int this_cpu, unsigned int cluster);
 bool __mcpm_outbound_enter_critical(unsigned int this_cpu, unsigned int cluster);
 int __mcpm_cluster_state(unsigned int cluster);
 int __mcpm_cluster_state(unsigned int cluster);
 
 
+/**
+ * mcpm_sync_init - Initialize the cluster synchronization support
+ *
+ * @power_up_setup: platform specific function invoked during very
+ * 		    early CPU/cluster bringup stage.
+ *
+ * This prepares memory used by vlocks and the MCPM state machine used
+ * across CPUs that may have their caches active or inactive. Must be
+ * called only after a successful call to mcpm_platform_register().
+ *
+ * The power_up_setup argument is a pointer to assembly code called when
+ * the MMU and caches are still disabled during boot  and no stack space is
+ * available. The affinity level passed to that code corresponds to the
+ * resource that needs to be initialized (e.g. 1 for cluster level, 0 for
+ * CPU level).  Proper exclusion mechanisms are already activated at that
+ * point.
+ */
 int __init mcpm_sync_init(
 int __init mcpm_sync_init(
 	void (*power_up_setup)(unsigned int affinity_level));
 	void (*power_up_setup)(unsigned int affinity_level));
 
 

+ 2 - 2
arch/arm/include/asm/percpu.h

@@ -30,14 +30,14 @@ static inline void set_my_cpu_offset(unsigned long off)
 static inline unsigned long __my_cpu_offset(void)
 static inline unsigned long __my_cpu_offset(void)
 {
 {
 	unsigned long off;
 	unsigned long off;
-	register unsigned long *sp asm ("sp");
 
 
 	/*
 	/*
 	 * Read TPIDRPRW.
 	 * Read TPIDRPRW.
 	 * We want to allow caching the value, so avoid using volatile and
 	 * We want to allow caching the value, so avoid using volatile and
 	 * instead use a fake stack read to hazard against barrier().
 	 * instead use a fake stack read to hazard against barrier().
 	 */
 	 */
-	asm("mrc p15, 0, %0, c13, c0, 4" : "=r" (off) : "Q" (*sp));
+	asm("mrc p15, 0, %0, c13, c0, 4" : "=r" (off)
+		: "Q" (*(const unsigned long *)current_stack_pointer));
 
 
 	return off;
 	return off;
 }
 }

+ 9 - 1
arch/arm/include/asm/pgalloc.h

@@ -157,7 +157,15 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
 static inline void
 static inline void
 pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
 pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
 {
 {
-	__pmd_populate(pmdp, page_to_phys(ptep), _PAGE_USER_TABLE);
+	extern pmdval_t user_pmd_table;
+	pmdval_t prot;
+
+	if (__LINUX_ARM_ARCH__ >= 6 && !IS_ENABLED(CONFIG_ARM_LPAE))
+		prot = user_pmd_table;
+	else
+		prot = _PAGE_USER_TABLE;
+
+	__pmd_populate(pmdp, page_to_phys(ptep), prot);
 }
 }
 #define pmd_pgtable(pmd) pmd_page(pmd)
 #define pmd_pgtable(pmd) pmd_page(pmd)
 
 

+ 2 - 0
arch/arm/include/asm/pgtable-2level-hwdef.h

@@ -20,12 +20,14 @@
 #define PMD_TYPE_FAULT		(_AT(pmdval_t, 0) << 0)
 #define PMD_TYPE_FAULT		(_AT(pmdval_t, 0) << 0)
 #define PMD_TYPE_TABLE		(_AT(pmdval_t, 1) << 0)
 #define PMD_TYPE_TABLE		(_AT(pmdval_t, 1) << 0)
 #define PMD_TYPE_SECT		(_AT(pmdval_t, 2) << 0)
 #define PMD_TYPE_SECT		(_AT(pmdval_t, 2) << 0)
+#define PMD_PXNTABLE		(_AT(pmdval_t, 1) << 2)     /* v7 */
 #define PMD_BIT4		(_AT(pmdval_t, 1) << 4)
 #define PMD_BIT4		(_AT(pmdval_t, 1) << 4)
 #define PMD_DOMAIN(x)		(_AT(pmdval_t, (x)) << 5)
 #define PMD_DOMAIN(x)		(_AT(pmdval_t, (x)) << 5)
 #define PMD_PROTECTION		(_AT(pmdval_t, 1) << 9)		/* v5 */
 #define PMD_PROTECTION		(_AT(pmdval_t, 1) << 9)		/* v5 */
 /*
 /*
  *   - section
  *   - section
  */
  */
+#define PMD_SECT_PXN    (_AT(pmdval_t, 1) << 0)     /* v7 */
 #define PMD_SECT_BUFFERABLE	(_AT(pmdval_t, 1) << 2)
 #define PMD_SECT_BUFFERABLE	(_AT(pmdval_t, 1) << 2)
 #define PMD_SECT_CACHEABLE	(_AT(pmdval_t, 1) << 3)
 #define PMD_SECT_CACHEABLE	(_AT(pmdval_t, 1) << 3)
 #define PMD_SECT_XN		(_AT(pmdval_t, 1) << 4)		/* v6 */
 #define PMD_SECT_XN		(_AT(pmdval_t, 1) << 4)		/* v6 */

+ 1 - 0
arch/arm/include/asm/pgtable-3level-hwdef.h

@@ -76,6 +76,7 @@
 #define PTE_EXT_SHARED		(_AT(pteval_t, 3) << 8)		/* SH[1:0], inner shareable */
 #define PTE_EXT_SHARED		(_AT(pteval_t, 3) << 8)		/* SH[1:0], inner shareable */
 #define PTE_EXT_AF		(_AT(pteval_t, 1) << 10)	/* Access Flag */
 #define PTE_EXT_AF		(_AT(pteval_t, 1) << 10)	/* Access Flag */
 #define PTE_EXT_NG		(_AT(pteval_t, 1) << 11)	/* nG */
 #define PTE_EXT_NG		(_AT(pteval_t, 1) << 11)	/* nG */
+#define PTE_EXT_PXN		(_AT(pteval_t, 1) << 53)	/* PXN */
 #define PTE_EXT_XN		(_AT(pteval_t, 1) << 54)	/* XN */
 #define PTE_EXT_XN		(_AT(pteval_t, 1) << 54)	/* XN */
 
 
 /*
 /*

+ 51 - 11
arch/arm/include/asm/pgtable.h

@@ -252,17 +252,57 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 	set_pte_ext(ptep, pteval, ext);
 	set_pte_ext(ptep, pteval, ext);
 }
 }
 
 
-#define PTE_BIT_FUNC(fn,op) \
-static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
-
-PTE_BIT_FUNC(wrprotect, |= L_PTE_RDONLY);
-PTE_BIT_FUNC(mkwrite,   &= ~L_PTE_RDONLY);
-PTE_BIT_FUNC(mkclean,   &= ~L_PTE_DIRTY);
-PTE_BIT_FUNC(mkdirty,   |= L_PTE_DIRTY);
-PTE_BIT_FUNC(mkold,     &= ~L_PTE_YOUNG);
-PTE_BIT_FUNC(mkyoung,   |= L_PTE_YOUNG);
-PTE_BIT_FUNC(mkexec,   &= ~L_PTE_XN);
-PTE_BIT_FUNC(mknexec,   |= L_PTE_XN);
+static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
+{
+	pte_val(pte) &= ~pgprot_val(prot);
+	return pte;
+}
+
+static inline pte_t set_pte_bit(pte_t pte, pgprot_t prot)
+{
+	pte_val(pte) |= pgprot_val(prot);
+	return pte;
+}
+
+static inline pte_t pte_wrprotect(pte_t pte)
+{
+	return set_pte_bit(pte, __pgprot(L_PTE_RDONLY));
+}
+
+static inline pte_t pte_mkwrite(pte_t pte)
+{
+	return clear_pte_bit(pte, __pgprot(L_PTE_RDONLY));
+}
+
+static inline pte_t pte_mkclean(pte_t pte)
+{
+	return clear_pte_bit(pte, __pgprot(L_PTE_DIRTY));
+}
+
+static inline pte_t pte_mkdirty(pte_t pte)
+{
+	return set_pte_bit(pte, __pgprot(L_PTE_DIRTY));
+}
+
+static inline pte_t pte_mkold(pte_t pte)
+{
+	return clear_pte_bit(pte, __pgprot(L_PTE_YOUNG));
+}
+
+static inline pte_t pte_mkyoung(pte_t pte)
+{
+	return set_pte_bit(pte, __pgprot(L_PTE_YOUNG));
+}
+
+static inline pte_t pte_mkexec(pte_t pte)
+{
+	return clear_pte_bit(pte, __pgprot(L_PTE_XN));
+}
+
+static inline pte_t pte_mknexec(pte_t pte)
+{
+	return set_pte_bit(pte, __pgprot(L_PTE_XN));
+}
 
 
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
 {

+ 2 - 3
arch/arm/include/asm/ptrace.h

@@ -154,9 +154,8 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
 	return regs->ARM_sp;
 	return regs->ARM_sp;
 }
 }
 
 
-#define current_pt_regs(void) ({				\
-	register unsigned long sp asm ("sp");			\
-	(struct pt_regs *)((sp | (THREAD_SIZE - 1)) - 7) - 1;	\
+#define current_pt_regs(void) ({ (struct pt_regs *)			\
+		((current_stack_pointer | (THREAD_SIZE - 1)) - 7) - 1;	\
 })
 })
 
 
 #endif /* __ASSEMBLY__ */
 #endif /* __ASSEMBLY__ */

+ 7 - 2
arch/arm/include/asm/thread_info.h

@@ -89,6 +89,11 @@ struct thread_info {
 #define init_thread_info	(init_thread_union.thread_info)
 #define init_thread_info	(init_thread_union.thread_info)
 #define init_stack		(init_thread_union.stack)
 #define init_stack		(init_thread_union.stack)
 
 
+/*
+ * how to get the current stack pointer in C
+ */
+register unsigned long current_stack_pointer asm ("sp");
+
 /*
 /*
  * how to get the thread information struct from C
  * how to get the thread information struct from C
  */
  */
@@ -96,8 +101,8 @@ static inline struct thread_info *current_thread_info(void) __attribute_const__;
 
 
 static inline struct thread_info *current_thread_info(void)
 static inline struct thread_info *current_thread_info(void)
 {
 {
-	register unsigned long sp asm ("sp");
-	return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
+	return (struct thread_info *)
+		(current_stack_pointer & ~(THREAD_SIZE - 1));
 }
 }
 
 
 #define thread_saved_pc(tsk)	\
 #define thread_saved_pc(tsk)	\

+ 5 - 0
arch/arm/include/asm/vfp.h

@@ -22,6 +22,7 @@
 #define FPSID_NODOUBLE		(1<<20)
 #define FPSID_NODOUBLE		(1<<20)
 #define FPSID_ARCH_BIT		(16)
 #define FPSID_ARCH_BIT		(16)
 #define FPSID_ARCH_MASK		(0xF  << FPSID_ARCH_BIT)
 #define FPSID_ARCH_MASK		(0xF  << FPSID_ARCH_BIT)
+#define FPSID_CPUID_ARCH_MASK	(0x7F  << FPSID_ARCH_BIT)
 #define FPSID_PART_BIT		(8)
 #define FPSID_PART_BIT		(8)
 #define FPSID_PART_MASK		(0xFF << FPSID_PART_BIT)
 #define FPSID_PART_MASK		(0xFF << FPSID_PART_BIT)
 #define FPSID_VARIANT_BIT	(4)
 #define FPSID_VARIANT_BIT	(4)
@@ -75,6 +76,10 @@
 /* MVFR0 bits */
 /* MVFR0 bits */
 #define MVFR0_A_SIMD_BIT	(0)
 #define MVFR0_A_SIMD_BIT	(0)
 #define MVFR0_A_SIMD_MASK	(0xf << MVFR0_A_SIMD_BIT)
 #define MVFR0_A_SIMD_MASK	(0xf << MVFR0_A_SIMD_BIT)
+#define MVFR0_SP_BIT		(4)
+#define MVFR0_SP_MASK		(0xf << MVFR0_SP_BIT)
+#define MVFR0_DP_BIT		(8)
+#define MVFR0_DP_MASK		(0xf << MVFR0_DP_BIT)
 
 
 /* Bit patterns for decoding the packaged operation descriptors */
 /* Bit patterns for decoding the packaged operation descriptors */
 #define VFPOPDESC_LENGTH_BIT	(9)
 #define VFPOPDESC_LENGTH_BIT	(9)

+ 3 - 1
arch/arm/kernel/Makefile

@@ -47,6 +47,7 @@ endif
 obj-$(CONFIG_HAVE_ARM_SCU)	+= smp_scu.o
 obj-$(CONFIG_HAVE_ARM_SCU)	+= smp_scu.o
 obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.o
 obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.o
 obj-$(CONFIG_ARM_ARCH_TIMER)	+= arch_timer.o
 obj-$(CONFIG_ARM_ARCH_TIMER)	+= arch_timer.o
+obj-$(CONFIG_FUNCTION_TRACER)	+= entry-ftrace.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o
 obj-$(CONFIG_JUMP_LABEL)	+= jump_label.o insn.o patch.o
 obj-$(CONFIG_JUMP_LABEL)	+= jump_label.o insn.o patch.o
@@ -67,7 +68,7 @@ test-kprobes-objs		+= kprobes-test-arm.o
 endif
 endif
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
 obj-$(CONFIG_ARM_THUMBEE)	+= thumbee.o
-obj-$(CONFIG_KGDB)		+= kgdb.o
+obj-$(CONFIG_KGDB)		+= kgdb.o patch.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_OF)		+= devtree.o
 obj-$(CONFIG_OF)		+= devtree.o
@@ -84,6 +85,7 @@ obj-$(CONFIG_CPU_PJ4B)		+= pj4-cp0.o
 obj-$(CONFIG_IWMMXT)		+= iwmmxt.o
 obj-$(CONFIG_IWMMXT)		+= iwmmxt.o
 obj-$(CONFIG_PERF_EVENTS)	+= perf_regs.o perf_callchain.o
 obj-$(CONFIG_PERF_EVENTS)	+= perf_regs.o perf_callchain.o
 obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o perf_event_cpu.o
 obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o perf_event_cpu.o
+CFLAGS_pj4-cp0.o		:= -marm
 AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
 AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt
 obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o
 obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o
 
 

+ 2 - 4
arch/arm/kernel/atags_compat.c

@@ -97,8 +97,7 @@ static void __init build_tag_list(struct param_struct *params, void *taglist)
 	struct tag *tag = taglist;
 	struct tag *tag = taglist;
 
 
 	if (params->u1.s.page_size != PAGE_SIZE) {
 	if (params->u1.s.page_size != PAGE_SIZE) {
-		printk(KERN_WARNING "Warning: bad configuration page, "
-		       "trying to continue\n");
+		pr_warn("Warning: bad configuration page, trying to continue\n");
 		return;
 		return;
 	}
 	}
 
 
@@ -109,8 +108,7 @@ static void __init build_tag_list(struct param_struct *params, void *taglist)
 	    params->u1.s.nr_pages != 0x04000 &&
 	    params->u1.s.nr_pages != 0x04000 &&
 	    params->u1.s.nr_pages != 0x08000 &&
 	    params->u1.s.nr_pages != 0x08000 &&
 	    params->u1.s.nr_pages != 0x10000) {
 	    params->u1.s.nr_pages != 0x10000) {
-		printk(KERN_WARNING "Warning: bad NeTTrom parameters "
-		       "detected, using defaults\n");
+		pr_warn("Warning: bad NeTTrom parameters detected, using defaults\n");
 
 
 		params->u1.s.nr_pages = 0x1000;	/* 16MB */
 		params->u1.s.nr_pages = 0x1000;	/* 16MB */
 		params->u1.s.ramdisk_size = 0;
 		params->u1.s.ramdisk_size = 0;

+ 2 - 3
arch/arm/kernel/atags_parse.c

@@ -167,8 +167,7 @@ static void __init parse_tags(const struct tag *t)
 {
 {
 	for (; t->hdr.size; t = tag_next(t))
 	for (; t->hdr.size; t = tag_next(t))
 		if (!parse_tag(t))
 		if (!parse_tag(t))
-			printk(KERN_WARNING
-				"Ignoring unrecognised tag 0x%08x\n",
+			pr_warn("Ignoring unrecognised tag 0x%08x\n",
 				t->hdr.tag);
 				t->hdr.tag);
 }
 }
 
 
@@ -193,7 +192,7 @@ setup_machine_tags(phys_addr_t __atags_pointer, unsigned int machine_nr)
 	 */
 	 */
 	for_each_machine_desc(p)
 	for_each_machine_desc(p)
 		if (machine_nr == p->nr) {
 		if (machine_nr == p->nr) {
-			printk("Machine: %s\n", p->name);
+			pr_info("Machine: %s\n", p->name);
 			mdesc = p;
 			mdesc = p;
 			break;
 			break;
 		}
 		}

+ 2 - 2
arch/arm/kernel/atags_proc.c

@@ -41,7 +41,7 @@ static int __init init_atags_procfs(void)
 	size_t size;
 	size_t size;
 
 
 	if (tag->hdr.tag != ATAG_CORE) {
 	if (tag->hdr.tag != ATAG_CORE) {
-		printk(KERN_INFO "No ATAGs?");
+		pr_info("No ATAGs?");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
@@ -68,7 +68,7 @@ static int __init init_atags_procfs(void)
 
 
 nomem:
 nomem:
 	kfree(b);
 	kfree(b);
-	printk(KERN_ERR "Exporting ATAGs: not enough memory\n");
+	pr_err("Exporting ATAGs: not enough memory\n");
 
 
 	return -ENOMEM;
 	return -ENOMEM;
 }
 }

+ 1 - 1
arch/arm/kernel/bios32.c

@@ -364,7 +364,7 @@ void pcibios_fixup_bus(struct pci_bus *bus)
 	/*
 	/*
 	 * Report what we did for this bus
 	 * Report what we did for this bus
 	 */
 	 */
-	printk(KERN_INFO "PCI: bus%d: Fast back to back transfers %sabled\n",
+	pr_info("PCI: bus%d: Fast back to back transfers %sabled\n",
 		bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis");
 		bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis");
 }
 }
 EXPORT_SYMBOL(pcibios_fixup_bus);
 EXPORT_SYMBOL(pcibios_fixup_bus);

+ 2 - 2
arch/arm/kernel/dma-isa.c

@@ -213,8 +213,8 @@ void __init isa_init_dma(void)
 		for (chan = 0; chan < 8; chan++) {
 		for (chan = 0; chan < 8; chan++) {
 			int ret = isa_dma_add(chan, &isa_dma[chan]);
 			int ret = isa_dma_add(chan, &isa_dma[chan]);
 			if (ret)
 			if (ret)
-				printk(KERN_ERR "ISADMA%u: unable to register: %d\n",
-					chan, ret);
+				pr_err("ISADMA%u: unable to register: %d\n",
+				       chan, ret);
 		}
 		}
 
 
 		request_dma(DMA_ISA_CASCADE, "cascade");
 		request_dma(DMA_ISA_CASCADE, "cascade");

+ 11 - 15
arch/arm/kernel/dma.c

@@ -79,7 +79,7 @@ int request_dma(unsigned int chan, const char *device_id)
 	return ret;
 	return ret;
 
 
 bad_dma:
 bad_dma:
-	printk(KERN_ERR "dma: trying to allocate DMA%d\n", chan);
+	pr_err("dma: trying to allocate DMA%d\n", chan);
 	return -EINVAL;
 	return -EINVAL;
 
 
 busy:
 busy:
@@ -100,7 +100,7 @@ void free_dma(unsigned int chan)
 		goto bad_dma;
 		goto bad_dma;
 
 
 	if (dma->active) {
 	if (dma->active) {
-		printk(KERN_ERR "dma%d: freeing active DMA\n", chan);
+		pr_err("dma%d: freeing active DMA\n", chan);
 		dma->d_ops->disable(chan, dma);
 		dma->d_ops->disable(chan, dma);
 		dma->active = 0;
 		dma->active = 0;
 	}
 	}
@@ -111,11 +111,11 @@ void free_dma(unsigned int chan)
 		return;
 		return;
 	}
 	}
 
 
-	printk(KERN_ERR "dma%d: trying to free free DMA\n", chan);
+	pr_err("dma%d: trying to free free DMA\n", chan);
 	return;
 	return;
 
 
 bad_dma:
 bad_dma:
-	printk(KERN_ERR "dma: trying to free DMA%d\n", chan);
+	pr_err("dma: trying to free DMA%d\n", chan);
 }
 }
 EXPORT_SYMBOL(free_dma);
 EXPORT_SYMBOL(free_dma);
 
 
@@ -126,8 +126,7 @@ void set_dma_sg (unsigned int chan, struct scatterlist *sg, int nr_sg)
 	dma_t *dma = dma_channel(chan);
 	dma_t *dma = dma_channel(chan);
 
 
 	if (dma->active)
 	if (dma->active)
-		printk(KERN_ERR "dma%d: altering DMA SG while "
-		       "DMA active\n", chan);
+		pr_err("dma%d: altering DMA SG while DMA active\n", chan);
 
 
 	dma->sg = sg;
 	dma->sg = sg;
 	dma->sgcount = nr_sg;
 	dma->sgcount = nr_sg;
@@ -144,8 +143,7 @@ void __set_dma_addr (unsigned int chan, void *addr)
 	dma_t *dma = dma_channel(chan);
 	dma_t *dma = dma_channel(chan);
 
 
 	if (dma->active)
 	if (dma->active)
-		printk(KERN_ERR "dma%d: altering DMA address while "
-		       "DMA active\n", chan);
+		pr_err("dma%d: altering DMA address while DMA active\n", chan);
 
 
 	dma->sg = NULL;
 	dma->sg = NULL;
 	dma->addr = addr;
 	dma->addr = addr;
@@ -162,8 +160,7 @@ void set_dma_count (unsigned int chan, unsigned long count)
 	dma_t *dma = dma_channel(chan);
 	dma_t *dma = dma_channel(chan);
 
 
 	if (dma->active)
 	if (dma->active)
-		printk(KERN_ERR "dma%d: altering DMA count while "
-		       "DMA active\n", chan);
+		pr_err("dma%d: altering DMA count while DMA active\n", chan);
 
 
 	dma->sg = NULL;
 	dma->sg = NULL;
 	dma->count = count;
 	dma->count = count;
@@ -178,8 +175,7 @@ void set_dma_mode (unsigned int chan, unsigned int mode)
 	dma_t *dma = dma_channel(chan);
 	dma_t *dma = dma_channel(chan);
 
 
 	if (dma->active)
 	if (dma->active)
-		printk(KERN_ERR "dma%d: altering DMA mode while "
-		       "DMA active\n", chan);
+		pr_err("dma%d: altering DMA mode while DMA active\n", chan);
 
 
 	dma->dma_mode = mode;
 	dma->dma_mode = mode;
 	dma->invalid = 1;
 	dma->invalid = 1;
@@ -202,7 +198,7 @@ void enable_dma (unsigned int chan)
 	return;
 	return;
 
 
 free_dma:
 free_dma:
-	printk(KERN_ERR "dma%d: trying to enable free DMA\n", chan);
+	pr_err("dma%d: trying to enable free DMA\n", chan);
 	BUG();
 	BUG();
 }
 }
 EXPORT_SYMBOL(enable_dma);
 EXPORT_SYMBOL(enable_dma);
@@ -223,7 +219,7 @@ void disable_dma (unsigned int chan)
 	return;
 	return;
 
 
 free_dma:
 free_dma:
-	printk(KERN_ERR "dma%d: trying to disable free DMA\n", chan);
+	pr_err("dma%d: trying to disable free DMA\n", chan);
 	BUG();
 	BUG();
 }
 }
 EXPORT_SYMBOL(disable_dma);
 EXPORT_SYMBOL(disable_dma);
@@ -240,7 +236,7 @@ EXPORT_SYMBOL(dma_channel_active);
 
 
 void set_dma_page(unsigned int chan, char pagenr)
 void set_dma_page(unsigned int chan, char pagenr)
 {
 {
-	printk(KERN_ERR "dma%d: trying to set_dma_page\n", chan);
+	pr_err("dma%d: trying to set_dma_page\n", chan);
 }
 }
 EXPORT_SYMBOL(set_dma_page);
 EXPORT_SYMBOL(set_dma_page);
 
 

+ 0 - 235
arch/arm/kernel/entry-common.S

@@ -109,241 +109,6 @@ ENDPROC(ret_from_fork)
 #undef CALL
 #undef CALL
 #define CALL(x) .long x
 #define CALL(x) .long x
 
 
-#ifdef CONFIG_FUNCTION_TRACER
-/*
- * When compiling with -pg, gcc inserts a call to the mcount routine at the
- * start of every function.  In mcount, apart from the function's address (in
- * lr), we need to get hold of the function's caller's address.
- *
- * Older GCCs (pre-4.4) inserted a call to a routine called mcount like this:
- *
- *	bl	mcount
- *
- * These versions have the limitation that in order for the mcount routine to
- * be able to determine the function's caller's address, an APCS-style frame
- * pointer (which is set up with something like the code below) is required.
- *
- *	mov     ip, sp
- *	push    {fp, ip, lr, pc}
- *	sub     fp, ip, #4
- *
- * With EABI, these frame pointers are not available unless -mapcs-frame is
- * specified, and if building as Thumb-2, not even then.
- *
- * Newer GCCs (4.4+) solve this problem by introducing a new version of mcount,
- * with call sites like:
- *
- *	push	{lr}
- *	bl	__gnu_mcount_nc
- *
- * With these compilers, frame pointers are not necessary.
- *
- * mcount can be thought of as a function called in the middle of a subroutine
- * call.  As such, it needs to be transparent for both the caller and the
- * callee: the original lr needs to be restored when leaving mcount, and no
- * registers should be clobbered.  (In the __gnu_mcount_nc implementation, we
- * 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
-
-.macro mcount_adjust_addr rd, rn
-	bic	\rd, \rn, #1		@ clear the Thumb bit if present
-	sub	\rd, \rd, #MCOUNT_INSN_SIZE
-.endm
-
-.macro __mcount suffix
-	mcount_enter
-	ldr	r0, =ftrace_trace_function
-	ldr	r2, [r0]
-	adr	r0, .Lftrace_stub
-	cmp	r0, r2
-	bne	1f
-
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-	ldr     r1, =ftrace_graph_return
-	ldr     r2, [r1]
-	cmp     r0, r2
-	bne     ftrace_graph_caller\suffix
-
-	ldr     r1, =ftrace_graph_entry
-	ldr     r2, [r1]
-	ldr     r0, =ftrace_graph_entry_stub
-	cmp     r0, r2
-	bne     ftrace_graph_caller\suffix
-#endif
-
-	mcount_exit
-
-1: 	mcount_get_lr	r1			@ lr of instrumented func
-	mcount_adjust_addr	r0, lr		@ instrumented function
-	adr	lr, BSYM(2f)
-	mov	pc, r2
-2:	mcount_exit
-.endm
-
-.macro __ftrace_caller suffix
-	mcount_enter
-
-	mcount_get_lr	r1			@ lr of instrumented func
-	mcount_adjust_addr	r0, lr		@ instrumented function
-
-	.globl ftrace_call\suffix
-ftrace_call\suffix:
-	bl	ftrace_stub
-
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-	.globl ftrace_graph_call\suffix
-ftrace_graph_call\suffix:
-	mov	r0, r0
-#endif
-
-	mcount_exit
-.endm
-
-.macro __ftrace_graph_caller
-	sub	r0, fp, #4		@ &lr of instrumented routine (&parent)
-#ifdef CONFIG_DYNAMIC_FTRACE
-	@ called from __ftrace_caller, saved in mcount_enter
-	ldr	r1, [sp, #16]		@ instrumented routine (func)
-	mcount_adjust_addr	r1, r1
-#else
-	@ called from __mcount, untouched in lr
-	mcount_adjust_addr	r1, lr	@ instrumented routine (func)
-#endif
-	mov	r2, fp			@ frame pointer
-	bl	prepare_ftrace_return
-	mcount_exit
-.endm
-
-#ifdef CONFIG_OLD_MCOUNT
-/*
- * mcount
- */
-
-.macro mcount_enter
-	stmdb	sp!, {r0-r3, lr}
-.endm
-
-.macro mcount_get_lr reg
-	ldr	\reg, [fp, #-4]
-.endm
-
-.macro mcount_exit
-	ldr	lr, [fp, #-4]
-	ldmia	sp!, {r0-r3, pc}
-.endm
-
-ENTRY(mcount)
-#ifdef CONFIG_DYNAMIC_FTRACE
-	stmdb	sp!, {lr}
-	ldr	lr, [fp, #-4]
-	ldmia	sp!, {pc}
-#else
-	__mcount _old
-#endif
-ENDPROC(mcount)
-
-#ifdef CONFIG_DYNAMIC_FTRACE
-ENTRY(ftrace_caller_old)
-	__ftrace_caller _old
-ENDPROC(ftrace_caller_old)
-#endif
-
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-ENTRY(ftrace_graph_caller_old)
-	__ftrace_graph_caller
-ENDPROC(ftrace_graph_caller_old)
-#endif
-
-.purgem mcount_enter
-.purgem mcount_get_lr
-.purgem mcount_exit
-#endif
-
-/*
- * __gnu_mcount_nc
- */
-
-.macro mcount_enter
-/*
- * This pad compensates for the push {lr} at the call site.  Note that we are
- * unable to unwind through a function which does not otherwise save its lr.
- */
- UNWIND(.pad	#4)
-	stmdb	sp!, {r0-r3, lr}
- UNWIND(.save	{r0-r3, lr})
-.endm
-
-.macro mcount_get_lr reg
-	ldr	\reg, [sp, #20]
-.endm
-
-.macro mcount_exit
-	ldmia	sp!, {r0-r3, ip, lr}
-	ret	ip
-.endm
-
-ENTRY(__gnu_mcount_nc)
-UNWIND(.fnstart)
-#ifdef CONFIG_DYNAMIC_FTRACE
-	mov	ip, lr
-	ldmia	sp!, {lr}
-	ret	ip
-#else
-	__mcount
-#endif
-UNWIND(.fnend)
-ENDPROC(__gnu_mcount_nc)
-
-#ifdef CONFIG_DYNAMIC_FTRACE
-ENTRY(ftrace_caller)
-UNWIND(.fnstart)
-	__ftrace_caller
-UNWIND(.fnend)
-ENDPROC(ftrace_caller)
-#endif
-
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-ENTRY(ftrace_graph_caller)
-UNWIND(.fnstart)
-	__ftrace_graph_caller
-UNWIND(.fnend)
-ENDPROC(ftrace_graph_caller)
-#endif
-
-.purgem mcount_enter
-.purgem mcount_get_lr
-.purgem mcount_exit
-
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-	.globl return_to_handler
-return_to_handler:
-	stmdb	sp!, {r0-r3}
-	mov	r0, fp			@ frame pointer
-	bl	ftrace_return_to_handler
-	mov	lr, r0			@ r0 has real ret addr
-	ldmia	sp!, {r0-r3}
-	ret	lr
-#endif
-
-ENTRY(ftrace_stub)
-.Lftrace_stub:
-	ret	lr
-ENDPROC(ftrace_stub)
-
-#endif /* CONFIG_FUNCTION_TRACER */
-
 /*=============================================================================
 /*=============================================================================
  * SWI handler
  * SWI handler
  *-----------------------------------------------------------------------------
  *-----------------------------------------------------------------------------

+ 243 - 0
arch/arm/kernel/entry-ftrace.S

@@ -0,0 +1,243 @@
+/*
+ * 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/assembler.h>
+#include <asm/ftrace.h>
+#include <asm/unwind.h>
+
+#include "entry-header.S"
+
+/*
+ * When compiling with -pg, gcc inserts a call to the mcount routine at the
+ * start of every function.  In mcount, apart from the function's address (in
+ * lr), we need to get hold of the function's caller's address.
+ *
+ * Older GCCs (pre-4.4) inserted a call to a routine called mcount like this:
+ *
+ *	bl	mcount
+ *
+ * These versions have the limitation that in order for the mcount routine to
+ * be able to determine the function's caller's address, an APCS-style frame
+ * pointer (which is set up with something like the code below) is required.
+ *
+ *	mov     ip, sp
+ *	push    {fp, ip, lr, pc}
+ *	sub     fp, ip, #4
+ *
+ * With EABI, these frame pointers are not available unless -mapcs-frame is
+ * specified, and if building as Thumb-2, not even then.
+ *
+ * Newer GCCs (4.4+) solve this problem by introducing a new version of mcount,
+ * with call sites like:
+ *
+ *	push	{lr}
+ *	bl	__gnu_mcount_nc
+ *
+ * With these compilers, frame pointers are not necessary.
+ *
+ * mcount can be thought of as a function called in the middle of a subroutine
+ * call.  As such, it needs to be transparent for both the caller and the
+ * callee: the original lr needs to be restored when leaving mcount, and no
+ * registers should be clobbered.  (In the __gnu_mcount_nc implementation, we
+ * 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
+
+.macro mcount_adjust_addr rd, rn
+	bic	\rd, \rn, #1		@ clear the Thumb bit if present
+	sub	\rd, \rd, #MCOUNT_INSN_SIZE
+.endm
+
+.macro __mcount suffix
+	mcount_enter
+	ldr	r0, =ftrace_trace_function
+	ldr	r2, [r0]
+	adr	r0, .Lftrace_stub
+	cmp	r0, r2
+	bne	1f
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	ldr     r1, =ftrace_graph_return
+	ldr     r2, [r1]
+	cmp     r0, r2
+	bne     ftrace_graph_caller\suffix
+
+	ldr     r1, =ftrace_graph_entry
+	ldr     r2, [r1]
+	ldr     r0, =ftrace_graph_entry_stub
+	cmp     r0, r2
+	bne     ftrace_graph_caller\suffix
+#endif
+
+	mcount_exit
+
+1: 	mcount_get_lr	r1			@ lr of instrumented func
+	mcount_adjust_addr	r0, lr		@ instrumented function
+	adr	lr, BSYM(2f)
+	mov	pc, r2
+2:	mcount_exit
+.endm
+
+.macro __ftrace_caller suffix
+	mcount_enter
+
+	mcount_get_lr	r1			@ lr of instrumented func
+	mcount_adjust_addr	r0, lr		@ instrumented function
+
+	.globl ftrace_call\suffix
+ftrace_call\suffix:
+	bl	ftrace_stub
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	.globl ftrace_graph_call\suffix
+ftrace_graph_call\suffix:
+	mov	r0, r0
+#endif
+
+	mcount_exit
+.endm
+
+.macro __ftrace_graph_caller
+	sub	r0, fp, #4		@ &lr of instrumented routine (&parent)
+#ifdef CONFIG_DYNAMIC_FTRACE
+	@ called from __ftrace_caller, saved in mcount_enter
+	ldr	r1, [sp, #16]		@ instrumented routine (func)
+	mcount_adjust_addr	r1, r1
+#else
+	@ called from __mcount, untouched in lr
+	mcount_adjust_addr	r1, lr	@ instrumented routine (func)
+#endif
+	mov	r2, fp			@ frame pointer
+	bl	prepare_ftrace_return
+	mcount_exit
+.endm
+
+#ifdef CONFIG_OLD_MCOUNT
+/*
+ * mcount
+ */
+
+.macro mcount_enter
+	stmdb	sp!, {r0-r3, lr}
+.endm
+
+.macro mcount_get_lr reg
+	ldr	\reg, [fp, #-4]
+.endm
+
+.macro mcount_exit
+	ldr	lr, [fp, #-4]
+	ldmia	sp!, {r0-r3, pc}
+.endm
+
+ENTRY(mcount)
+#ifdef CONFIG_DYNAMIC_FTRACE
+	stmdb	sp!, {lr}
+	ldr	lr, [fp, #-4]
+	ldmia	sp!, {pc}
+#else
+	__mcount _old
+#endif
+ENDPROC(mcount)
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+ENTRY(ftrace_caller_old)
+	__ftrace_caller _old
+ENDPROC(ftrace_caller_old)
+#endif
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ENTRY(ftrace_graph_caller_old)
+	__ftrace_graph_caller
+ENDPROC(ftrace_graph_caller_old)
+#endif
+
+.purgem mcount_enter
+.purgem mcount_get_lr
+.purgem mcount_exit
+#endif
+
+/*
+ * __gnu_mcount_nc
+ */
+
+.macro mcount_enter
+/*
+ * This pad compensates for the push {lr} at the call site.  Note that we are
+ * unable to unwind through a function which does not otherwise save its lr.
+ */
+ UNWIND(.pad	#4)
+	stmdb	sp!, {r0-r3, lr}
+ UNWIND(.save	{r0-r3, lr})
+.endm
+
+.macro mcount_get_lr reg
+	ldr	\reg, [sp, #20]
+.endm
+
+.macro mcount_exit
+	ldmia	sp!, {r0-r3, ip, lr}
+	ret	ip
+.endm
+
+ENTRY(__gnu_mcount_nc)
+UNWIND(.fnstart)
+#ifdef CONFIG_DYNAMIC_FTRACE
+	mov	ip, lr
+	ldmia	sp!, {lr}
+	ret	ip
+#else
+	__mcount
+#endif
+UNWIND(.fnend)
+ENDPROC(__gnu_mcount_nc)
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+ENTRY(ftrace_caller)
+UNWIND(.fnstart)
+	__ftrace_caller
+UNWIND(.fnend)
+ENDPROC(ftrace_caller)
+#endif
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ENTRY(ftrace_graph_caller)
+UNWIND(.fnstart)
+	__ftrace_graph_caller
+UNWIND(.fnend)
+ENDPROC(ftrace_graph_caller)
+#endif
+
+.purgem mcount_enter
+.purgem mcount_get_lr
+.purgem mcount_exit
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	.globl return_to_handler
+return_to_handler:
+	stmdb	sp!, {r0-r3}
+	mov	r0, fp			@ frame pointer
+	bl	ftrace_return_to_handler
+	mov	lr, r0			@ r0 has real ret addr
+	ldmia	sp!, {r0-r3}
+	ret	lr
+#endif
+
+ENTRY(ftrace_stub)
+.Lftrace_stub:
+	ret	lr
+ENDPROC(ftrace_stub)

+ 6 - 6
arch/arm/kernel/etm.c

@@ -213,7 +213,7 @@ static void etm_dump(void)
 	int length;
 	int length;
 
 
 	if (!t->etb_regs) {
 	if (!t->etb_regs) {
-		printk(KERN_INFO "No tracing hardware found\n");
+		pr_info("No tracing hardware found\n");
 		return;
 		return;
 	}
 	}
 
 
@@ -229,11 +229,11 @@ static void etm_dump(void)
 
 
 	etb_writel(t, first, ETBR_READADDR);
 	etb_writel(t, first, ETBR_READADDR);
 
 
-	printk(KERN_INFO "Trace buffer contents length: %d\n", length);
-	printk(KERN_INFO "--- ETB buffer begin ---\n");
+	pr_info("Trace buffer contents length: %d\n", length);
+	pr_info("--- ETB buffer begin ---\n");
 	for (; length; length--)
 	for (; length; length--)
 		printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
 		printk("%08x", cpu_to_be32(etb_readl(t, ETBR_READMEM)));
-	printk(KERN_INFO "\n--- ETB buffer end ---\n");
+	pr_info("\n--- ETB buffer end ---\n");
 
 
 	/* deassert the overflow bit */
 	/* deassert the overflow bit */
 	etb_writel(t, 1, ETBR_CTRL);
 	etb_writel(t, 1, ETBR_CTRL);
@@ -633,14 +633,14 @@ static int __init etm_init(void)
 
 
 	retval = amba_driver_register(&etb_driver);
 	retval = amba_driver_register(&etb_driver);
 	if (retval) {
 	if (retval) {
-		printk(KERN_ERR "Failed to register etb\n");
+		pr_err("Failed to register etb\n");
 		return retval;
 		return retval;
 	}
 	}
 
 
 	retval = amba_driver_register(&etm_driver);
 	retval = amba_driver_register(&etm_driver);
 	if (retval) {
 	if (retval) {
 		amba_driver_unregister(&etb_driver);
 		amba_driver_unregister(&etb_driver);
-		printk(KERN_ERR "Failed to probe etm\n");
+		pr_err("Failed to probe etm\n");
 		return retval;
 		return retval;
 	}
 	}
 
 

+ 1 - 1
arch/arm/kernel/fiq.c

@@ -124,7 +124,7 @@ int claim_fiq(struct fiq_handler *f)
 void release_fiq(struct fiq_handler *f)
 void release_fiq(struct fiq_handler *f)
 {
 {
 	if (current_fiq != f) {
 	if (current_fiq != f) {
-		printk(KERN_ERR "%s FIQ trying to release %s FIQ\n",
+		pr_err("%s FIQ trying to release %s FIQ\n",
 		       f->name, current_fiq->name);
 		       f->name, current_fiq->name);
 		dump_stack();
 		dump_stack();
 		return;
 		return;

+ 19 - 0
arch/arm/kernel/ftrace.c

@@ -15,6 +15,7 @@
 #include <linux/ftrace.h>
 #include <linux/ftrace.h>
 #include <linux/uaccess.h>
 #include <linux/uaccess.h>
 #include <linux/module.h>
 #include <linux/module.h>
+#include <linux/stop_machine.h>
 
 
 #include <asm/cacheflush.h>
 #include <asm/cacheflush.h>
 #include <asm/opcodes.h>
 #include <asm/opcodes.h>
@@ -35,6 +36,22 @@
 
 
 #define	OLD_NOP		0xe1a00000	/* mov r0, r0 */
 #define	OLD_NOP		0xe1a00000	/* mov r0, r0 */
 
 
+static int __ftrace_modify_code(void *data)
+{
+	int *command = data;
+
+	set_kernel_text_rw();
+	ftrace_modify_all_code(*command);
+	set_kernel_text_ro();
+
+	return 0;
+}
+
+void arch_ftrace_update_code(int command)
+{
+	stop_machine(__ftrace_modify_code, &command, NULL);
+}
+
 static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec)
 static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec)
 {
 {
 	return rec->arch.old_mcount ? OLD_NOP : NOP;
 	return rec->arch.old_mcount ? OLD_NOP : NOP;
@@ -73,6 +90,8 @@ int ftrace_arch_code_modify_prepare(void)
 int ftrace_arch_code_modify_post_process(void)
 int ftrace_arch_code_modify_post_process(void)
 {
 {
 	set_all_modules_text_ro();
 	set_all_modules_text_ro();
+	/* Make sure any TLB misses during machine stop are cleared. */
+	flush_tlb_all();
 	return 0;
 	return 0;
 }
 }
 
 

+ 2 - 3
arch/arm/kernel/io.c

@@ -51,6 +51,7 @@ void _memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
 		from++;
 		from++;
 	}
 	}
 }
 }
+EXPORT_SYMBOL(_memcpy_fromio);
 
 
 /*
 /*
  * Copy data from "real" memory space to IO memory space.
  * Copy data from "real" memory space to IO memory space.
@@ -66,6 +67,7 @@ void _memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
 		to++;
 		to++;
 	}
 	}
 }
 }
+EXPORT_SYMBOL(_memcpy_toio);
 
 
 /*
 /*
  * "memset" on IO memory space.
  * "memset" on IO memory space.
@@ -79,7 +81,4 @@ void _memset_io(volatile void __iomem *dst, int c, size_t count)
 		dst++;
 		dst++;
 	}
 	}
 }
 }
-
-EXPORT_SYMBOL(_memcpy_fromio);
-EXPORT_SYMBOL(_memcpy_toio);
 EXPORT_SYMBOL(_memset_io);
 EXPORT_SYMBOL(_memset_io);

+ 4 - 4
arch/arm/kernel/irq.c

@@ -31,6 +31,7 @@
 #include <linux/smp.h>
 #include <linux/smp.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/seq_file.h>
 #include <linux/seq_file.h>
+#include <linux/ratelimit.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/list.h>
 #include <linux/list.h>
 #include <linux/kallsyms.h>
 #include <linux/kallsyms.h>
@@ -82,7 +83,7 @@ void set_irq_flags(unsigned int irq, unsigned int iflags)
 	unsigned long clr = 0, set = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
 	unsigned long clr = 0, set = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
 
 
 	if (irq >= nr_irqs) {
 	if (irq >= nr_irqs) {
-		printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
+		pr_err("Trying to set irq flags for IRQ%d\n", irq);
 		return;
 		return;
 	}
 	}
 
 
@@ -135,7 +136,6 @@ int __init arch_probe_nr_irqs(void)
 #endif
 #endif
 
 
 #ifdef CONFIG_HOTPLUG_CPU
 #ifdef CONFIG_HOTPLUG_CPU
-
 static bool migrate_one_irq(struct irq_desc *desc)
 static bool migrate_one_irq(struct irq_desc *desc)
 {
 {
 	struct irq_data *d = irq_desc_get_irq_data(desc);
 	struct irq_data *d = irq_desc_get_irq_data(desc);
@@ -187,8 +187,8 @@ void migrate_irqs(void)
 		affinity_broken = migrate_one_irq(desc);
 		affinity_broken = migrate_one_irq(desc);
 		raw_spin_unlock(&desc->lock);
 		raw_spin_unlock(&desc->lock);
 
 
-		if (affinity_broken && printk_ratelimit())
-			pr_warn("IRQ%u no longer affine to CPU%u\n",
+		if (affinity_broken)
+			pr_warn_ratelimited("IRQ%u no longer affine to CPU%u\n",
 				i, smp_processor_id());
 				i, smp_processor_id());
 	}
 	}
 
 

+ 13 - 0
arch/arm/kernel/iwmmxt.S

@@ -58,6 +58,7 @@
 #define MMX_SIZE		(0x98)
 #define MMX_SIZE		(0x98)
 
 
 	.text
 	.text
+	.arm
 
 
 /*
 /*
  * Lazy switching of Concan coprocessor context
  * Lazy switching of Concan coprocessor context
@@ -182,6 +183,8 @@ concan_load:
 	tmcr	wCon, r2
 	tmcr	wCon, r2
 	ret	lr
 	ret	lr
 
 
+ENDPROC(iwmmxt_task_enable)
+
 /*
 /*
  * Back up Concan regs to save area and disable access to them
  * Back up Concan regs to save area and disable access to them
  * (mainly for gdb or sleep mode usage)
  * (mainly for gdb or sleep mode usage)
@@ -232,6 +235,8 @@ ENTRY(iwmmxt_task_disable)
 1:	msr	cpsr_c, ip			@ restore interrupt mode
 1:	msr	cpsr_c, ip			@ restore interrupt mode
 	ldmfd	sp!, {r4, pc}
 	ldmfd	sp!, {r4, pc}
 
 
+ENDPROC(iwmmxt_task_disable)
+
 /*
 /*
  * Copy Concan state to given memory address
  * Copy Concan state to given memory address
  *
  *
@@ -268,6 +273,8 @@ ENTRY(iwmmxt_task_copy)
 	msr	cpsr_c, ip			@ restore interrupt mode
 	msr	cpsr_c, ip			@ restore interrupt mode
 	ret	r3
 	ret	r3
 
 
+ENDPROC(iwmmxt_task_copy)
+
 /*
 /*
  * Restore Concan state from given memory address
  * Restore Concan state from given memory address
  *
  *
@@ -304,6 +311,8 @@ ENTRY(iwmmxt_task_restore)
 	msr	cpsr_c, ip			@ restore interrupt mode
 	msr	cpsr_c, ip			@ restore interrupt mode
 	ret	r3
 	ret	r3
 
 
+ENDPROC(iwmmxt_task_restore)
+
 /*
 /*
  * Concan handling on task switch
  * Concan handling on task switch
  *
  *
@@ -335,6 +344,8 @@ ENTRY(iwmmxt_task_switch)
 	mrc	p15, 0, r1, c2, c0, 0
 	mrc	p15, 0, r1, c2, c0, 0
 	sub	pc, lr, r1, lsr #32		@ cpwait and return
 	sub	pc, lr, r1, lsr #32		@ cpwait and return
 
 
+ENDPROC(iwmmxt_task_switch)
+
 /*
 /*
  * Remove Concan ownership of given task
  * Remove Concan ownership of given task
  *
  *
@@ -353,6 +364,8 @@ ENTRY(iwmmxt_task_release)
 	msr	cpsr_c, r2			@ restore interrupts
 	msr	cpsr_c, r2			@ restore interrupts
 	ret	lr
 	ret	lr
 
 
+ENDPROC(iwmmxt_task_release)
+
 	.data
 	.data
 concan_owner:
 concan_owner:
 	.word	0
 	.word	0

+ 1 - 1
arch/arm/kernel/jump_label.c

@@ -19,7 +19,7 @@ static void __arch_jump_label_transform(struct jump_entry *entry,
 		insn = arm_gen_nop();
 		insn = arm_gen_nop();
 
 
 	if (is_static)
 	if (is_static)
-		__patch_text(addr, insn);
+		__patch_text_early(addr, insn);
 	else
 	else
 		patch_text(addr, insn);
 		patch_text(addr, insn);
 }
 }

+ 29 - 0
arch/arm/kernel/kgdb.c

@@ -12,8 +12,12 @@
 #include <linux/irq.h>
 #include <linux/irq.h>
 #include <linux/kdebug.h>
 #include <linux/kdebug.h>
 #include <linux/kgdb.h>
 #include <linux/kgdb.h>
+#include <linux/uaccess.h>
+
 #include <asm/traps.h>
 #include <asm/traps.h>
 
 
+#include "patch.h"
+
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
 {
 {
 	{ "r0", 4, offsetof(struct pt_regs, ARM_r0)},
 	{ "r0", 4, offsetof(struct pt_regs, ARM_r0)},
@@ -244,6 +248,31 @@ void kgdb_arch_exit(void)
 	unregister_die_notifier(&kgdb_notifier);
 	unregister_die_notifier(&kgdb_notifier);
 }
 }
 
 
+int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
+{
+	int err;
+
+	/* patch_text() only supports int-sized breakpoints */
+	BUILD_BUG_ON(sizeof(int) != BREAK_INSTR_SIZE);
+
+	err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr,
+				BREAK_INSTR_SIZE);
+	if (err)
+		return err;
+
+	patch_text((void *)bpt->bpt_addr,
+		   *(unsigned int *)arch_kgdb_ops.gdb_bpt_instr);
+
+	return err;
+}
+
+int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
+{
+	patch_text((void *)bpt->bpt_addr, *(unsigned int *)bpt->saved_instr);
+
+	return 0;
+}
+
 /*
 /*
  * Register our undef instruction hooks with ARM undef core.
  * Register our undef instruction hooks with ARM undef core.
  * We regsiter a hook specifically looking for the KGB break inst
  * We regsiter a hook specifically looking for the KGB break inst

+ 8 - 7
arch/arm/kernel/machine_kexec.c

@@ -29,6 +29,7 @@ extern unsigned long kexec_boot_atags;
 
 
 static atomic_t waiting_for_crash_ipi;
 static atomic_t waiting_for_crash_ipi;
 
 
+static unsigned long dt_mem;
 /*
 /*
  * Provide a dummy crash_notes definition while crash dump arrives to arm.
  * Provide a dummy crash_notes definition while crash dump arrives to arm.
  * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
  * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
@@ -64,7 +65,7 @@ int machine_kexec_prepare(struct kimage *image)
 			return err;
 			return err;
 
 
 		if (be32_to_cpu(header) == OF_DT_HEADER)
 		if (be32_to_cpu(header) == OF_DT_HEADER)
-			kexec_boot_atags = current_segment->mem;
+			dt_mem = current_segment->mem;
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -126,12 +127,12 @@ void machine_crash_shutdown(struct pt_regs *regs)
 		msecs--;
 		msecs--;
 	}
 	}
 	if (atomic_read(&waiting_for_crash_ipi) > 0)
 	if (atomic_read(&waiting_for_crash_ipi) > 0)
-		printk(KERN_WARNING "Non-crashing CPUs did not react to IPI\n");
+		pr_warn("Non-crashing CPUs did not react to IPI\n");
 
 
 	crash_save_cpu(regs, smp_processor_id());
 	crash_save_cpu(regs, smp_processor_id());
 	machine_kexec_mask_interrupts();
 	machine_kexec_mask_interrupts();
 
 
-	printk(KERN_INFO "Loading crashdump kernel...\n");
+	pr_info("Loading crashdump kernel...\n");
 }
 }
 
 
 /*
 /*
@@ -163,12 +164,12 @@ void machine_kexec(struct kimage *image)
 	reboot_code_buffer = page_address(image->control_code_page);
 	reboot_code_buffer = page_address(image->control_code_page);
 
 
 	/* Prepare parameters for reboot_code_buffer*/
 	/* Prepare parameters for reboot_code_buffer*/
+	set_kernel_text_rw();
 	kexec_start_address = image->start;
 	kexec_start_address = image->start;
 	kexec_indirection_page = page_list;
 	kexec_indirection_page = page_list;
 	kexec_mach_type = machine_arch_type;
 	kexec_mach_type = machine_arch_type;
-	if (!kexec_boot_atags)
-		kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
-
+	kexec_boot_atags = dt_mem ?: image->start - KEXEC_ARM_ZIMAGE_OFFSET
+				     + KEXEC_ARM_ATAGS_OFFSET;
 
 
 	/* copy our kernel relocation code to the control code page */
 	/* copy our kernel relocation code to the control code page */
 	reboot_entry = fncpy(reboot_code_buffer,
 	reboot_entry = fncpy(reboot_code_buffer,
@@ -177,7 +178,7 @@ void machine_kexec(struct kimage *image)
 	reboot_entry_phys = (unsigned long)reboot_entry +
 	reboot_entry_phys = (unsigned long)reboot_entry +
 		(reboot_code_buffer_phys - (unsigned long)reboot_code_buffer);
 		(reboot_code_buffer_phys - (unsigned long)reboot_code_buffer);
 
 
-	printk(KERN_INFO "Bye!\n");
+	pr_info("Bye!\n");
 
 
 	if (kexec_reinit)
 	if (kexec_reinit)
 		kexec_reinit();
 		kexec_reinit();

+ 1 - 1
arch/arm/kernel/module.c

@@ -251,7 +251,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
 #endif
 #endif
 
 
 		default:
 		default:
-			printk(KERN_ERR "%s: unknown relocation: %u\n",
+			pr_err("%s: unknown relocation: %u\n",
 			       module->name, ELF32_R_TYPE(rel->r_info));
 			       module->name, ELF32_R_TYPE(rel->r_info));
 			return -ENOEXEC;
 			return -ENOEXEC;
 		}
 		}

+ 73 - 19
arch/arm/kernel/patch.c

@@ -1,8 +1,11 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
+#include <linux/spinlock.h>
 #include <linux/kprobes.h>
 #include <linux/kprobes.h>
+#include <linux/mm.h>
 #include <linux/stop_machine.h>
 #include <linux/stop_machine.h>
 
 
 #include <asm/cacheflush.h>
 #include <asm/cacheflush.h>
+#include <asm/fixmap.h>
 #include <asm/smp_plat.h>
 #include <asm/smp_plat.h>
 #include <asm/opcodes.h>
 #include <asm/opcodes.h>
 
 
@@ -13,21 +16,77 @@ struct patch {
 	unsigned int insn;
 	unsigned int insn;
 };
 };
 
 
-void __kprobes __patch_text(void *addr, unsigned int insn)
+static DEFINE_SPINLOCK(patch_lock);
+
+static void __kprobes *patch_map(void *addr, int fixmap, unsigned long *flags)
+	__acquires(&patch_lock)
+{
+	unsigned int uintaddr = (uintptr_t) addr;
+	bool module = !core_kernel_text(uintaddr);
+	struct page *page;
+
+	if (module && IS_ENABLED(CONFIG_DEBUG_SET_MODULE_RONX))
+		page = vmalloc_to_page(addr);
+	else if (!module && IS_ENABLED(CONFIG_DEBUG_RODATA))
+		page = virt_to_page(addr);
+	else
+		return addr;
+
+	if (flags)
+		spin_lock_irqsave(&patch_lock, *flags);
+	else
+		__acquire(&patch_lock);
+
+	set_fixmap(fixmap, page_to_phys(page));
+
+	return (void *) (__fix_to_virt(fixmap) + (uintaddr & ~PAGE_MASK));
+}
+
+static void __kprobes patch_unmap(int fixmap, unsigned long *flags)
+	__releases(&patch_lock)
+{
+	clear_fixmap(fixmap);
+
+	if (flags)
+		spin_unlock_irqrestore(&patch_lock, *flags);
+	else
+		__release(&patch_lock);
+}
+
+void __kprobes __patch_text_real(void *addr, unsigned int insn, bool remap)
 {
 {
 	bool thumb2 = IS_ENABLED(CONFIG_THUMB2_KERNEL);
 	bool thumb2 = IS_ENABLED(CONFIG_THUMB2_KERNEL);
+	unsigned int uintaddr = (uintptr_t) addr;
+	bool twopage = false;
+	unsigned long flags;
+	void *waddr = addr;
 	int size;
 	int size;
 
 
+	if (remap)
+		waddr = patch_map(addr, FIX_TEXT_POKE0, &flags);
+	else
+		__acquire(&patch_lock);
+
 	if (thumb2 && __opcode_is_thumb16(insn)) {
 	if (thumb2 && __opcode_is_thumb16(insn)) {
-		*(u16 *)addr = __opcode_to_mem_thumb16(insn);
+		*(u16 *)waddr = __opcode_to_mem_thumb16(insn);
 		size = sizeof(u16);
 		size = sizeof(u16);
-	} else if (thumb2 && ((uintptr_t)addr & 2)) {
+	} else if (thumb2 && (uintaddr & 2)) {
 		u16 first = __opcode_thumb32_first(insn);
 		u16 first = __opcode_thumb32_first(insn);
 		u16 second = __opcode_thumb32_second(insn);
 		u16 second = __opcode_thumb32_second(insn);
-		u16 *addrh = addr;
+		u16 *addrh0 = waddr;
+		u16 *addrh1 = waddr + 2;
+
+		twopage = (uintaddr & ~PAGE_MASK) == PAGE_SIZE - 2;
+		if (twopage && remap)
+			addrh1 = patch_map(addr + 2, FIX_TEXT_POKE1, NULL);
+
+		*addrh0 = __opcode_to_mem_thumb16(first);
+		*addrh1 = __opcode_to_mem_thumb16(second);
 
 
-		addrh[0] = __opcode_to_mem_thumb16(first);
-		addrh[1] = __opcode_to_mem_thumb16(second);
+		if (twopage && addrh1 != addr + 2) {
+			flush_kernel_vmap_range(addrh1, 2);
+			patch_unmap(FIX_TEXT_POKE1, NULL);
+		}
 
 
 		size = sizeof(u32);
 		size = sizeof(u32);
 	} else {
 	} else {
@@ -36,10 +95,16 @@ void __kprobes __patch_text(void *addr, unsigned int insn)
 		else
 		else
 			insn = __opcode_to_mem_arm(insn);
 			insn = __opcode_to_mem_arm(insn);
 
 
-		*(u32 *)addr = insn;
+		*(u32 *)waddr = insn;
 		size = sizeof(u32);
 		size = sizeof(u32);
 	}
 	}
 
 
+	if (waddr != addr) {
+		flush_kernel_vmap_range(waddr, twopage ? size / 2 : size);
+		patch_unmap(FIX_TEXT_POKE0, &flags);
+	} else
+		__release(&patch_lock);
+
 	flush_icache_range((uintptr_t)(addr),
 	flush_icache_range((uintptr_t)(addr),
 			   (uintptr_t)(addr) + size);
 			   (uintptr_t)(addr) + size);
 }
 }
@@ -60,16 +125,5 @@ void __kprobes patch_text(void *addr, unsigned int insn)
 		.insn = insn,
 		.insn = insn,
 	};
 	};
 
 
-	if (cache_ops_need_broadcast()) {
-		stop_machine(patch_text_stop_machine, &patch, cpu_online_mask);
-	} else {
-		bool straddles_word = IS_ENABLED(CONFIG_THUMB2_KERNEL)
-				      && __opcode_is_thumb32(insn)
-				      && ((uintptr_t)addr & 2);
-
-		if (straddles_word)
-			stop_machine(patch_text_stop_machine, &patch, NULL);
-		else
-			__patch_text(addr, insn);
-	}
+	stop_machine(patch_text_stop_machine, &patch, NULL);
 }
 }

+ 11 - 1
arch/arm/kernel/patch.h

@@ -2,6 +2,16 @@
 #define _ARM_KERNEL_PATCH_H
 #define _ARM_KERNEL_PATCH_H
 
 
 void patch_text(void *addr, unsigned int insn);
 void patch_text(void *addr, unsigned int insn);
-void __patch_text(void *addr, unsigned int insn);
+void __patch_text_real(void *addr, unsigned int insn, bool remap);
+
+static inline void __patch_text(void *addr, unsigned int insn)
+{
+	__patch_text_real(addr, insn, true);
+}
+
+static inline void __patch_text_early(void *addr, unsigned int insn)
+{
+	__patch_text_real(addr, insn, false);
+}
 
 
 #endif
 #endif

+ 2 - 2
arch/arm/kernel/process.c

@@ -51,8 +51,8 @@ EXPORT_SYMBOL(__stack_chk_guard);
 static const char *processor_modes[] __maybe_unused = {
 static const char *processor_modes[] __maybe_unused = {
   "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
   "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
   "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
   "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
-  "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" ,
-  "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32"
+  "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "MON_32" , "ABT_32" ,
+  "UK8_32" , "UK9_32" , "HYP_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32"
 };
 };
 
 
 static const char *isa_modes[] __maybe_unused = {
 static const char *isa_modes[] __maybe_unused = {

+ 1 - 2
arch/arm/kernel/return_address.c

@@ -39,13 +39,12 @@ void *return_address(unsigned int level)
 {
 {
 	struct return_address_data data;
 	struct return_address_data data;
 	struct stackframe frame;
 	struct stackframe frame;
-	register unsigned long current_sp asm ("sp");
 
 
 	data.level = level + 2;
 	data.level = level + 2;
 	data.addr = NULL;
 	data.addr = NULL;
 
 
 	frame.fp = (unsigned long)__builtin_frame_address(0);
 	frame.fp = (unsigned long)__builtin_frame_address(0);
-	frame.sp = current_sp;
+	frame.sp = current_stack_pointer;
 	frame.lr = (unsigned long)__builtin_return_address(0);
 	frame.lr = (unsigned long)__builtin_return_address(0);
 	frame.pc = (unsigned long)return_address;
 	frame.pc = (unsigned long)return_address;
 
 

+ 1 - 0
arch/arm/kernel/setup.c

@@ -900,6 +900,7 @@ void __init setup_arch(char **cmdline_p)
 		mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
 		mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
 	machine_desc = mdesc;
 	machine_desc = mdesc;
 	machine_name = mdesc->name;
 	machine_name = mdesc->name;
+	dump_stack_set_arch_desc("%s", mdesc->name);
 
 
 	if (mdesc->reboot_mode != REBOOT_HARD)
 	if (mdesc->reboot_mode != REBOOT_HARD)
 		reboot_mode = mdesc->reboot_mode;
 		reboot_mode = mdesc->reboot_mode;

+ 0 - 1
arch/arm/kernel/signal.c

@@ -592,7 +592,6 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
 				}
 				}
 				syscall = 0;
 				syscall = 0;
 			} else if (thread_flags & _TIF_UPROBE) {
 			} else if (thread_flags & _TIF_UPROBE) {
-				clear_thread_flag(TIF_UPROBE);
 				uprobe_notify_resume(regs);
 				uprobe_notify_resume(regs);
 			} else {
 			} else {
 				clear_thread_flag(TIF_NOTIFY_RESUME);
 				clear_thread_flag(TIF_NOTIFY_RESUME);

+ 6 - 9
arch/arm/kernel/smp.c

@@ -225,7 +225,7 @@ void __cpu_die(unsigned int cpu)
 		pr_err("CPU%u: cpu didn't die\n", cpu);
 		pr_err("CPU%u: cpu didn't die\n", cpu);
 		return;
 		return;
 	}
 	}
-	printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);
+	pr_notice("CPU%u: shutdown\n", cpu);
 
 
 	/*
 	/*
 	 * platform_cpu_kill() is generally expected to do the powering off
 	 * platform_cpu_kill() is generally expected to do the powering off
@@ -235,7 +235,7 @@ void __cpu_die(unsigned int cpu)
 	 * the requesting CPU and the dying CPU actually losing power.
 	 * the requesting CPU and the dying CPU actually losing power.
 	 */
 	 */
 	if (!platform_cpu_kill(cpu))
 	if (!platform_cpu_kill(cpu))
-		printk("CPU%u: unable to kill\n", cpu);
+		pr_err("CPU%u: unable to kill\n", cpu);
 }
 }
 
 
 /*
 /*
@@ -351,7 +351,7 @@ asmlinkage void secondary_start_kernel(void)
 
 
 	cpu_init();
 	cpu_init();
 
 
-	printk("CPU%u: Booted secondary processor\n", cpu);
+	pr_debug("CPU%u: Booted secondary processor\n", cpu);
 
 
 	preempt_disable();
 	preempt_disable();
 	trace_hardirqs_off();
 	trace_hardirqs_off();
@@ -387,9 +387,6 @@ asmlinkage void secondary_start_kernel(void)
 
 
 void __init smp_cpus_done(unsigned int max_cpus)
 void __init smp_cpus_done(unsigned int max_cpus)
 {
 {
-	printk(KERN_INFO "SMP: Total of %d processors activated.\n",
-	       num_online_cpus());
-
 	hyp_mode_check();
 	hyp_mode_check();
 }
 }
 
 
@@ -521,7 +518,7 @@ static void ipi_cpu_stop(unsigned int cpu)
 	if (system_state == SYSTEM_BOOTING ||
 	if (system_state == SYSTEM_BOOTING ||
 	    system_state == SYSTEM_RUNNING) {
 	    system_state == SYSTEM_RUNNING) {
 		raw_spin_lock(&stop_lock);
 		raw_spin_lock(&stop_lock);
-		printk(KERN_CRIT "CPU%u: stopping\n", cpu);
+		pr_crit("CPU%u: stopping\n", cpu);
 		dump_stack();
 		dump_stack();
 		raw_spin_unlock(&stop_lock);
 		raw_spin_unlock(&stop_lock);
 	}
 	}
@@ -615,8 +612,8 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 		break;
 		break;
 
 
 	default:
 	default:
-		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
-		       cpu, ipinr);
+		pr_crit("CPU%u: Unknown IPI message 0x%x\n",
+		        cpu, ipinr);
 		break;
 		break;
 	}
 	}
 
 

+ 2 - 2
arch/arm/kernel/smp_twd.c

@@ -199,7 +199,7 @@ static void twd_calibrate_rate(void)
 	 * the timer ticks
 	 * the timer ticks
 	 */
 	 */
 	if (twd_timer_rate == 0) {
 	if (twd_timer_rate == 0) {
-		printk(KERN_INFO "Calibrating local timer... ");
+		pr_info("Calibrating local timer... ");
 
 
 		/* Wait for a tick to start */
 		/* Wait for a tick to start */
 		waitjiffies = get_jiffies_64() + 1;
 		waitjiffies = get_jiffies_64() + 1;
@@ -223,7 +223,7 @@ static void twd_calibrate_rate(void)
 
 
 		twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
 		twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
 
 
-		printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000,
+		pr_cont("%lu.%02luMHz.\n", twd_timer_rate / 1000000,
 			(twd_timer_rate / 10000) % 100);
 			(twd_timer_rate / 10000) % 100);
 	}
 	}
 }
 }

+ 1 - 3
arch/arm/kernel/stacktrace.c

@@ -134,12 +134,10 @@ static noinline void __save_stack_trace(struct task_struct *tsk,
 		frame.pc = thread_saved_pc(tsk);
 		frame.pc = thread_saved_pc(tsk);
 #endif
 #endif
 	} else {
 	} else {
-		register unsigned long current_sp asm ("sp");
-
 		/* We don't want this function nor the caller */
 		/* We don't want this function nor the caller */
 		data.skip += 2;
 		data.skip += 2;
 		frame.fp = (unsigned long)__builtin_frame_address(0);
 		frame.fp = (unsigned long)__builtin_frame_address(0);
-		frame.sp = current_sp;
+		frame.sp = current_stack_pointer;
 		frame.lr = (unsigned long)__builtin_return_address(0);
 		frame.lr = (unsigned long)__builtin_return_address(0);
 		frame.pc = (unsigned long)__save_stack_trace;
 		frame.pc = (unsigned long)__save_stack_trace;
 	}
 	}

+ 1 - 1
arch/arm/kernel/swp_emulate.c

@@ -260,7 +260,7 @@ static int __init swp_emulation_init(void)
 		return -ENOMEM;
 		return -ENOMEM;
 #endif /* CONFIG_PROC_FS */
 #endif /* CONFIG_PROC_FS */
 
 
-	printk(KERN_NOTICE "Registering SWP/SWPB emulation handler\n");
+	pr_notice("Registering SWP/SWPB emulation handler\n");
 	register_undef_hook(&swp_hook);
 	register_undef_hook(&swp_hook);
 
 
 	return 0;
 	return 0;

+ 1 - 1
arch/arm/kernel/thumbee.c

@@ -72,7 +72,7 @@ static int __init thumbee_init(void)
 	if ((pfr0 & 0x0000f000) != 0x00001000)
 	if ((pfr0 & 0x0000f000) != 0x00001000)
 		return 0;
 		return 0;
 
 
-	printk(KERN_INFO "ThumbEE CPU extension supported.\n");
+	pr_info("ThumbEE CPU extension supported.\n");
 	elf_hwcap |= HWCAP_THUMBEE;
 	elf_hwcap |= HWCAP_THUMBEE;
 	thread_register_notifier(&thumbee_notifier_block);
 	thread_register_notifier(&thumbee_notifier_block);
 
 

+ 2 - 2
arch/arm/kernel/topology.c

@@ -165,7 +165,7 @@ static void update_cpu_capacity(unsigned int cpu)
 
 
 	set_capacity_scale(cpu, cpu_capacity(cpu) / middle_capacity);
 	set_capacity_scale(cpu, cpu_capacity(cpu) / middle_capacity);
 
 
-	printk(KERN_INFO "CPU%u: update cpu_capacity %lu\n",
+	pr_info("CPU%u: update cpu_capacity %lu\n",
 		cpu, arch_scale_cpu_capacity(NULL, cpu));
 		cpu, arch_scale_cpu_capacity(NULL, cpu));
 }
 }
 
 
@@ -269,7 +269,7 @@ void store_cpu_topology(unsigned int cpuid)
 
 
 	update_cpu_capacity(cpuid);
 	update_cpu_capacity(cpuid);
 
 
-	printk(KERN_INFO "CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n",
+	pr_info("CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n",
 		cpuid, cpu_topology[cpuid].thread_id,
 		cpuid, cpu_topology[cpuid].thread_id,
 		cpu_topology[cpuid].core_id,
 		cpu_topology[cpuid].core_id,
 		cpu_topology[cpuid].socket_id, mpidr);
 		cpu_topology[cpuid].socket_id, mpidr);

+ 21 - 21
arch/arm/kernel/traps.c

@@ -198,14 +198,14 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
 	}
 	}
 
 
 	if (!fp) {
 	if (!fp) {
-		printk("no frame pointer");
+		pr_cont("no frame pointer");
 		ok = 0;
 		ok = 0;
 	} else if (verify_stack(fp)) {
 	} else if (verify_stack(fp)) {
-		printk("invalid frame pointer 0x%08x", fp);
+		pr_cont("invalid frame pointer 0x%08x", fp);
 		ok = 0;
 		ok = 0;
 	} else if (fp < (unsigned long)end_of_stack(tsk))
 	} else if (fp < (unsigned long)end_of_stack(tsk))
-		printk("frame pointer underflow");
-	printk("\n");
+		pr_cont("frame pointer underflow");
+	pr_cont("\n");
 
 
 	if (ok)
 	if (ok)
 		c_backtrace(fp, mode);
 		c_backtrace(fp, mode);
@@ -240,8 +240,8 @@ static int __die(const char *str, int err, struct pt_regs *regs)
 	static int die_counter;
 	static int die_counter;
 	int ret;
 	int ret;
 
 
-	printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP
-	       S_ISA "\n", str, err, ++die_counter);
+	pr_emerg("Internal error: %s: %x [#%d]" S_PREEMPT S_SMP S_ISA "\n",
+	         str, err, ++die_counter);
 
 
 	/* trap and error numbers are mostly meaningless on ARM */
 	/* trap and error numbers are mostly meaningless on ARM */
 	ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV);
 	ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV);
@@ -250,8 +250,8 @@ static int __die(const char *str, int err, struct pt_regs *regs)
 
 
 	print_modules();
 	print_modules();
 	__show_regs(regs);
 	__show_regs(regs);
-	printk(KERN_EMERG "Process %.*s (pid: %d, stack limit = 0x%p)\n",
-		TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), end_of_stack(tsk));
+	pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n",
+		 TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), end_of_stack(tsk));
 
 
 	if (!user_mode(regs) || in_interrupt()) {
 	if (!user_mode(regs) || in_interrupt()) {
 		dump_mem(KERN_EMERG, "Stack: ", regs->ARM_sp,
 		dump_mem(KERN_EMERG, "Stack: ", regs->ARM_sp,
@@ -446,7 +446,7 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
 die_sig:
 die_sig:
 #ifdef CONFIG_DEBUG_USER
 #ifdef CONFIG_DEBUG_USER
 	if (user_debug & UDBG_UNDEFINED) {
 	if (user_debug & UDBG_UNDEFINED) {
-		printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
+		pr_info("%s (%d): undefined instruction: pc=%p\n",
 			current->comm, task_pid_nr(current), pc);
 			current->comm, task_pid_nr(current), pc);
 		__show_regs(regs);
 		__show_regs(regs);
 		dump_instr(KERN_INFO, regs);
 		dump_instr(KERN_INFO, regs);
@@ -496,7 +496,7 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason)
 {
 {
 	console_verbose();
 	console_verbose();
 
 
-	printk(KERN_CRIT "Bad mode in %s handler detected\n", handler[reason]);
+	pr_crit("Bad mode in %s handler detected\n", handler[reason]);
 
 
 	die("Oops - bad mode", regs, 0);
 	die("Oops - bad mode", regs, 0);
 	local_irq_disable();
 	local_irq_disable();
@@ -516,7 +516,7 @@ static int bad_syscall(int n, struct pt_regs *regs)
 
 
 #ifdef CONFIG_DEBUG_USER
 #ifdef CONFIG_DEBUG_USER
 	if (user_debug & UDBG_SYSCALL) {
 	if (user_debug & UDBG_SYSCALL) {
-		printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n",
+		pr_err("[%d] %s: obsolete system call %08x.\n",
 			task_pid_nr(current), current->comm, n);
 			task_pid_nr(current), current->comm, n);
 		dump_instr(KERN_ERR, regs);
 		dump_instr(KERN_ERR, regs);
 	}
 	}
@@ -694,7 +694,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
 	 * something catastrophic has happened
 	 * something catastrophic has happened
 	 */
 	 */
 	if (user_debug & UDBG_SYSCALL) {
 	if (user_debug & UDBG_SYSCALL) {
-		printk("[%d] %s: arm syscall %d\n",
+		pr_err("[%d] %s: arm syscall %d\n",
 		       task_pid_nr(current), current->comm, no);
 		       task_pid_nr(current), current->comm, no);
 		dump_instr("", regs);
 		dump_instr("", regs);
 		if (user_mode(regs)) {
 		if (user_mode(regs)) {
@@ -753,8 +753,8 @@ late_initcall(arm_mrc_hook_init);
 
 
 void __bad_xchg(volatile void *ptr, int size)
 void __bad_xchg(volatile void *ptr, int size)
 {
 {
-	printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
-		__builtin_return_address(0), ptr, size);
+	pr_err("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
+	       __builtin_return_address(0), ptr, size);
 	BUG();
 	BUG();
 }
 }
 EXPORT_SYMBOL(__bad_xchg);
 EXPORT_SYMBOL(__bad_xchg);
@@ -771,8 +771,8 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs)
 
 
 #ifdef CONFIG_DEBUG_USER
 #ifdef CONFIG_DEBUG_USER
 	if (user_debug & UDBG_BADABORT) {
 	if (user_debug & UDBG_BADABORT) {
-		printk(KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n",
-			task_pid_nr(current), current->comm, code, instr);
+		pr_err("[%d] %s: bad data abort: code %d instr 0x%08lx\n",
+		       task_pid_nr(current), current->comm, code, instr);
 		dump_instr(KERN_ERR, regs);
 		dump_instr(KERN_ERR, regs);
 		show_pte(current->mm, addr);
 		show_pte(current->mm, addr);
 	}
 	}
@@ -788,29 +788,29 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs)
 
 
 void __readwrite_bug(const char *fn)
 void __readwrite_bug(const char *fn)
 {
 {
-	printk("%s called, but not implemented\n", fn);
+	pr_err("%s called, but not implemented\n", fn);
 	BUG();
 	BUG();
 }
 }
 EXPORT_SYMBOL(__readwrite_bug);
 EXPORT_SYMBOL(__readwrite_bug);
 
 
 void __pte_error(const char *file, int line, pte_t pte)
 void __pte_error(const char *file, int line, pte_t pte)
 {
 {
-	printk("%s:%d: bad pte %08llx.\n", file, line, (long long)pte_val(pte));
+	pr_err("%s:%d: bad pte %08llx.\n", file, line, (long long)pte_val(pte));
 }
 }
 
 
 void __pmd_error(const char *file, int line, pmd_t pmd)
 void __pmd_error(const char *file, int line, pmd_t pmd)
 {
 {
-	printk("%s:%d: bad pmd %08llx.\n", file, line, (long long)pmd_val(pmd));
+	pr_err("%s:%d: bad pmd %08llx.\n", file, line, (long long)pmd_val(pmd));
 }
 }
 
 
 void __pgd_error(const char *file, int line, pgd_t pgd)
 void __pgd_error(const char *file, int line, pgd_t pgd)
 {
 {
-	printk("%s:%d: bad pgd %08llx.\n", file, line, (long long)pgd_val(pgd));
+	pr_err("%s:%d: bad pgd %08llx.\n", file, line, (long long)pgd_val(pgd));
 }
 }
 
 
 asmlinkage void __div0(void)
 asmlinkage void __div0(void)
 {
 {
-	printk("Division by zero in kernel.\n");
+	pr_err("Division by zero in kernel.\n");
 	dump_stack();
 	dump_stack();
 }
 }
 EXPORT_SYMBOL(__div0);
 EXPORT_SYMBOL(__div0);

+ 1 - 2
arch/arm/kernel/unwind.c

@@ -471,7 +471,6 @@ int unwind_frame(struct stackframe *frame)
 void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk)
 void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk)
 {
 {
 	struct stackframe frame;
 	struct stackframe frame;
-	register unsigned long current_sp asm ("sp");
 
 
 	pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
 	pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
 
 
@@ -485,7 +484,7 @@ void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk)
 			frame.pc = regs->ARM_lr;
 			frame.pc = regs->ARM_lr;
 	} else if (tsk == current) {
 	} else if (tsk == current) {
 		frame.fp = (unsigned long)__builtin_frame_address(0);
 		frame.fp = (unsigned long)__builtin_frame_address(0);
-		frame.sp = current_sp;
+		frame.sp = current_stack_pointer;
 		frame.lr = (unsigned long)__builtin_return_address(0);
 		frame.lr = (unsigned long)__builtin_return_address(0);
 		frame.pc = (unsigned long)unwind_backtrace;
 		frame.pc = (unsigned long)unwind_backtrace;
 	} else {
 	} else {

+ 19 - 0
arch/arm/kernel/vmlinux.lds.S

@@ -8,6 +8,9 @@
 #include <asm/thread_info.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
 #include <asm/memory.h>
 #include <asm/page.h>
 #include <asm/page.h>
+#ifdef CONFIG_ARM_KERNMEM_PERMS
+#include <asm/pgtable.h>
+#endif
 	
 	
 #define PROC_INFO							\
 #define PROC_INFO							\
 	. = ALIGN(4);							\
 	. = ALIGN(4);							\
@@ -90,6 +93,11 @@ SECTIONS
 		_text = .;
 		_text = .;
 		HEAD_TEXT
 		HEAD_TEXT
 	}
 	}
+
+#ifdef CONFIG_ARM_KERNMEM_PERMS
+	. = ALIGN(1<<SECTION_SHIFT);
+#endif
+
 	.text : {			/* Real text segment		*/
 	.text : {			/* Real text segment		*/
 		_stext = .;		/* Text and read-only data	*/
 		_stext = .;		/* Text and read-only data	*/
 			__exception_text_start = .;
 			__exception_text_start = .;
@@ -112,6 +120,9 @@ SECTIONS
 			ARM_CPU_KEEP(PROC_INFO)
 			ARM_CPU_KEEP(PROC_INFO)
 	}
 	}
 
 
+#ifdef CONFIG_DEBUG_RODATA
+	. = ALIGN(1<<SECTION_SHIFT);
+#endif
 	RO_DATA(PAGE_SIZE)
 	RO_DATA(PAGE_SIZE)
 
 
 	. = ALIGN(4);
 	. = ALIGN(4);
@@ -145,7 +156,11 @@ SECTIONS
 	_etext = .;			/* End of text and rodata section */
 	_etext = .;			/* End of text and rodata section */
 
 
 #ifndef CONFIG_XIP_KERNEL
 #ifndef CONFIG_XIP_KERNEL
+# ifdef CONFIG_ARM_KERNMEM_PERMS
+	. = ALIGN(1<<SECTION_SHIFT);
+# else
 	. = ALIGN(PAGE_SIZE);
 	. = ALIGN(PAGE_SIZE);
+# endif
 	__init_begin = .;
 	__init_begin = .;
 #endif
 #endif
 	/*
 	/*
@@ -218,8 +233,12 @@ SECTIONS
 #ifdef CONFIG_XIP_KERNEL
 #ifdef CONFIG_XIP_KERNEL
 	__data_loc = ALIGN(4);		/* location in binary */
 	__data_loc = ALIGN(4);		/* location in binary */
 	. = PAGE_OFFSET + TEXT_OFFSET;
 	. = PAGE_OFFSET + TEXT_OFFSET;
+#else
+#ifdef CONFIG_ARM_KERNMEM_PERMS
+	. = ALIGN(1<<SECTION_SHIFT);
 #else
 #else
 	. = ALIGN(THREAD_SIZE);
 	. = ALIGN(THREAD_SIZE);
+#endif
 	__init_end = .;
 	__init_end = .;
 	__data_loc = .;
 	__data_loc = .;
 #endif
 #endif

+ 3 - 4
arch/arm/kernel/xscale-cp0.c

@@ -157,15 +157,14 @@ static int __init xscale_cp0_init(void)
 
 
 	if (cpu_has_iwmmxt()) {
 	if (cpu_has_iwmmxt()) {
 #ifndef CONFIG_IWMMXT
 #ifndef CONFIG_IWMMXT
-		printk(KERN_WARNING "CAUTION: XScale iWMMXt coprocessor "
-			"detected, but kernel support is missing.\n");
+		pr_warn("CAUTION: XScale iWMMXt coprocessor detected, but kernel support is missing.\n");
 #else
 #else
-		printk(KERN_INFO "XScale iWMMXt coprocessor detected.\n");
+		pr_info("XScale iWMMXt coprocessor detected.\n");
 		elf_hwcap |= HWCAP_IWMMXT;
 		elf_hwcap |= HWCAP_IWMMXT;
 		thread_register_notifier(&iwmmxt_notifier_block);
 		thread_register_notifier(&iwmmxt_notifier_block);
 #endif
 #endif
 	} else {
 	} else {
-		printk(KERN_INFO "XScale DSP coprocessor detected.\n");
+		pr_info("XScale DSP coprocessor detected.\n");
 		thread_register_notifier(&dsp_notifier_block);
 		thread_register_notifier(&dsp_notifier_block);
 		cp_access |= 1;
 		cp_access |= 1;
 	}
 	}

+ 5 - 0
arch/arm/lib/copy_from_user.S

@@ -12,6 +12,7 @@
 
 
 #include <linux/linkage.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/assembler.h>
+#include <asm/unwind.h>
 
 
 /*
 /*
  * Prototype:
  * Prototype:
@@ -77,6 +78,10 @@
 	stmdb	sp!, {r0, r2, r3, \reg1, \reg2}
 	stmdb	sp!, {r0, r2, r3, \reg1, \reg2}
 	.endm
 	.endm
 
 
+	.macro usave reg1 reg2
+	UNWIND(	.save {r0, r2, r3, \reg1, \reg2}	)
+	.endm
+
 	.macro exit reg1 reg2
 	.macro exit reg1 reg2
 	add	sp, sp, #8
 	add	sp, sp, #8
 	ldmfd	sp!, {r0, \reg1, \reg2}
 	ldmfd	sp!, {r0, \reg1, \reg2}

+ 30 - 0
arch/arm/lib/copy_template.S

@@ -53,6 +53,12 @@
  *	data as needed by the implementation including this code. Called
  *	data as needed by the implementation including this code. Called
  *	upon code entry.
  *	upon code entry.
  *
  *
+ * usave reg1 reg2
+ *
+ *	Unwind annotation macro is corresponding for 'enter' macro.
+ *	It tell unwinder that preserved some provided registers on the stack
+ *	and additional data by a prior 'enter' macro.
+ *
  * exit reg1 reg2
  * exit reg1 reg2
  *
  *
  *	Restore registers with the values previously saved with the
  *	Restore registers with the values previously saved with the
@@ -67,7 +73,12 @@
  */
  */
 
 
 
 
+	UNWIND(	.fnstart			)
 		enter	r4, lr
 		enter	r4, lr
+	UNWIND(	.fnend				)
+
+	UNWIND(	.fnstart			)
+		usave	r4, lr			  @ in first stmdb block
 
 
 		subs	r2, r2, #4
 		subs	r2, r2, #4
 		blt	8f
 		blt	8f
@@ -79,6 +90,11 @@
 
 
 1:		subs	r2, r2, #(28)
 1:		subs	r2, r2, #(28)
 		stmfd	sp!, {r5 - r8}
 		stmfd	sp!, {r5 - r8}
+	UNWIND(	.fnend				)
+
+	UNWIND(	.fnstart			)
+		usave	r4, lr
+	UNWIND(	.save	{r5 - r8}		) @ in second stmfd block
 		blt	5f
 		blt	5f
 
 
 	CALGN(	ands	ip, r0, #31		)
 	CALGN(	ands	ip, r0, #31		)
@@ -144,7 +160,10 @@
 	CALGN(	bcs	2b			)
 	CALGN(	bcs	2b			)
 
 
 7:		ldmfd	sp!, {r5 - r8}
 7:		ldmfd	sp!, {r5 - r8}
+	UNWIND(	.fnend				) @ end of second stmfd block
 
 
+	UNWIND(	.fnstart			)
+		usave	r4, lr			  @ still in first stmdb block
 8:		movs	r2, r2, lsl #31
 8:		movs	r2, r2, lsl #31
 		ldr1b	r1, r3, ne, abort=21f
 		ldr1b	r1, r3, ne, abort=21f
 		ldr1b	r1, r4, cs, abort=21f
 		ldr1b	r1, r4, cs, abort=21f
@@ -173,10 +192,13 @@
 		ldr1w	r1, lr, abort=21f
 		ldr1w	r1, lr, abort=21f
 		beq	17f
 		beq	17f
 		bgt	18f
 		bgt	18f
+	UNWIND(	.fnend				)
 
 
 
 
 		.macro	forward_copy_shift pull push
 		.macro	forward_copy_shift pull push
 
 
+	UNWIND(	.fnstart			)
+		usave	r4, lr			  @ still in first stmdb block
 		subs	r2, r2, #28
 		subs	r2, r2, #28
 		blt	14f
 		blt	14f
 
 
@@ -187,7 +209,11 @@
 	CALGN(	bcc	15f			)
 	CALGN(	bcc	15f			)
 
 
 11:		stmfd	sp!, {r5 - r9}
 11:		stmfd	sp!, {r5 - r9}
+	UNWIND(	.fnend				)
 
 
+	UNWIND(	.fnstart			)
+		usave	r4, lr
+	UNWIND(	.save	{r5 - r9}		) @ in new second stmfd block
 	PLD(	pld	[r1, #0]		)
 	PLD(	pld	[r1, #0]		)
 	PLD(	subs	r2, r2, #96		)
 	PLD(	subs	r2, r2, #96		)
 	PLD(	pld	[r1, #28]		)
 	PLD(	pld	[r1, #28]		)
@@ -221,7 +247,10 @@
 	PLD(	bge	13b			)
 	PLD(	bge	13b			)
 
 
 		ldmfd	sp!, {r5 - r9}
 		ldmfd	sp!, {r5 - r9}
+	UNWIND(	.fnend				) @ end of the second stmfd block
 
 
+	UNWIND(	.fnstart			)
+		usave	r4, lr			  @ still in first stmdb block
 14:		ands	ip, r2, #28
 14:		ands	ip, r2, #28
 		beq	16f
 		beq	16f
 
 
@@ -236,6 +265,7 @@
 
 
 16:		sub	r1, r1, #(\push / 8)
 16:		sub	r1, r1, #(\push / 8)
 		b	8b
 		b	8b
+	UNWIND(	.fnend				)
 
 
 		.endm
 		.endm
 
 

+ 5 - 0
arch/arm/lib/copy_to_user.S

@@ -12,6 +12,7 @@
 
 
 #include <linux/linkage.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/assembler.h>
+#include <asm/unwind.h>
 
 
 /*
 /*
  * Prototype:
  * Prototype:
@@ -80,6 +81,10 @@
 	stmdb	sp!, {r0, r2, r3, \reg1, \reg2}
 	stmdb	sp!, {r0, r2, r3, \reg1, \reg2}
 	.endm
 	.endm
 
 
+	.macro usave reg1 reg2
+	UNWIND(	.save {r0, r2, r3, \reg1, \reg2}	)
+	.endm
+
 	.macro exit reg1 reg2
 	.macro exit reg1 reg2
 	add	sp, sp, #8
 	add	sp, sp, #8
 	ldmfd	sp!, {r0, \reg1, \reg2}
 	ldmfd	sp!, {r0, \reg1, \reg2}

+ 5 - 0
arch/arm/lib/memcpy.S

@@ -12,6 +12,7 @@
 
 
 #include <linux/linkage.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/assembler.h>
+#include <asm/unwind.h>
 
 
 #define LDR1W_SHIFT	0
 #define LDR1W_SHIFT	0
 #define STR1W_SHIFT	0
 #define STR1W_SHIFT	0
@@ -48,6 +49,10 @@
 	stmdb sp!, {r0, \reg1, \reg2}
 	stmdb sp!, {r0, \reg1, \reg2}
 	.endm
 	.endm
 
 
+	.macro usave reg1 reg2
+	UNWIND(	.save	{r0, \reg1, \reg2}	)
+	.endm
+
 	.macro exit reg1 reg2
 	.macro exit reg1 reg2
 	ldmfd sp!, {r0, \reg1, \reg2}
 	ldmfd sp!, {r0, \reg1, \reg2}
 	.endm
 	.endm

+ 28 - 0
arch/arm/lib/memmove.S

@@ -12,6 +12,7 @@
 
 
 #include <linux/linkage.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/assembler.h>
+#include <asm/unwind.h>
 
 
 		.text
 		.text
 
 
@@ -27,12 +28,17 @@
  */
  */
 
 
 ENTRY(memmove)
 ENTRY(memmove)
+	UNWIND(	.fnstart			)
 
 
 		subs	ip, r0, r1
 		subs	ip, r0, r1
 		cmphi	r2, ip
 		cmphi	r2, ip
 		bls	memcpy
 		bls	memcpy
 
 
 		stmfd	sp!, {r0, r4, lr}
 		stmfd	sp!, {r0, r4, lr}
+	UNWIND(	.fnend				)
+
+	UNWIND(	.fnstart			)
+	UNWIND(	.save	{r0, r4, lr}		) @ in first stmfd block
 		add	r1, r1, r2
 		add	r1, r1, r2
 		add	r0, r0, r2
 		add	r0, r0, r2
 		subs	r2, r2, #4
 		subs	r2, r2, #4
@@ -45,6 +51,11 @@ ENTRY(memmove)
 
 
 1:		subs	r2, r2, #(28)
 1:		subs	r2, r2, #(28)
 		stmfd	sp!, {r5 - r8}
 		stmfd	sp!, {r5 - r8}
+	UNWIND(	.fnend				)
+
+	UNWIND(	.fnstart			)
+	UNWIND(	.save	{r0, r4, lr}		)
+	UNWIND(	.save	{r5 - r8}		) @ in second stmfd block
 		blt	5f
 		blt	5f
 
 
 	CALGN(	ands	ip, r0, #31		)
 	CALGN(	ands	ip, r0, #31		)
@@ -97,6 +108,10 @@ ENTRY(memmove)
 	CALGN(	bcs	2b			)
 	CALGN(	bcs	2b			)
 
 
 7:		ldmfd	sp!, {r5 - r8}
 7:		ldmfd	sp!, {r5 - r8}
+	UNWIND(	.fnend				) @ end of second stmfd block
+
+	UNWIND(	.fnstart			)
+	UNWIND(	.save	{r0, r4, lr}		) @ still in first stmfd block
 
 
 8:		movs	r2, r2, lsl #31
 8:		movs	r2, r2, lsl #31
 		ldrneb	r3, [r1, #-1]!
 		ldrneb	r3, [r1, #-1]!
@@ -124,10 +139,13 @@ ENTRY(memmove)
 		ldr	r3, [r1, #0]
 		ldr	r3, [r1, #0]
 		beq	17f
 		beq	17f
 		blt	18f
 		blt	18f
+	UNWIND(	.fnend				)
 
 
 
 
 		.macro	backward_copy_shift push pull
 		.macro	backward_copy_shift push pull
 
 
+	UNWIND(	.fnstart			)
+	UNWIND(	.save	{r0, r4, lr}		) @ still in first stmfd block
 		subs	r2, r2, #28
 		subs	r2, r2, #28
 		blt	14f
 		blt	14f
 
 
@@ -137,6 +155,11 @@ ENTRY(memmove)
 	CALGN(	bcc	15f			)
 	CALGN(	bcc	15f			)
 
 
 11:		stmfd	sp!, {r5 - r9}
 11:		stmfd	sp!, {r5 - r9}
+	UNWIND(	.fnend				)
+
+	UNWIND(	.fnstart			)
+	UNWIND(	.save	{r0, r4, lr}		)
+	UNWIND(	.save	{r5 - r9}		) @ in new second stmfd block
 
 
 	PLD(	pld	[r1, #-4]		)
 	PLD(	pld	[r1, #-4]		)
 	PLD(	subs	r2, r2, #96		)
 	PLD(	subs	r2, r2, #96		)
@@ -171,6 +194,10 @@ ENTRY(memmove)
 	PLD(	bge	13b			)
 	PLD(	bge	13b			)
 
 
 		ldmfd	sp!, {r5 - r9}
 		ldmfd	sp!, {r5 - r9}
+	UNWIND(	.fnend				) @ end of the second stmfd block
+
+	UNWIND(	.fnstart			)
+	UNWIND(	.save {r0, r4, lr}		) @ still in first stmfd block
 
 
 14:		ands	ip, r2, #28
 14:		ands	ip, r2, #28
 		beq	16f
 		beq	16f
@@ -186,6 +213,7 @@ ENTRY(memmove)
 
 
 16:		add	r1, r1, #(\pull / 8)
 16:		add	r1, r1, #(\pull / 8)
 		b	8b
 		b	8b
+	UNWIND(	.fnend				)
 
 
 		.endm
 		.endm
 
 

+ 12 - 0
arch/arm/lib/memset.S

@@ -11,11 +11,13 @@
  */
  */
 #include <linux/linkage.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/assembler.h>
+#include <asm/unwind.h>
 
 
 	.text
 	.text
 	.align	5
 	.align	5
 
 
 ENTRY(memset)
 ENTRY(memset)
+UNWIND( .fnstart         )
 	ands	r3, r0, #3		@ 1 unaligned?
 	ands	r3, r0, #3		@ 1 unaligned?
 	mov	ip, r0			@ preserve r0 as return value
 	mov	ip, r0			@ preserve r0 as return value
 	bne	6f			@ 1
 	bne	6f			@ 1
@@ -34,6 +36,9 @@ ENTRY(memset)
  * We need 2 extra registers for this loop - use r8 and the LR
  * We need 2 extra registers for this loop - use r8 and the LR
  */
  */
 	stmfd	sp!, {r8, lr}
 	stmfd	sp!, {r8, lr}
+UNWIND( .fnend              )
+UNWIND( .fnstart            )
+UNWIND( .save {r8, lr}      )
 	mov	r8, r1
 	mov	r8, r1
 	mov	lr, r1
 	mov	lr, r1
 
 
@@ -53,6 +58,7 @@ ENTRY(memset)
 	tst	r2, #16
 	tst	r2, #16
 	stmneia	ip!, {r1, r3, r8, lr}
 	stmneia	ip!, {r1, r3, r8, lr}
 	ldmfd	sp!, {r8, lr}
 	ldmfd	sp!, {r8, lr}
+UNWIND( .fnend              )
 
 
 #else
 #else
 
 
@@ -62,6 +68,9 @@ ENTRY(memset)
  */
  */
 
 
 	stmfd	sp!, {r4-r8, lr}
 	stmfd	sp!, {r4-r8, lr}
+UNWIND( .fnend                 )
+UNWIND( .fnstart               )
+UNWIND( .save {r4-r8, lr}      )
 	mov	r4, r1
 	mov	r4, r1
 	mov	r5, r1
 	mov	r5, r1
 	mov	r6, r1
 	mov	r6, r1
@@ -94,9 +103,11 @@ ENTRY(memset)
 	tst	r2, #16
 	tst	r2, #16
 	stmneia	ip!, {r4-r7}
 	stmneia	ip!, {r4-r7}
 	ldmfd	sp!, {r4-r8, lr}
 	ldmfd	sp!, {r4-r8, lr}
+UNWIND( .fnend                 )
 
 
 #endif
 #endif
 
 
+UNWIND( .fnstart            )
 4:	tst	r2, #8
 4:	tst	r2, #8
 	stmneia	ip!, {r1, r3}
 	stmneia	ip!, {r1, r3}
 	tst	r2, #4
 	tst	r2, #4
@@ -120,4 +131,5 @@ ENTRY(memset)
 	strb	r1, [ip], #1		@ 1
 	strb	r1, [ip], #1		@ 1
 	add	r2, r2, r3		@ 1 (r2 = r2 - (4 - r3))
 	add	r2, r2, r3		@ 1 (r2 = r2 - (4 - r3))
 	b	1b
 	b	1b
+UNWIND( .fnend   )
 ENDPROC(memset)
 ENDPROC(memset)

+ 12 - 0
arch/arm/lib/memzero.S

@@ -9,6 +9,7 @@
  */
  */
 #include <linux/linkage.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/assembler.h>
+#include <asm/unwind.h>
 
 
 	.text
 	.text
 	.align	5
 	.align	5
@@ -18,6 +19,7 @@
  * mis-aligned by, and r1 is the number of bytes.  If r1 < 4, then we
  * mis-aligned by, and r1 is the number of bytes.  If r1 < 4, then we
  * don't bother; we use byte stores instead.
  * don't bother; we use byte stores instead.
  */
  */
+UNWIND(	.fnstart			)
 1:	subs	r1, r1, #4		@ 1 do we have enough
 1:	subs	r1, r1, #4		@ 1 do we have enough
 	blt	5f			@ 1 bytes to align with?
 	blt	5f			@ 1 bytes to align with?
 	cmp	r3, #2			@ 1
 	cmp	r3, #2			@ 1
@@ -47,6 +49,9 @@ ENTRY(__memzero)
  * use the LR
  * use the LR
  */
  */
 	str	lr, [sp, #-4]!		@ 1
 	str	lr, [sp, #-4]!		@ 1
+UNWIND(	.fnend				)
+UNWIND(	.fnstart			)
+UNWIND(	.save 	{lr}			)
 	mov	ip, r2			@ 1
 	mov	ip, r2			@ 1
 	mov	lr, r2			@ 1
 	mov	lr, r2			@ 1
 
 
@@ -66,6 +71,7 @@ ENTRY(__memzero)
 	tst	r1, #16			@ 1 16 bytes or more?
 	tst	r1, #16			@ 1 16 bytes or more?
 	stmneia	r0!, {r2, r3, ip, lr}	@ 4
 	stmneia	r0!, {r2, r3, ip, lr}	@ 4
 	ldr	lr, [sp], #4		@ 1
 	ldr	lr, [sp], #4		@ 1
+UNWIND(	.fnend				)
 
 
 #else
 #else
 
 
@@ -75,6 +81,9 @@ ENTRY(__memzero)
  */
  */
 
 
 	stmfd	sp!, {r4-r7, lr}
 	stmfd	sp!, {r4-r7, lr}
+UNWIND(	.fnend		       )
+UNWIND(	.fnstart	       )
+UNWIND(	.save 	{r4-r7, lr}    )
 	mov	r4, r2
 	mov	r4, r2
 	mov	r5, r2
 	mov	r5, r2
 	mov	r6, r2
 	mov	r6, r2
@@ -105,9 +114,11 @@ ENTRY(__memzero)
 	tst	r1, #16
 	tst	r1, #16
 	stmneia	r0!, {r4-r7}
 	stmneia	r0!, {r4-r7}
 	ldmfd	sp!, {r4-r7, lr}
 	ldmfd	sp!, {r4-r7, lr}
+UNWIND(	.fnend		       )
 
 
 #endif
 #endif
 
 
+UNWIND(	.fnstart			)
 4:	tst	r1, #8			@ 1 8 bytes or more?
 4:	tst	r1, #8			@ 1 8 bytes or more?
 	stmneia	r0!, {r2, r3}		@ 2
 	stmneia	r0!, {r2, r3}		@ 2
 	tst	r1, #4			@ 1 4 bytes or more?
 	tst	r1, #4			@ 1 4 bytes or more?
@@ -122,4 +133,5 @@ ENTRY(__memzero)
 	tst	r1, #1			@ 1 a byte left over
 	tst	r1, #1			@ 1 a byte left over
 	strneb	r2, [r0], #1		@ 1
 	strneb	r2, [r0], #1		@ 1
 	ret	lr			@ 1
 	ret	lr			@ 1
+UNWIND(	.fnend				)
 ENDPROC(__memzero)
 ENDPROC(__memzero)

+ 36 - 7
arch/arm/mach-sa1100/clock.c

@@ -15,10 +15,12 @@
 #include <linux/clkdev.h>
 #include <linux/clkdev.h>
 
 
 #include <mach/hardware.h>
 #include <mach/hardware.h>
+#include <mach/generic.h>
 
 
 struct clkops {
 struct clkops {
 	void			(*enable)(struct clk *);
 	void			(*enable)(struct clk *);
 	void			(*disable)(struct clk *);
 	void			(*disable)(struct clk *);
+	unsigned long		(*get_rate)(struct clk *);
 };
 };
 
 
 struct clk {
 struct clk {
@@ -33,13 +35,6 @@ struct clk clk_##_name = {				\
 
 
 static DEFINE_SPINLOCK(clocks_lock);
 static DEFINE_SPINLOCK(clocks_lock);
 
 
-/* Dummy clk routine to build generic kernel parts that may be using them */
-unsigned long clk_get_rate(struct clk *clk)
-{
-	return 0;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
 static void clk_gpio27_enable(struct clk *clk)
 static void clk_gpio27_enable(struct clk *clk)
 {
 {
 	/*
 	/*
@@ -58,6 +53,19 @@ static void clk_gpio27_disable(struct clk *clk)
 	GAFR &= ~GPIO_32_768kHz;
 	GAFR &= ~GPIO_32_768kHz;
 }
 }
 
 
+static void clk_cpu_enable(struct clk *clk)
+{
+}
+
+static void clk_cpu_disable(struct clk *clk)
+{
+}
+
+static unsigned long clk_cpu_get_rate(struct clk *clk)
+{
+	return sa11x0_getspeed(0) * 1000;
+}
+
 int clk_enable(struct clk *clk)
 int clk_enable(struct clk *clk)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
@@ -87,16 +95,37 @@ void clk_disable(struct clk *clk)
 }
 }
 EXPORT_SYMBOL(clk_disable);
 EXPORT_SYMBOL(clk_disable);
 
 
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk && clk->ops && clk->ops->get_rate)
+		return clk->ops->get_rate(clk);
+
+	return 0;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
 const struct clkops clk_gpio27_ops = {
 const struct clkops clk_gpio27_ops = {
 	.enable		= clk_gpio27_enable,
 	.enable		= clk_gpio27_enable,
 	.disable	= clk_gpio27_disable,
 	.disable	= clk_gpio27_disable,
 };
 };
 
 
+const struct clkops clk_cpu_ops = {
+	.enable		= clk_cpu_enable,
+	.disable	= clk_cpu_disable,
+	.get_rate	= clk_cpu_get_rate,
+};
+
 static DEFINE_CLK(gpio27, &clk_gpio27_ops);
 static DEFINE_CLK(gpio27, &clk_gpio27_ops);
 
 
+static DEFINE_CLK(cpu, &clk_cpu_ops);
+
 static struct clk_lookup sa11xx_clkregs[] = {
 static struct clk_lookup sa11xx_clkregs[] = {
 	CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27),
 	CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27),
 	CLKDEV_INIT("sa1100-rtc", NULL, NULL),
 	CLKDEV_INIT("sa1100-rtc", NULL, NULL),
+	CLKDEV_INIT("sa11x0-fb", NULL, &clk_cpu),
+	CLKDEV_INIT("sa11x0-pcmcia", NULL, &clk_cpu),
+	/* sa1111 names devices using internal offsets, PCMCIA is at 0x1800 */
+	CLKDEV_INIT("1800", NULL, &clk_cpu),
 };
 };
 
 
 static int __init sa11xx_clk_init(void)
 static int __init sa11xx_clk_init(void)

+ 7 - 48
arch/arm/mach-sa1100/collie.c

@@ -30,7 +30,7 @@
 #include <linux/gpio_keys.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
-#include <linux/pda_power.h>
+#include <linux/power/gpio-charger.h>
 
 
 #include <video/sa1100fb.h>
 #include <video/sa1100fb.h>
 
 
@@ -131,62 +131,24 @@ static struct irda_platform_data collie_ir_data = {
 /*
 /*
  * Collie AC IN
  * Collie AC IN
  */
  */
-static int collie_power_init(struct device *dev)
-{
-	int ret = gpio_request(COLLIE_GPIO_AC_IN, "ac in");
-	if (ret)
-		goto err_gpio_req;
-
-	ret = gpio_direction_input(COLLIE_GPIO_AC_IN);
-	if (ret)
-		goto err_gpio_in;
-
-	return 0;
-
-err_gpio_in:
-	gpio_free(COLLIE_GPIO_AC_IN);
-err_gpio_req:
-	return ret;
-}
-
-static void collie_power_exit(struct device *dev)
-{
-	gpio_free(COLLIE_GPIO_AC_IN);
-}
-
-static int collie_power_ac_online(void)
-{
-	return gpio_get_value(COLLIE_GPIO_AC_IN) == 2;
-}
-
 static char *collie_ac_supplied_to[] = {
 static char *collie_ac_supplied_to[] = {
 	"main-battery",
 	"main-battery",
 	"backup-battery",
 	"backup-battery",
 };
 };
 
 
-static struct pda_power_pdata collie_power_data = {
-	.init			= collie_power_init,
-	.is_ac_online		= collie_power_ac_online,
-	.exit			= collie_power_exit,
+
+static struct gpio_charger_platform_data collie_power_data = {
+	.name			= "charger",
+	.type			= POWER_SUPPLY_TYPE_MAINS,
+	.gpio			= COLLIE_GPIO_AC_IN,
 	.supplied_to		= collie_ac_supplied_to,
 	.supplied_to		= collie_ac_supplied_to,
 	.num_supplicants	= ARRAY_SIZE(collie_ac_supplied_to),
 	.num_supplicants	= ARRAY_SIZE(collie_ac_supplied_to),
 };
 };
 
 
-static struct resource collie_power_resource[] = {
-	{
-		.name		= "ac",
-		.flags		= IORESOURCE_IRQ |
-				  IORESOURCE_IRQ_HIGHEDGE |
-				  IORESOURCE_IRQ_LOWEDGE,
-	},
-};
-
 static struct platform_device collie_power_device = {
 static struct platform_device collie_power_device = {
-	.name			= "pda-power",
+	.name			= "gpio-charger",
 	.id			= -1,
 	.id			= -1,
 	.dev.platform_data	= &collie_power_data,
 	.dev.platform_data	= &collie_power_data,
-	.resource		= collie_power_resource,
-	.num_resources		= ARRAY_SIZE(collie_power_resource),
 };
 };
 
 
 #ifdef CONFIG_SHARP_LOCOMO
 #ifdef CONFIG_SHARP_LOCOMO
@@ -420,9 +382,6 @@ static void __init collie_init(void)
 
 
 	GPSR |= _COLLIE_GPIO_UCB1x00_RESET;
 	GPSR |= _COLLIE_GPIO_UCB1x00_RESET;
 
 
-	collie_power_resource[0].start = gpio_to_irq(COLLIE_GPIO_AC_IN);
-	collie_power_resource[0].end = gpio_to_irq(COLLIE_GPIO_AC_IN);
-
 	sa11x0_ppc_configure_mcp();
 	sa11x0_ppc_configure_mcp();
 
 
 
 

+ 0 - 41
arch/arm/mach-sa1100/include/mach/entry-macro.S

@@ -1,41 +0,0 @@
-/*
- * arch/arm/mach-sa1100/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for SA1100-based platforms
- *
- * 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.
- */
-
-		.macro  get_irqnr_preamble, base, tmp
-		mov	\base, #0xfa000000		@ ICIP = 0xfa050000
-		add	\base, \base, #0x00050000
-		.endm
-
-		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
-		ldr	\irqstat, [\base]		@ get irqs
-		ldr	\irqnr, [\base, #4]		@ ICMR = 0xfa050004
-		ands	\irqstat, \irqstat, \irqnr
-		mov	\irqnr, #0
-		beq	1001f
-		tst	\irqstat, #0xff
-		moveq	\irqstat, \irqstat, lsr #8
-		addeq	\irqnr, \irqnr, #8
-		tsteq	\irqstat, #0xff
-		moveq	\irqstat, \irqstat, lsr #8
-		addeq	\irqnr, \irqnr, #8
-		tsteq	\irqstat, #0xff
-		moveq	\irqstat, \irqstat, lsr #8
-		addeq	\irqnr, \irqnr, #8
-		tst	\irqstat, #0x0f
-		moveq	\irqstat, \irqstat, lsr #4
-		addeq	\irqnr, \irqnr, #4
-		tst	\irqstat, #0x03
-		moveq	\irqstat, \irqstat, lsr #2
-		addeq	\irqnr, \irqnr, #2
-		tst	\irqstat, #0x01
-		addeqs	\irqnr, \irqnr, #1
-1001:
-		.endm
-

+ 51 - 51
arch/arm/mach-sa1100/include/mach/irqs.h

@@ -8,56 +8,56 @@
  * 2001/11/14	RMK	Cleaned up and standardised a lot of the IRQs.
  * 2001/11/14	RMK	Cleaned up and standardised a lot of the IRQs.
  */
  */
 
 
-#define	IRQ_GPIO0		0
-#define	IRQ_GPIO1		1
-#define	IRQ_GPIO2		2
-#define	IRQ_GPIO3		3
-#define	IRQ_GPIO4		4
-#define	IRQ_GPIO5		5
-#define	IRQ_GPIO6		6
-#define	IRQ_GPIO7		7
-#define	IRQ_GPIO8		8
-#define	IRQ_GPIO9		9
-#define	IRQ_GPIO10		10
-#define	IRQ_GPIO11_27		11
-#define	IRQ_LCD  		12	/* LCD controller           */
-#define	IRQ_Ser0UDC		13	/* Ser. port 0 UDC          */
-#define	IRQ_Ser1SDLC		14	/* Ser. port 1 SDLC         */
-#define	IRQ_Ser1UART		15	/* Ser. port 1 UART         */
-#define	IRQ_Ser2ICP		16	/* Ser. port 2 ICP          */
-#define	IRQ_Ser3UART		17	/* Ser. port 3 UART         */
-#define	IRQ_Ser4MCP		18	/* Ser. port 4 MCP          */
-#define	IRQ_Ser4SSP		19	/* Ser. port 4 SSP          */
-#define	IRQ_DMA0 		20	/* DMA controller channel 0 */
-#define	IRQ_DMA1 		21	/* DMA controller channel 1 */
-#define	IRQ_DMA2 		22	/* DMA controller channel 2 */
-#define	IRQ_DMA3 		23	/* DMA controller channel 3 */
-#define	IRQ_DMA4 		24	/* DMA controller channel 4 */
-#define	IRQ_DMA5 		25	/* DMA controller channel 5 */
-#define	IRQ_OST0 		26	/* OS Timer match 0         */
-#define	IRQ_OST1 		27	/* OS Timer match 1         */
-#define	IRQ_OST2 		28	/* OS Timer match 2         */
-#define	IRQ_OST3 		29	/* OS Timer match 3         */
-#define	IRQ_RTC1Hz		30	/* RTC 1 Hz clock           */
-#define	IRQ_RTCAlrm		31	/* RTC Alarm                */
+#define	IRQ_GPIO0		1
+#define	IRQ_GPIO1		2
+#define	IRQ_GPIO2		3
+#define	IRQ_GPIO3		4
+#define	IRQ_GPIO4		5
+#define	IRQ_GPIO5		6
+#define	IRQ_GPIO6		7
+#define	IRQ_GPIO7		8
+#define	IRQ_GPIO8		9
+#define	IRQ_GPIO9		10
+#define	IRQ_GPIO10		11
+#define	IRQ_GPIO11_27		12
+#define	IRQ_LCD			13	/* LCD controller           */
+#define	IRQ_Ser0UDC		14	/* Ser. port 0 UDC          */
+#define	IRQ_Ser1SDLC		15	/* Ser. port 1 SDLC         */
+#define	IRQ_Ser1UART		16	/* Ser. port 1 UART         */
+#define	IRQ_Ser2ICP		17	/* Ser. port 2 ICP          */
+#define	IRQ_Ser3UART		18	/* Ser. port 3 UART         */
+#define	IRQ_Ser4MCP		19	/* Ser. port 4 MCP          */
+#define	IRQ_Ser4SSP		20	/* Ser. port 4 SSP          */
+#define	IRQ_DMA0		21	/* DMA controller channel 0 */
+#define	IRQ_DMA1		22	/* DMA controller channel 1 */
+#define	IRQ_DMA2		23	/* DMA controller channel 2 */
+#define	IRQ_DMA3		24	/* DMA controller channel 3 */
+#define	IRQ_DMA4		25	/* DMA controller channel 4 */
+#define	IRQ_DMA5		26	/* DMA controller channel 5 */
+#define	IRQ_OST0		27	/* OS Timer match 0         */
+#define	IRQ_OST1		28	/* OS Timer match 1         */
+#define	IRQ_OST2		29	/* OS Timer match 2         */
+#define	IRQ_OST3		30	/* OS Timer match 3         */
+#define	IRQ_RTC1Hz		31	/* RTC 1 Hz clock           */
+#define	IRQ_RTCAlrm		32	/* RTC Alarm                */
 
 
-#define	IRQ_GPIO11		32
-#define	IRQ_GPIO12		33
-#define	IRQ_GPIO13		34
-#define	IRQ_GPIO14		35
-#define	IRQ_GPIO15		36
-#define	IRQ_GPIO16		37
-#define	IRQ_GPIO17		38
-#define	IRQ_GPIO18		39
-#define	IRQ_GPIO19		40
-#define	IRQ_GPIO20		41
-#define	IRQ_GPIO21		42
-#define	IRQ_GPIO22		43
-#define	IRQ_GPIO23		44
-#define	IRQ_GPIO24		45
-#define	IRQ_GPIO25		46
-#define	IRQ_GPIO26		47
-#define	IRQ_GPIO27		48
+#define	IRQ_GPIO11		33
+#define	IRQ_GPIO12		34
+#define	IRQ_GPIO13		35
+#define	IRQ_GPIO14		36
+#define	IRQ_GPIO15		37
+#define	IRQ_GPIO16		38
+#define	IRQ_GPIO17		39
+#define	IRQ_GPIO18		40
+#define	IRQ_GPIO19		41
+#define	IRQ_GPIO20		42
+#define	IRQ_GPIO21		43
+#define	IRQ_GPIO22		44
+#define	IRQ_GPIO23		45
+#define	IRQ_GPIO24		46
+#define	IRQ_GPIO25		47
+#define	IRQ_GPIO26		48
+#define	IRQ_GPIO27		49
 
 
 /*
 /*
  * The next 16 interrupts are for board specific purposes.  Since
  * The next 16 interrupts are for board specific purposes.  Since
@@ -65,8 +65,8 @@
  * these.  If you need more, increase IRQ_BOARD_END, but keep it
  * these.  If you need more, increase IRQ_BOARD_END, but keep it
  * within sensible limits.  IRQs 49 to 64 are available.
  * within sensible limits.  IRQs 49 to 64 are available.
  */
  */
-#define IRQ_BOARD_START		49
-#define IRQ_BOARD_END		65
+#define IRQ_BOARD_START		50
+#define IRQ_BOARD_END		66
 
 
 /*
 /*
  * Figure out the MAX IRQ number.
  * Figure out the MAX IRQ number.

+ 130 - 99
arch/arm/mach-sa1100/irq.c

@@ -14,16 +14,72 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/ioport.h>
 #include <linux/ioport.h>
 #include <linux/syscore_ops.h>
 #include <linux/syscore_ops.h>
 
 
 #include <mach/hardware.h>
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/irqs.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/irq.h>
+#include <asm/exception.h>
 
 
 #include "generic.h"
 #include "generic.h"
 
 
 
 
+/*
+ * We don't need to ACK IRQs on the SA1100 unless they're GPIOs
+ * this is for internal IRQs i.e. from IRQ LCD to RTCAlrm.
+ */
+static void sa1100_mask_irq(struct irq_data *d)
+{
+	ICMR &= ~BIT(d->hwirq);
+}
+
+static void sa1100_unmask_irq(struct irq_data *d)
+{
+	ICMR |= BIT(d->hwirq);
+}
+
+/*
+ * Apart form GPIOs, only the RTC alarm can be a wakeup event.
+ */
+static int sa1100_set_wake(struct irq_data *d, unsigned int on)
+{
+	if (BIT(d->hwirq) == IC_RTCAlrm) {
+		if (on)
+			PWER |= PWER_RTC;
+		else
+			PWER &= ~PWER_RTC;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static struct irq_chip sa1100_normal_chip = {
+	.name		= "SC",
+	.irq_ack	= sa1100_mask_irq,
+	.irq_mask	= sa1100_mask_irq,
+	.irq_unmask	= sa1100_unmask_irq,
+	.irq_set_wake	= sa1100_set_wake,
+};
+
+static int sa1100_normal_irqdomain_map(struct irq_domain *d,
+		unsigned int irq, irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &sa1100_normal_chip,
+				 handle_level_irq);
+	set_irq_flags(irq, IRQF_VALID);
+
+	return 0;
+}
+
+static struct irq_domain_ops sa1100_normal_irqdomain_ops = {
+	.map = sa1100_normal_irqdomain_map,
+	.xlate = irq_domain_xlate_onetwocell,
+};
+
+static struct irq_domain *sa1100_normal_irqdomain;
+
 /*
 /*
  * SA1100 GPIO edge detection for IRQs:
  * SA1100 GPIO edge detection for IRQs:
  * IRQs are generated on Falling-Edge, Rising-Edge, or both.
  * IRQs are generated on Falling-Edge, Rising-Edge, or both.
@@ -33,20 +89,11 @@ static int GPIO_IRQ_rising_edge;
 static int GPIO_IRQ_falling_edge;
 static int GPIO_IRQ_falling_edge;
 static int GPIO_IRQ_mask = (1 << 11) - 1;
 static int GPIO_IRQ_mask = (1 << 11) - 1;
 
 
-/*
- * To get the GPIO number from an IRQ number
- */
-#define GPIO_11_27_IRQ(i)	((i) - 21)
-#define GPIO11_27_MASK(irq)	(1 << GPIO_11_27_IRQ(irq))
-
 static int sa1100_gpio_type(struct irq_data *d, unsigned int type)
 static int sa1100_gpio_type(struct irq_data *d, unsigned int type)
 {
 {
 	unsigned int mask;
 	unsigned int mask;
 
 
-	if (d->irq <= 10)
-		mask = 1 << d->irq;
-	else
-		mask = GPIO11_27_MASK(d->irq);
+	mask = BIT(d->hwirq);
 
 
 	if (type == IRQ_TYPE_PROBE) {
 	if (type == IRQ_TYPE_PROBE) {
 		if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask)
 		if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask)
@@ -70,41 +117,51 @@ static int sa1100_gpio_type(struct irq_data *d, unsigned int type)
 }
 }
 
 
 /*
 /*
- * GPIO IRQs must be acknowledged.  This is for IRQs from 0 to 10.
+ * GPIO IRQs must be acknowledged.
  */
  */
-static void sa1100_low_gpio_ack(struct irq_data *d)
-{
-	GEDR = (1 << d->irq);
-}
-
-static void sa1100_low_gpio_mask(struct irq_data *d)
-{
-	ICMR &= ~(1 << d->irq);
-}
-
-static void sa1100_low_gpio_unmask(struct irq_data *d)
+static void sa1100_gpio_ack(struct irq_data *d)
 {
 {
-	ICMR |= 1 << d->irq;
+	GEDR = BIT(d->hwirq);
 }
 }
 
 
-static int sa1100_low_gpio_wake(struct irq_data *d, unsigned int on)
+static int sa1100_gpio_wake(struct irq_data *d, unsigned int on)
 {
 {
 	if (on)
 	if (on)
-		PWER |= 1 << d->irq;
+		PWER |= BIT(d->hwirq);
 	else
 	else
-		PWER &= ~(1 << d->irq);
+		PWER &= ~BIT(d->hwirq);
 	return 0;
 	return 0;
 }
 }
 
 
+/*
+ * This is for IRQs from 0 to 10.
+ */
 static struct irq_chip sa1100_low_gpio_chip = {
 static struct irq_chip sa1100_low_gpio_chip = {
 	.name		= "GPIO-l",
 	.name		= "GPIO-l",
-	.irq_ack	= sa1100_low_gpio_ack,
-	.irq_mask	= sa1100_low_gpio_mask,
-	.irq_unmask	= sa1100_low_gpio_unmask,
+	.irq_ack	= sa1100_gpio_ack,
+	.irq_mask	= sa1100_mask_irq,
+	.irq_unmask	= sa1100_unmask_irq,
 	.irq_set_type	= sa1100_gpio_type,
 	.irq_set_type	= sa1100_gpio_type,
-	.irq_set_wake	= sa1100_low_gpio_wake,
+	.irq_set_wake	= sa1100_gpio_wake,
+};
+
+static int sa1100_low_gpio_irqdomain_map(struct irq_domain *d,
+		unsigned int irq, irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &sa1100_low_gpio_chip,
+				 handle_edge_irq);
+	set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+
+	return 0;
+}
+
+static struct irq_domain_ops sa1100_low_gpio_irqdomain_ops = {
+	.map = sa1100_low_gpio_irqdomain_map,
+	.xlate = irq_domain_xlate_onetwocell,
 };
 };
 
 
+static struct irq_domain *sa1100_low_gpio_irqdomain;
+
 /*
 /*
  * IRQ11 (GPIO11 through 27) handler.  We enter here with the
  * IRQ11 (GPIO11 through 27) handler.  We enter here with the
  * irq_controller_lock held, and IRQs disabled.  Decode the IRQ
  * irq_controller_lock held, and IRQs disabled.  Decode the IRQ
@@ -141,16 +198,9 @@ sa1100_high_gpio_handler(unsigned int irq, struct irq_desc *desc)
  * In addition, the IRQs are all collected up into one bit in the
  * In addition, the IRQs are all collected up into one bit in the
  * interrupt controller registers.
  * interrupt controller registers.
  */
  */
-static void sa1100_high_gpio_ack(struct irq_data *d)
-{
-	unsigned int mask = GPIO11_27_MASK(d->irq);
-
-	GEDR = mask;
-}
-
 static void sa1100_high_gpio_mask(struct irq_data *d)
 static void sa1100_high_gpio_mask(struct irq_data *d)
 {
 {
-	unsigned int mask = GPIO11_27_MASK(d->irq);
+	unsigned int mask = BIT(d->hwirq);
 
 
 	GPIO_IRQ_mask &= ~mask;
 	GPIO_IRQ_mask &= ~mask;
 
 
@@ -160,7 +210,7 @@ static void sa1100_high_gpio_mask(struct irq_data *d)
 
 
 static void sa1100_high_gpio_unmask(struct irq_data *d)
 static void sa1100_high_gpio_unmask(struct irq_data *d)
 {
 {
-	unsigned int mask = GPIO11_27_MASK(d->irq);
+	unsigned int mask = BIT(d->hwirq);
 
 
 	GPIO_IRQ_mask |= mask;
 	GPIO_IRQ_mask |= mask;
 
 
@@ -168,61 +218,32 @@ static void sa1100_high_gpio_unmask(struct irq_data *d)
 	GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
 	GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
 }
 }
 
 
-static int sa1100_high_gpio_wake(struct irq_data *d, unsigned int on)
-{
-	if (on)
-		PWER |= GPIO11_27_MASK(d->irq);
-	else
-		PWER &= ~GPIO11_27_MASK(d->irq);
-	return 0;
-}
-
 static struct irq_chip sa1100_high_gpio_chip = {
 static struct irq_chip sa1100_high_gpio_chip = {
 	.name		= "GPIO-h",
 	.name		= "GPIO-h",
-	.irq_ack	= sa1100_high_gpio_ack,
+	.irq_ack	= sa1100_gpio_ack,
 	.irq_mask	= sa1100_high_gpio_mask,
 	.irq_mask	= sa1100_high_gpio_mask,
 	.irq_unmask	= sa1100_high_gpio_unmask,
 	.irq_unmask	= sa1100_high_gpio_unmask,
 	.irq_set_type	= sa1100_gpio_type,
 	.irq_set_type	= sa1100_gpio_type,
-	.irq_set_wake	= sa1100_high_gpio_wake,
+	.irq_set_wake	= sa1100_gpio_wake,
 };
 };
 
 
-/*
- * We don't need to ACK IRQs on the SA1100 unless they're GPIOs
- * this is for internal IRQs i.e. from 11 to 31.
- */
-static void sa1100_mask_irq(struct irq_data *d)
-{
-	ICMR &= ~(1 << d->irq);
-}
-
-static void sa1100_unmask_irq(struct irq_data *d)
+static int sa1100_high_gpio_irqdomain_map(struct irq_domain *d,
+		unsigned int irq, irq_hw_number_t hwirq)
 {
 {
-	ICMR |= (1 << d->irq);
-}
+	irq_set_chip_and_handler(irq, &sa1100_high_gpio_chip,
+				 handle_edge_irq);
+	set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 
 
-/*
- * Apart form GPIOs, only the RTC alarm can be a wakeup event.
- */
-static int sa1100_set_wake(struct irq_data *d, unsigned int on)
-{
-	if (d->irq == IRQ_RTCAlrm) {
-		if (on)
-			PWER |= PWER_RTC;
-		else
-			PWER &= ~PWER_RTC;
-		return 0;
-	}
-	return -EINVAL;
+	return 0;
 }
 }
 
 
-static struct irq_chip sa1100_normal_chip = {
-	.name		= "SC",
-	.irq_ack	= sa1100_mask_irq,
-	.irq_mask	= sa1100_mask_irq,
-	.irq_unmask	= sa1100_unmask_irq,
-	.irq_set_wake	= sa1100_set_wake,
+static struct irq_domain_ops sa1100_high_gpio_irqdomain_ops = {
+	.map = sa1100_high_gpio_irqdomain_map,
+	.xlate = irq_domain_xlate_onetwocell,
 };
 };
 
 
+static struct irq_domain *sa1100_high_gpio_irqdomain;
+
 static struct resource irq_resource =
 static struct resource irq_resource =
 	DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs");
 	DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs");
 
 
@@ -291,10 +312,25 @@ static int __init sa1100irq_init_devicefs(void)
 
 
 device_initcall(sa1100irq_init_devicefs);
 device_initcall(sa1100irq_init_devicefs);
 
 
-void __init sa1100_init_irq(void)
+static asmlinkage void __exception_irq_entry
+sa1100_handle_irq(struct pt_regs *regs)
 {
 {
-	unsigned int irq;
+	uint32_t icip, icmr, mask;
+
+	do {
+		icip = (ICIP);
+		icmr = (ICMR);
+		mask = icip & icmr;
+
+		if (mask == 0)
+			break;
+
+		handle_IRQ(ffs(mask) - 1 + IRQ_GPIO0, regs);
+	} while (1);
+}
 
 
+void __init sa1100_init_irq(void)
+{
 	request_resource(&iomem_resource, &irq_resource);
 	request_resource(&iomem_resource, &irq_resource);
 
 
 	/* disable all IRQs */
 	/* disable all IRQs */
@@ -314,29 +350,24 @@ void __init sa1100_init_irq(void)
 	 */
 	 */
 	ICCR = 1;
 	ICCR = 1;
 
 
-	for (irq = 0; irq <= 10; irq++) {
-		irq_set_chip_and_handler(irq, &sa1100_low_gpio_chip,
-					 handle_edge_irq);
-		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-	}
+	sa1100_low_gpio_irqdomain = irq_domain_add_legacy(NULL,
+			11, IRQ_GPIO0, 0,
+			&sa1100_low_gpio_irqdomain_ops, NULL);
 
 
-	for (irq = 12; irq <= 31; irq++) {
-		irq_set_chip_and_handler(irq, &sa1100_normal_chip,
-					 handle_level_irq);
-		set_irq_flags(irq, IRQF_VALID);
-	}
+	sa1100_normal_irqdomain = irq_domain_add_legacy(NULL,
+			21, IRQ_GPIO11_27, 11,
+			&sa1100_normal_irqdomain_ops, NULL);
 
 
-	for (irq = 32; irq <= 48; irq++) {
-		irq_set_chip_and_handler(irq, &sa1100_high_gpio_chip,
-					 handle_edge_irq);
-		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-	}
+	sa1100_high_gpio_irqdomain = irq_domain_add_legacy(NULL,
+			17, IRQ_GPIO11, 11,
+			&sa1100_high_gpio_irqdomain_ops, NULL);
 
 
 	/*
 	/*
 	 * Install handler for GPIO 11-27 edge detect interrupts
 	 * Install handler for GPIO 11-27 edge detect interrupts
 	 */
 	 */
-	irq_set_chip(IRQ_GPIO11_27, &sa1100_normal_chip);
 	irq_set_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler);
 	irq_set_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler);
 
 
+	set_handle_irq(sa1100_handle_irq);
+
 	sa1100_init_gpio();
 	sa1100_init_gpio();
 }
 }

+ 21 - 0
arch/arm/mm/Kconfig

@@ -1009,3 +1009,24 @@ config ARCH_SUPPORTS_BIG_ENDIAN
 	help
 	help
 	  This option specifies the architecture can support big endian
 	  This option specifies the architecture can support big endian
 	  operation.
 	  operation.
+
+config ARM_KERNMEM_PERMS
+	bool "Restrict kernel memory permissions"
+	help
+	  If this is set, kernel memory other than kernel text (and rodata)
+	  will be made non-executable. The tradeoff is that each region is
+	  padded to section-size (1MiB) boundaries (because their permissions
+	  are different and splitting the 1M pages into 4K ones causes TLB
+	  performance problems), wasting memory.
+
+config DEBUG_RODATA
+	bool "Make kernel text and rodata read-only"
+	depends on ARM_KERNMEM_PERMS
+	default y
+	help
+	  If this is set, kernel text and rodata will be made read-only. This
+	  is to help catch accidental or malicious attempts to change the
+	  kernel's executable code. Additionally splits rodata from kernel
+	  text so it can be made explicitly non-executable. This creates
+	  another section-size padded region, so it can waste more memory
+	  space while gaining the read-only protections.

+ 1 - 1
arch/arm/mm/Makefile

@@ -6,7 +6,7 @@ obj-y				:= dma-mapping.o extable.o fault.o init.o \
 				   iomap.o
 				   iomap.o
 
 
 obj-$(CONFIG_MMU)		+= fault-armv.o flush.o idmap.o ioremap.o \
 obj-$(CONFIG_MMU)		+= fault-armv.o flush.o idmap.o ioremap.o \
-				   mmap.o pgd.o mmu.o
+				   mmap.o pgd.o mmu.o pageattr.o
 
 
 ifneq ($(CONFIG_MMU),y)
 ifneq ($(CONFIG_MMU),y)
 obj-y				+= nommu.o
 obj-y				+= nommu.o

+ 5 - 5
arch/arm/mm/alignment.c

@@ -113,7 +113,7 @@ static int safe_usermode(int new_usermode, bool warn)
 		new_usermode |= UM_FIXUP;
 		new_usermode |= UM_FIXUP;
 
 
 		if (warn)
 		if (warn)
-			printk(KERN_WARNING "alignment: ignoring faults is unsafe on this CPU.  Defaulting to fixup mode.\n");
+			pr_warn("alignment: ignoring faults is unsafe on this CPU.  Defaulting to fixup mode.\n");
 	}
 	}
 
 
 	return new_usermode;
 	return new_usermode;
@@ -523,7 +523,7 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg
 	 * processor for us.
 	 * processor for us.
 	 */
 	 */
 	if (addr != eaddr) {
 	if (addr != eaddr) {
-		printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, "
+		pr_err("LDMSTM: PC = %08lx, instr = %08lx, "
 			"addr = %08lx, eaddr = %08lx\n",
 			"addr = %08lx, eaddr = %08lx\n",
 			 instruction_pointer(regs), instr, addr, eaddr);
 			 instruction_pointer(regs), instr, addr, eaddr);
 		show_regs(regs);
 		show_regs(regs);
@@ -567,7 +567,7 @@ fault:
 	return TYPE_FAULT;
 	return TYPE_FAULT;
 
 
 bad:
 bad:
-	printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n");
+	pr_err("Alignment trap: not handling ldm with s-bit set\n");
 	return TYPE_ERROR;
 	return TYPE_ERROR;
 }
 }
 
 
@@ -899,13 +899,13 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	return 0;
 	return 0;
 
 
  swp:
  swp:
-	printk(KERN_ERR "Alignment trap: not handling swp instruction\n");
+	pr_err("Alignment trap: not handling swp instruction\n");
 
 
  bad:
  bad:
 	/*
 	/*
 	 * Oops, we didn't handle the instruction.
 	 * Oops, we didn't handle the instruction.
 	 */
 	 */
-	printk(KERN_ERR "Alignment trap: not handling instruction "
+	pr_err("Alignment trap: not handling instruction "
 		"%0*lx at [<%08lx>]\n",
 		"%0*lx at [<%08lx>]\n",
 		isize << 1,
 		isize << 1,
 		isize == 2 ? tinstr : instr, instrptr);
 		isize == 2 ? tinstr : instr, instrptr);

+ 3 - 3
arch/arm/mm/cache-feroceon-l2.c

@@ -313,7 +313,7 @@ static void __init disable_l2_prefetch(void)
 	 */
 	 */
 	u = read_extra_features();
 	u = read_extra_features();
 	if (!(u & 0x01000000)) {
 	if (!(u & 0x01000000)) {
-		printk(KERN_INFO "Feroceon L2: Disabling L2 prefetch.\n");
+		pr_info("Feroceon L2: Disabling L2 prefetch.\n");
 		write_extra_features(u | 0x01000000);
 		write_extra_features(u | 0x01000000);
 	}
 	}
 }
 }
@@ -326,7 +326,7 @@ static void __init enable_l2(void)
 	if (!(u & 0x00400000)) {
 	if (!(u & 0x00400000)) {
 		int i, d;
 		int i, d;
 
 
-		printk(KERN_INFO "Feroceon L2: Enabling L2\n");
+		pr_info("Feroceon L2: Enabling L2\n");
 
 
 		d = flush_and_disable_dcache();
 		d = flush_and_disable_dcache();
 		i = invalidate_and_disable_icache();
 		i = invalidate_and_disable_icache();
@@ -353,7 +353,7 @@ void __init feroceon_l2_init(int __l2_wt_override)
 
 
 	enable_l2();
 	enable_l2();
 
 
-	printk(KERN_INFO "Feroceon L2: Cache support initialised%s.\n",
+	pr_info("Feroceon L2: Cache support initialised%s.\n",
 			 l2_wt_override ? ", in WT override mode" : "");
 			 l2_wt_override ? ", in WT override mode" : "");
 }
 }
 #ifdef CONFIG_OF
 #ifdef CONFIG_OF

+ 6 - 6
arch/arm/mm/cache-tauros2.c

@@ -185,7 +185,7 @@ static void enable_extra_feature(unsigned int features)
 		u &= ~0x01000000;
 		u &= ~0x01000000;
 	else
 	else
 		u |= 0x01000000;
 		u |= 0x01000000;
-	printk(KERN_INFO "Tauros2: %s L2 prefetch.\n",
+	pr_info("Tauros2: %s L2 prefetch.\n",
 			(features & CACHE_TAUROS2_PREFETCH_ON)
 			(features & CACHE_TAUROS2_PREFETCH_ON)
 			? "Enabling" : "Disabling");
 			? "Enabling" : "Disabling");
 
 
@@ -193,7 +193,7 @@ static void enable_extra_feature(unsigned int features)
 		u |= 0x00100000;
 		u |= 0x00100000;
 	else
 	else
 		u &= ~0x00100000;
 		u &= ~0x00100000;
-	printk(KERN_INFO "Tauros2: %s line fill burt8.\n",
+	pr_info("Tauros2: %s line fill burt8.\n",
 			(features & CACHE_TAUROS2_LINEFILL_BURST8)
 			(features & CACHE_TAUROS2_LINEFILL_BURST8)
 			? "Enabling" : "Disabling");
 			? "Enabling" : "Disabling");
 
 
@@ -216,7 +216,7 @@ static void __init tauros2_internal_init(unsigned int features)
 		 */
 		 */
 		feat = read_extra_features();
 		feat = read_extra_features();
 		if (!(feat & 0x00400000)) {
 		if (!(feat & 0x00400000)) {
-			printk(KERN_INFO "Tauros2: Enabling L2 cache.\n");
+			pr_info("Tauros2: Enabling L2 cache.\n");
 			write_extra_features(feat | 0x00400000);
 			write_extra_features(feat | 0x00400000);
 		}
 		}
 
 
@@ -253,7 +253,7 @@ static void __init tauros2_internal_init(unsigned int features)
 		 */
 		 */
 		actlr = read_actlr();
 		actlr = read_actlr();
 		if (!(actlr & 0x00000002)) {
 		if (!(actlr & 0x00000002)) {
-			printk(KERN_INFO "Tauros2: Enabling L2 cache.\n");
+			pr_info("Tauros2: Enabling L2 cache.\n");
 			write_actlr(actlr | 0x00000002);
 			write_actlr(actlr | 0x00000002);
 		}
 		}
 
 
@@ -262,11 +262,11 @@ static void __init tauros2_internal_init(unsigned int features)
 #endif
 #endif
 
 
 	if (mode == NULL) {
 	if (mode == NULL) {
-		printk(KERN_CRIT "Tauros2: Unable to detect CPU mode.\n");
+		pr_crit("Tauros2: Unable to detect CPU mode.\n");
 		return;
 		return;
 	}
 	}
 
 
-	printk(KERN_INFO "Tauros2: L2 cache support initialised "
+	pr_info("Tauros2: L2 cache support initialised "
 			 "in %s mode.\n", mode);
 			 "in %s mode.\n", mode);
 }
 }
 
 

+ 34 - 24
arch/arm/mm/context.c

@@ -184,36 +184,46 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
 	u64 asid = atomic64_read(&mm->context.id);
 	u64 asid = atomic64_read(&mm->context.id);
 	u64 generation = atomic64_read(&asid_generation);
 	u64 generation = atomic64_read(&asid_generation);
 
 
-	if (asid != 0 && is_reserved_asid(asid)) {
+	if (asid != 0) {
 		/*
 		/*
-		 * Our current ASID was active during a rollover, we can
-		 * continue to use it and this was just a false alarm.
+		 * If our current ASID was active during a rollover, we
+		 * can continue to use it and this was just a false alarm.
 		 */
 		 */
-		asid = generation | (asid & ~ASID_MASK);
-	} else {
+		if (is_reserved_asid(asid))
+			return generation | (asid & ~ASID_MASK);
+
 		/*
 		/*
-		 * Allocate a free ASID. If we can't find one, take a
-		 * note of the currently active ASIDs and mark the TLBs
-		 * as requiring flushes. We always count from ASID #1,
-		 * as we reserve ASID #0 to switch via TTBR0 and to
-		 * avoid speculative page table walks from hitting in
-		 * any partial walk caches, which could be populated
-		 * from overlapping level-1 descriptors used to map both
-		 * the module area and the userspace stack.
+		 * We had a valid ASID in a previous life, so try to re-use
+		 * it if possible.,
 		 */
 		 */
-		asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, cur_idx);
-		if (asid == NUM_USER_ASIDS) {
-			generation = atomic64_add_return(ASID_FIRST_VERSION,
-							 &asid_generation);
-			flush_context(cpu);
-			asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, 1);
-		}
-		__set_bit(asid, asid_map);
-		cur_idx = asid;
-		asid |= generation;
-		cpumask_clear(mm_cpumask(mm));
+		asid &= ~ASID_MASK;
+		if (!__test_and_set_bit(asid, asid_map))
+			goto bump_gen;
 	}
 	}
 
 
+	/*
+	 * Allocate a free ASID. If we can't find one, take a note of the
+	 * currently active ASIDs and mark the TLBs as requiring flushes.
+	 * We always count from ASID #1, as we reserve ASID #0 to switch
+	 * via TTBR0 and to avoid speculative page table walks from hitting
+	 * in any partial walk caches, which could be populated from
+	 * overlapping level-1 descriptors used to map both the module
+	 * area and the userspace stack.
+	 */
+	asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, cur_idx);
+	if (asid == NUM_USER_ASIDS) {
+		generation = atomic64_add_return(ASID_FIRST_VERSION,
+						 &asid_generation);
+		flush_context(cpu);
+		asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, 1);
+	}
+
+	__set_bit(asid, asid_map);
+	cur_idx = asid;
+
+bump_gen:
+	asid |= generation;
+	cpumask_clear(mm_cpumask(mm));
 	return asid;
 	return asid;
 }
 }
 
 

+ 1 - 1
arch/arm/mm/copypage-v6.c

@@ -62,7 +62,7 @@ static void discard_old_kernel_data(void *kto)
 	__asm__("mcrr	p15, 0, %1, %0, c6	@ 0xec401f06"
 	__asm__("mcrr	p15, 0, %1, %0, c6	@ 0xec401f06"
 	   :
 	   :
 	   : "r" (kto),
 	   : "r" (kto),
-	     "r" ((unsigned long)kto + PAGE_SIZE - L1_CACHE_BYTES)
+	     "r" ((unsigned long)kto + PAGE_SIZE - 1)
 	   : "cc");
 	   : "cc");
 }
 }
 
 

+ 3 - 3
arch/arm/mm/fault-armv.c

@@ -235,7 +235,7 @@ void __init check_writebuffer_bugs(void)
 	const char *reason;
 	const char *reason;
 	unsigned long v = 1;
 	unsigned long v = 1;
 
 
-	printk(KERN_INFO "CPU: Testing write buffer coherency: ");
+	pr_info("CPU: Testing write buffer coherency: ");
 
 
 	page = alloc_page(GFP_KERNEL);
 	page = alloc_page(GFP_KERNEL);
 	if (page) {
 	if (page) {
@@ -261,9 +261,9 @@ void __init check_writebuffer_bugs(void)
 	}
 	}
 
 
 	if (v) {
 	if (v) {
-		printk("failed, %s\n", reason);
+		pr_cont("failed, %s\n", reason);
 		shared_pte_mask = L_PTE_MT_UNCACHED;
 		shared_pte_mask = L_PTE_MT_UNCACHED;
 	} else {
 	} else {
-		printk("ok\n");
+		pr_cont("ok\n");
 	}
 	}
 }
 }

+ 15 - 16
arch/arm/mm/fault.c

@@ -63,9 +63,9 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
 	if (!mm)
 	if (!mm)
 		mm = &init_mm;
 		mm = &init_mm;
 
 
-	printk(KERN_ALERT "pgd = %p\n", mm->pgd);
+	pr_alert("pgd = %p\n", mm->pgd);
 	pgd = pgd_offset(mm, addr);
 	pgd = pgd_offset(mm, addr);
-	printk(KERN_ALERT "[%08lx] *pgd=%08llx",
+	pr_alert("[%08lx] *pgd=%08llx",
 			addr, (long long)pgd_val(*pgd));
 			addr, (long long)pgd_val(*pgd));
 
 
 	do {
 	do {
@@ -77,31 +77,31 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
 			break;
 			break;
 
 
 		if (pgd_bad(*pgd)) {
 		if (pgd_bad(*pgd)) {
-			printk("(bad)");
+			pr_cont("(bad)");
 			break;
 			break;
 		}
 		}
 
 
 		pud = pud_offset(pgd, addr);
 		pud = pud_offset(pgd, addr);
 		if (PTRS_PER_PUD != 1)
 		if (PTRS_PER_PUD != 1)
-			printk(", *pud=%08llx", (long long)pud_val(*pud));
+			pr_cont(", *pud=%08llx", (long long)pud_val(*pud));
 
 
 		if (pud_none(*pud))
 		if (pud_none(*pud))
 			break;
 			break;
 
 
 		if (pud_bad(*pud)) {
 		if (pud_bad(*pud)) {
-			printk("(bad)");
+			pr_cont("(bad)");
 			break;
 			break;
 		}
 		}
 
 
 		pmd = pmd_offset(pud, addr);
 		pmd = pmd_offset(pud, addr);
 		if (PTRS_PER_PMD != 1)
 		if (PTRS_PER_PMD != 1)
-			printk(", *pmd=%08llx", (long long)pmd_val(*pmd));
+			pr_cont(", *pmd=%08llx", (long long)pmd_val(*pmd));
 
 
 		if (pmd_none(*pmd))
 		if (pmd_none(*pmd))
 			break;
 			break;
 
 
 		if (pmd_bad(*pmd)) {
 		if (pmd_bad(*pmd)) {
-			printk("(bad)");
+			pr_cont("(bad)");
 			break;
 			break;
 		}
 		}
 
 
@@ -110,15 +110,15 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
 			break;
 			break;
 
 
 		pte = pte_offset_map(pmd, addr);
 		pte = pte_offset_map(pmd, addr);
-		printk(", *pte=%08llx", (long long)pte_val(*pte));
+		pr_cont(", *pte=%08llx", (long long)pte_val(*pte));
 #ifndef CONFIG_ARM_LPAE
 #ifndef CONFIG_ARM_LPAE
-		printk(", *ppte=%08llx",
+		pr_cont(", *ppte=%08llx",
 		       (long long)pte_val(pte[PTE_HWTABLE_PTRS]));
 		       (long long)pte_val(pte[PTE_HWTABLE_PTRS]));
 #endif
 #endif
 		pte_unmap(pte);
 		pte_unmap(pte);
 	} while(0);
 	} while(0);
 
 
-	printk("\n");
+	pr_cont("\n");
 }
 }
 #else					/* CONFIG_MMU */
 #else					/* CONFIG_MMU */
 void show_pte(struct mm_struct *mm, unsigned long addr)
 void show_pte(struct mm_struct *mm, unsigned long addr)
@@ -142,10 +142,9 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
 	 * No handler, we'll have to terminate things with extreme prejudice.
 	 * No handler, we'll have to terminate things with extreme prejudice.
 	 */
 	 */
 	bust_spinlocks(1);
 	bust_spinlocks(1);
-	printk(KERN_ALERT
-		"Unable to handle kernel %s at virtual address %08lx\n",
-		(addr < PAGE_SIZE) ? "NULL pointer dereference" :
-		"paging request", addr);
+	pr_alert("Unable to handle kernel %s at virtual address %08lx\n",
+		 (addr < PAGE_SIZE) ? "NULL pointer dereference" :
+		 "paging request", addr);
 
 
 	show_pte(mm, addr);
 	show_pte(mm, addr);
 	die("Oops", regs, fsr);
 	die("Oops", regs, fsr);
@@ -551,7 +550,7 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
 	if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
 		return;
 		return;
 
 
-	printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
+	pr_alert("Unhandled fault: %s (0x%03x) at 0x%08lx\n",
 		inf->name, fsr, addr);
 		inf->name, fsr, addr);
 
 
 	info.si_signo = inf->sig;
 	info.si_signo = inf->sig;
@@ -583,7 +582,7 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
 	if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
 	if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
 		return;
 		return;
 
 
-	printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
+	pr_alert("Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
 		inf->name, ifsr, addr);
 		inf->name, ifsr, addr);
 
 
 	info.si_signo = inf->sig;
 	info.si_signo = inf->sig;

+ 1 - 1
arch/arm/mm/flush.c

@@ -33,7 +33,7 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
 	asm(	"mcrr	p15, 0, %1, %0, c14\n"
 	asm(	"mcrr	p15, 0, %1, %0, c14\n"
 	"	mcr	p15, 0, %2, c7, c10, 4"
 	"	mcr	p15, 0, %2, c7, c10, 4"
 	    :
 	    :
-	    : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES), "r" (zero)
+	    : "r" (to), "r" (to + PAGE_SIZE - 1), "r" (zero)
 	    : "cc");
 	    : "cc");
 }
 }
 
 

+ 8 - 7
arch/arm/mm/highmem.c

@@ -18,19 +18,20 @@
 #include <asm/tlbflush.h>
 #include <asm/tlbflush.h>
 #include "mm.h"
 #include "mm.h"
 
 
-pte_t *fixmap_page_table;
-
 static inline void set_fixmap_pte(int idx, pte_t pte)
 static inline void set_fixmap_pte(int idx, pte_t pte)
 {
 {
 	unsigned long vaddr = __fix_to_virt(idx);
 	unsigned long vaddr = __fix_to_virt(idx);
-	set_pte_ext(fixmap_page_table + idx, pte, 0);
+	pte_t *ptep = pte_offset_kernel(pmd_off_k(vaddr), vaddr);
+
+	set_pte_ext(ptep, pte, 0);
 	local_flush_tlb_kernel_page(vaddr);
 	local_flush_tlb_kernel_page(vaddr);
 }
 }
 
 
 static inline pte_t get_fixmap_pte(unsigned long vaddr)
 static inline pte_t get_fixmap_pte(unsigned long vaddr)
 {
 {
-	unsigned long idx = __virt_to_fix(vaddr);
-	return *(fixmap_page_table + idx);
+	pte_t *ptep = pte_offset_kernel(pmd_off_k(vaddr), vaddr);
+
+	return *ptep;
 }
 }
 
 
 void *kmap(struct page *page)
 void *kmap(struct page *page)
@@ -84,7 +85,7 @@ void *kmap_atomic(struct page *page)
 	 * With debugging enabled, kunmap_atomic forces that entry to 0.
 	 * With debugging enabled, kunmap_atomic forces that entry to 0.
 	 * Make sure it was indeed properly unmapped.
 	 * Make sure it was indeed properly unmapped.
 	 */
 	 */
-	BUG_ON(!pte_none(*(fixmap_page_table + idx)));
+	BUG_ON(!pte_none(get_fixmap_pte(vaddr)));
 #endif
 #endif
 	/*
 	/*
 	 * When debugging is off, kunmap_atomic leaves the previous mapping
 	 * When debugging is off, kunmap_atomic leaves the previous mapping
@@ -137,7 +138,7 @@ void *kmap_atomic_pfn(unsigned long pfn)
 	idx = type + KM_TYPE_NR * smp_processor_id();
 	idx = type + KM_TYPE_NR * smp_processor_id();
 	vaddr = __fix_to_virt(idx);
 	vaddr = __fix_to_virt(idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
 #ifdef CONFIG_DEBUG_HIGHMEM
-	BUG_ON(!pte_none(*(fixmap_page_table + idx)));
+	BUG_ON(!pte_none(get_fixmap_pte(vaddr)));
 #endif
 #endif
 	set_fixmap_pte(idx, pfn_pte(pfn, kmap_prot));
 	set_fixmap_pte(idx, pfn_pte(pfn, kmap_prot));
 
 

+ 149 - 4
arch/arm/mm/init.c

@@ -29,6 +29,7 @@
 #include <asm/prom.h>
 #include <asm/prom.h>
 #include <asm/sections.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/setup.h>
+#include <asm/system_info.h>
 #include <asm/tlb.h>
 #include <asm/tlb.h>
 #include <asm/fixmap.h>
 #include <asm/fixmap.h>
 
 
@@ -67,7 +68,7 @@ early_param("initrd", early_initrd);
 
 
 static int __init parse_tag_initrd(const struct tag *tag)
 static int __init parse_tag_initrd(const struct tag *tag)
 {
 {
-	printk(KERN_WARNING "ATAG_INITRD is deprecated; "
+	pr_warn("ATAG_INITRD is deprecated; "
 		"please update your bootloader.\n");
 		"please update your bootloader.\n");
 	phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
 	phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
 	phys_initrd_size = tag->u.initrd.size;
 	phys_initrd_size = tag->u.initrd.size;
@@ -544,7 +545,7 @@ void __init mem_init(void)
 #define MLM(b, t) b, t, ((t) - (b)) >> 20
 #define MLM(b, t) b, t, ((t) - (b)) >> 20
 #define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
 #define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
 
 
-	printk(KERN_NOTICE "Virtual kernel memory layout:\n"
+	pr_notice("Virtual kernel memory layout:\n"
 			"    vector  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 			"    vector  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 #ifdef CONFIG_HAVE_TCM
 #ifdef CONFIG_HAVE_TCM
 			"    DTCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 			"    DTCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
@@ -570,7 +571,7 @@ void __init mem_init(void)
 			MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
 			MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
 			MLK(ITCM_OFFSET, (unsigned long) itcm_end),
 			MLK(ITCM_OFFSET, (unsigned long) itcm_end),
 #endif
 #endif
-			MLK(FIXADDR_START, FIXADDR_TOP),
+			MLK(FIXADDR_START, FIXADDR_END),
 			MLM(VMALLOC_START, VMALLOC_END),
 			MLM(VMALLOC_START, VMALLOC_END),
 			MLM(PAGE_OFFSET, (unsigned long)high_memory),
 			MLM(PAGE_OFFSET, (unsigned long)high_memory),
 #ifdef CONFIG_HIGHMEM
 #ifdef CONFIG_HIGHMEM
@@ -615,7 +616,145 @@ void __init mem_init(void)
 	}
 	}
 }
 }
 
 
-void free_initmem(void)
+#ifdef CONFIG_ARM_KERNMEM_PERMS
+struct section_perm {
+	unsigned long start;
+	unsigned long end;
+	pmdval_t mask;
+	pmdval_t prot;
+	pmdval_t clear;
+};
+
+static struct section_perm nx_perms[] = {
+	/* Make pages tables, etc before _stext RW (set NX). */
+	{
+		.start	= PAGE_OFFSET,
+		.end	= (unsigned long)_stext,
+		.mask	= ~PMD_SECT_XN,
+		.prot	= PMD_SECT_XN,
+	},
+	/* Make init RW (set NX). */
+	{
+		.start	= (unsigned long)__init_begin,
+		.end	= (unsigned long)_sdata,
+		.mask	= ~PMD_SECT_XN,
+		.prot	= PMD_SECT_XN,
+	},
+#ifdef CONFIG_DEBUG_RODATA
+	/* Make rodata NX (set RO in ro_perms below). */
+	{
+		.start  = (unsigned long)__start_rodata,
+		.end    = (unsigned long)__init_begin,
+		.mask   = ~PMD_SECT_XN,
+		.prot   = PMD_SECT_XN,
+	},
+#endif
+};
+
+#ifdef CONFIG_DEBUG_RODATA
+static struct section_perm ro_perms[] = {
+	/* Make kernel code and rodata RX (set RO). */
+	{
+		.start  = (unsigned long)_stext,
+		.end    = (unsigned long)__init_begin,
+#ifdef CONFIG_ARM_LPAE
+		.mask   = ~PMD_SECT_RDONLY,
+		.prot   = PMD_SECT_RDONLY,
+#else
+		.mask   = ~(PMD_SECT_APX | PMD_SECT_AP_WRITE),
+		.prot   = PMD_SECT_APX | PMD_SECT_AP_WRITE,
+		.clear  = PMD_SECT_AP_WRITE,
+#endif
+	},
+};
+#endif
+
+/*
+ * Updates section permissions only for the current mm (sections are
+ * copied into each mm). During startup, this is the init_mm. Is only
+ * safe to be called with preemption disabled, as under stop_machine().
+ */
+static inline void section_update(unsigned long addr, pmdval_t mask,
+				  pmdval_t prot)
+{
+	struct mm_struct *mm;
+	pmd_t *pmd;
+
+	mm = current->active_mm;
+	pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), addr), addr);
+
+#ifdef CONFIG_ARM_LPAE
+	pmd[0] = __pmd((pmd_val(pmd[0]) & mask) | prot);
+#else
+	if (addr & SECTION_SIZE)
+		pmd[1] = __pmd((pmd_val(pmd[1]) & mask) | prot);
+	else
+		pmd[0] = __pmd((pmd_val(pmd[0]) & mask) | prot);
+#endif
+	flush_pmd_entry(pmd);
+	local_flush_tlb_kernel_range(addr, addr + SECTION_SIZE);
+}
+
+/* Make sure extended page tables are in use. */
+static inline bool arch_has_strict_perms(void)
+{
+	if (cpu_architecture() < CPU_ARCH_ARMv6)
+		return false;
+
+	return !!(get_cr() & CR_XP);
+}
+
+#define set_section_perms(perms, field)	{				\
+	size_t i;							\
+	unsigned long addr;						\
+									\
+	if (!arch_has_strict_perms())					\
+		return;							\
+									\
+	for (i = 0; i < ARRAY_SIZE(perms); i++) {			\
+		if (!IS_ALIGNED(perms[i].start, SECTION_SIZE) ||	\
+		    !IS_ALIGNED(perms[i].end, SECTION_SIZE)) {		\
+			pr_err("BUG: section %lx-%lx not aligned to %lx\n", \
+				perms[i].start, perms[i].end,		\
+				SECTION_SIZE);				\
+			continue;					\
+		}							\
+									\
+		for (addr = perms[i].start;				\
+		     addr < perms[i].end;				\
+		     addr += SECTION_SIZE)				\
+			section_update(addr, perms[i].mask,		\
+				       perms[i].field);			\
+	}								\
+}
+
+static inline void fix_kernmem_perms(void)
+{
+	set_section_perms(nx_perms, prot);
+}
+
+#ifdef CONFIG_DEBUG_RODATA
+void mark_rodata_ro(void)
+{
+	set_section_perms(ro_perms, prot);
+}
+
+void set_kernel_text_rw(void)
+{
+	set_section_perms(ro_perms, clear);
+}
+
+void set_kernel_text_ro(void)
+{
+	set_section_perms(ro_perms, prot);
+}
+#endif /* CONFIG_DEBUG_RODATA */
+
+#else
+static inline void fix_kernmem_perms(void) { }
+#endif /* CONFIG_ARM_KERNMEM_PERMS */
+
+void free_tcmmem(void)
 {
 {
 #ifdef CONFIG_HAVE_TCM
 #ifdef CONFIG_HAVE_TCM
 	extern char __tcm_start, __tcm_end;
 	extern char __tcm_start, __tcm_end;
@@ -623,6 +762,12 @@ void free_initmem(void)
 	poison_init_mem(&__tcm_start, &__tcm_end - &__tcm_start);
 	poison_init_mem(&__tcm_start, &__tcm_end - &__tcm_start);
 	free_reserved_area(&__tcm_start, &__tcm_end, -1, "TCM link");
 	free_reserved_area(&__tcm_start, &__tcm_end, -1, "TCM link");
 #endif
 #endif
+}
+
+void free_initmem(void)
+{
+	fix_kernmem_perms();
+	free_tcmmem();
 
 
 	poison_init_mem(__init_begin, __init_end - __init_begin);
 	poison_init_mem(__init_begin, __init_end - __init_begin);
 	if (!machine_is_integrator() && !machine_is_cintegrator())
 	if (!machine_is_integrator() && !machine_is_cintegrator())

+ 64 - 63
arch/arm/mm/mmu.c

@@ -22,6 +22,7 @@
 #include <asm/cputype.h>
 #include <asm/cputype.h>
 #include <asm/sections.h>
 #include <asm/sections.h>
 #include <asm/cachetype.h>
 #include <asm/cachetype.h>
+#include <asm/fixmap.h>
 #include <asm/sections.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/setup.h>
 #include <asm/smp_plat.h>
 #include <asm/smp_plat.h>
@@ -52,6 +53,8 @@ EXPORT_SYMBOL(empty_zero_page);
  */
  */
 pmd_t *top_pmd;
 pmd_t *top_pmd;
 
 
+pmdval_t user_pmd_table = _PAGE_USER_TABLE;
+
 #define CPOLICY_UNCACHED	0
 #define CPOLICY_UNCACHED	0
 #define CPOLICY_BUFFERED	1
 #define CPOLICY_BUFFERED	1
 #define CPOLICY_WRITETHROUGH	2
 #define CPOLICY_WRITETHROUGH	2
@@ -192,7 +195,7 @@ early_param("cachepolicy", early_cachepolicy);
 static int __init early_nocache(char *__unused)
 static int __init early_nocache(char *__unused)
 {
 {
 	char *p = "buffered";
 	char *p = "buffered";
-	printk(KERN_WARNING "nocache is deprecated; use cachepolicy=%s\n", p);
+	pr_warn("nocache is deprecated; use cachepolicy=%s\n", p);
 	early_cachepolicy(p);
 	early_cachepolicy(p);
 	return 0;
 	return 0;
 }
 }
@@ -201,7 +204,7 @@ early_param("nocache", early_nocache);
 static int __init early_nowrite(char *__unused)
 static int __init early_nowrite(char *__unused)
 {
 {
 	char *p = "uncached";
 	char *p = "uncached";
-	printk(KERN_WARNING "nowb is deprecated; use cachepolicy=%s\n", p);
+	pr_warn("nowb is deprecated; use cachepolicy=%s\n", p);
 	early_cachepolicy(p);
 	early_cachepolicy(p);
 	return 0;
 	return 0;
 }
 }
@@ -354,43 +357,28 @@ const struct mem_type *get_mem_type(unsigned int type)
 }
 }
 EXPORT_SYMBOL(get_mem_type);
 EXPORT_SYMBOL(get_mem_type);
 
 
-#define PTE_SET_FN(_name, pteop) \
-static int pte_set_##_name(pte_t *ptep, pgtable_t token, unsigned long addr, \
-			void *data) \
-{ \
-	pte_t pte = pteop(*ptep); \
-\
-	set_pte_ext(ptep, pte, 0); \
-	return 0; \
-} \
-
-#define SET_MEMORY_FN(_name, callback) \
-int set_memory_##_name(unsigned long addr, int numpages) \
-{ \
-	unsigned long start = addr; \
-	unsigned long size = PAGE_SIZE*numpages; \
-	unsigned end = start + size; \
-\
-	if (start < MODULES_VADDR || start >= MODULES_END) \
-		return -EINVAL;\
-\
-	if (end < MODULES_VADDR || end >= MODULES_END) \
-		return -EINVAL; \
-\
-	apply_to_page_range(&init_mm, start, size, callback, NULL); \
-	flush_tlb_kernel_range(start, end); \
-	return 0;\
-}
+/*
+ * To avoid TLB flush broadcasts, this uses local_flush_tlb_kernel_range().
+ * As a result, this can only be called with preemption disabled, as under
+ * stop_machine().
+ */
+void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
+{
+	unsigned long vaddr = __fix_to_virt(idx);
+	pte_t *pte = pte_offset_kernel(pmd_off_k(vaddr), vaddr);
 
 
-PTE_SET_FN(ro, pte_wrprotect)
-PTE_SET_FN(rw, pte_mkwrite)
-PTE_SET_FN(x, pte_mkexec)
-PTE_SET_FN(nx, pte_mknexec)
+	/* Make sure fixmap region does not exceed available allocation. */
+	BUILD_BUG_ON(FIXADDR_START + (__end_of_fixed_addresses * PAGE_SIZE) >
+		     FIXADDR_END);
+	BUG_ON(idx >= __end_of_fixed_addresses);
 
 
-SET_MEMORY_FN(ro, pte_set_ro)
-SET_MEMORY_FN(rw, pte_set_rw)
-SET_MEMORY_FN(x, pte_set_x)
-SET_MEMORY_FN(nx, pte_set_nx)
+	if (pgprot_val(prot))
+		set_pte_at(NULL, vaddr, pte,
+			pfn_pte(phys >> PAGE_SHIFT, prot));
+	else
+		pte_clear(NULL, vaddr, pte);
+	local_flush_tlb_kernel_range(vaddr, vaddr + PAGE_SIZE);
+}
 
 
 /*
 /*
  * Adjust the PMD section entries according to the CPU in use.
  * Adjust the PMD section entries according to the CPU in use.
@@ -528,14 +516,23 @@ static void __init build_mem_type_table(void)
 	hyp_device_pgprot = mem_types[MT_DEVICE].prot_pte;
 	hyp_device_pgprot = mem_types[MT_DEVICE].prot_pte;
 	s2_device_pgprot = mem_types[MT_DEVICE].prot_pte_s2;
 	s2_device_pgprot = mem_types[MT_DEVICE].prot_pte_s2;
 
 
+#ifndef CONFIG_ARM_LPAE
 	/*
 	/*
 	 * We don't use domains on ARMv6 (since this causes problems with
 	 * We don't use domains on ARMv6 (since this causes problems with
 	 * v6/v7 kernels), so we must use a separate memory type for user
 	 * v6/v7 kernels), so we must use a separate memory type for user
 	 * r/o, kernel r/w to map the vectors page.
 	 * r/o, kernel r/w to map the vectors page.
 	 */
 	 */
-#ifndef CONFIG_ARM_LPAE
 	if (cpu_arch == CPU_ARCH_ARMv6)
 	if (cpu_arch == CPU_ARCH_ARMv6)
 		vecs_pgprot |= L_PTE_MT_VECTORS;
 		vecs_pgprot |= L_PTE_MT_VECTORS;
+
+	/*
+	 * Check is it with support for the PXN bit
+	 * in the Short-descriptor translation table format descriptors.
+	 */
+	if (cpu_arch == CPU_ARCH_ARMv7 &&
+		(read_cpuid_ext(CPUID_EXT_MMFR0) & 0xF) == 4) {
+		user_pmd_table |= PMD_PXNTABLE;
+	}
 #endif
 #endif
 
 
 	/*
 	/*
@@ -605,6 +602,11 @@ static void __init build_mem_type_table(void)
 	}
 	}
 	kern_pgprot |= PTE_EXT_AF;
 	kern_pgprot |= PTE_EXT_AF;
 	vecs_pgprot |= PTE_EXT_AF;
 	vecs_pgprot |= PTE_EXT_AF;
+
+	/*
+	 * Set PXN for user mappings
+	 */
+	user_pgprot |= PTE_EXT_PXN;
 #endif
 #endif
 
 
 	for (i = 0; i < 16; i++) {
 	for (i = 0; i < 16; i++) {
@@ -786,8 +788,7 @@ static void __init create_36bit_mapping(struct map_desc *md,
 	length = PAGE_ALIGN(md->length);
 	length = PAGE_ALIGN(md->length);
 
 
 	if (!(cpu_architecture() >= CPU_ARCH_ARMv6 || cpu_is_xsc3())) {
 	if (!(cpu_architecture() >= CPU_ARCH_ARMv6 || cpu_is_xsc3())) {
-		printk(KERN_ERR "MM: CPU does not support supersection "
-		       "mapping for 0x%08llx at 0x%08lx\n",
+		pr_err("MM: CPU does not support supersection mapping for 0x%08llx at 0x%08lx\n",
 		       (long long)__pfn_to_phys((u64)md->pfn), addr);
 		       (long long)__pfn_to_phys((u64)md->pfn), addr);
 		return;
 		return;
 	}
 	}
@@ -799,15 +800,13 @@ static void __init create_36bit_mapping(struct map_desc *md,
 	 *	of the actual domain assignments in use.
 	 *	of the actual domain assignments in use.
 	 */
 	 */
 	if (type->domain) {
 	if (type->domain) {
-		printk(KERN_ERR "MM: invalid domain in supersection "
-		       "mapping for 0x%08llx at 0x%08lx\n",
+		pr_err("MM: invalid domain in supersection mapping for 0x%08llx at 0x%08lx\n",
 		       (long long)__pfn_to_phys((u64)md->pfn), addr);
 		       (long long)__pfn_to_phys((u64)md->pfn), addr);
 		return;
 		return;
 	}
 	}
 
 
 	if ((addr | length | __pfn_to_phys(md->pfn)) & ~SUPERSECTION_MASK) {
 	if ((addr | length | __pfn_to_phys(md->pfn)) & ~SUPERSECTION_MASK) {
-		printk(KERN_ERR "MM: cannot create mapping for 0x%08llx"
-		       " at 0x%08lx invalid alignment\n",
+		pr_err("MM: cannot create mapping for 0x%08llx at 0x%08lx invalid alignment\n",
 		       (long long)__pfn_to_phys((u64)md->pfn), addr);
 		       (long long)__pfn_to_phys((u64)md->pfn), addr);
 		return;
 		return;
 	}
 	}
@@ -850,18 +849,16 @@ static void __init create_mapping(struct map_desc *md)
 	pgd_t *pgd;
 	pgd_t *pgd;
 
 
 	if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
 	if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
-		printk(KERN_WARNING "BUG: not creating mapping for 0x%08llx"
-		       " at 0x%08lx in user region\n",
-		       (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
+		pr_warn("BUG: not creating mapping for 0x%08llx at 0x%08lx in user region\n",
+			(long long)__pfn_to_phys((u64)md->pfn), md->virtual);
 		return;
 		return;
 	}
 	}
 
 
 	if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
 	if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
 	    md->virtual >= PAGE_OFFSET &&
 	    md->virtual >= PAGE_OFFSET &&
 	    (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
 	    (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
-		printk(KERN_WARNING "BUG: mapping for 0x%08llx"
-		       " at 0x%08lx out of vmalloc space\n",
-		       (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
+		pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n",
+			(long long)__pfn_to_phys((u64)md->pfn), md->virtual);
 	}
 	}
 
 
 	type = &mem_types[md->type];
 	type = &mem_types[md->type];
@@ -881,9 +878,8 @@ static void __init create_mapping(struct map_desc *md)
 	length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
 	length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
 
 
 	if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {
 	if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {
-		printk(KERN_WARNING "BUG: map for 0x%08llx at 0x%08lx can not "
-		       "be mapped using pages, ignoring.\n",
-		       (long long)__pfn_to_phys(md->pfn), addr);
+		pr_warn("BUG: map for 0x%08llx at 0x%08lx can not be mapped using pages, ignoring.\n",
+			(long long)__pfn_to_phys(md->pfn), addr);
 		return;
 		return;
 	}
 	}
 
 
@@ -1053,15 +1049,13 @@ static int __init early_vmalloc(char *arg)
 
 
 	if (vmalloc_reserve < SZ_16M) {
 	if (vmalloc_reserve < SZ_16M) {
 		vmalloc_reserve = SZ_16M;
 		vmalloc_reserve = SZ_16M;
-		printk(KERN_WARNING
-			"vmalloc area too small, limiting to %luMB\n",
+		pr_warn("vmalloc area too small, limiting to %luMB\n",
 			vmalloc_reserve >> 20);
 			vmalloc_reserve >> 20);
 	}
 	}
 
 
 	if (vmalloc_reserve > VMALLOC_END - (PAGE_OFFSET + SZ_32M)) {
 	if (vmalloc_reserve > VMALLOC_END - (PAGE_OFFSET + SZ_32M)) {
 		vmalloc_reserve = VMALLOC_END - (PAGE_OFFSET + SZ_32M);
 		vmalloc_reserve = VMALLOC_END - (PAGE_OFFSET + SZ_32M);
-		printk(KERN_WARNING
-			"vmalloc area is too big, limiting to %luMB\n",
+		pr_warn("vmalloc area is too big, limiting to %luMB\n",
 			vmalloc_reserve >> 20);
 			vmalloc_reserve >> 20);
 	}
 	}
 
 
@@ -1094,7 +1088,7 @@ void __init sanity_check_meminfo(void)
 
 
 			if (highmem) {
 			if (highmem) {
 				pr_notice("Ignoring RAM at %pa-%pa (!CONFIG_HIGHMEM)\n",
 				pr_notice("Ignoring RAM at %pa-%pa (!CONFIG_HIGHMEM)\n",
-					&block_start, &block_end);
+					  &block_start, &block_end);
 				memblock_remove(reg->base, reg->size);
 				memblock_remove(reg->base, reg->size);
 				continue;
 				continue;
 			}
 			}
@@ -1103,7 +1097,7 @@ void __init sanity_check_meminfo(void)
 				phys_addr_t overlap_size = reg->size - size_limit;
 				phys_addr_t overlap_size = reg->size - size_limit;
 
 
 				pr_notice("Truncating RAM at %pa-%pa to -%pa",
 				pr_notice("Truncating RAM at %pa-%pa to -%pa",
-				      &block_start, &block_end, &vmalloc_limit);
+					  &block_start, &block_end, &vmalloc_limit);
 				memblock_remove(vmalloc_limit, overlap_size);
 				memblock_remove(vmalloc_limit, overlap_size);
 				block_end = vmalloc_limit;
 				block_end = vmalloc_limit;
 			}
 			}
@@ -1326,10 +1320,10 @@ static void __init kmap_init(void)
 #ifdef CONFIG_HIGHMEM
 #ifdef CONFIG_HIGHMEM
 	pkmap_page_table = early_pte_alloc(pmd_off_k(PKMAP_BASE),
 	pkmap_page_table = early_pte_alloc(pmd_off_k(PKMAP_BASE),
 		PKMAP_BASE, _PAGE_KERNEL_TABLE);
 		PKMAP_BASE, _PAGE_KERNEL_TABLE);
-
-	fixmap_page_table = early_pte_alloc(pmd_off_k(FIXADDR_START),
-		FIXADDR_START, _PAGE_KERNEL_TABLE);
 #endif
 #endif
+
+	early_pte_alloc(pmd_off_k(FIXADDR_START), FIXADDR_START,
+			_PAGE_KERNEL_TABLE);
 }
 }
 
 
 static void __init map_lowmem(void)
 static void __init map_lowmem(void)
@@ -1349,12 +1343,19 @@ static void __init map_lowmem(void)
 		if (start >= end)
 		if (start >= end)
 			break;
 			break;
 
 
-		if (end < kernel_x_start || start >= kernel_x_end) {
+		if (end < kernel_x_start) {
 			map.pfn = __phys_to_pfn(start);
 			map.pfn = __phys_to_pfn(start);
 			map.virtual = __phys_to_virt(start);
 			map.virtual = __phys_to_virt(start);
 			map.length = end - start;
 			map.length = end - start;
 			map.type = MT_MEMORY_RWX;
 			map.type = MT_MEMORY_RWX;
 
 
+			create_mapping(&map);
+		} else if (start >= kernel_x_end) {
+			map.pfn = __phys_to_pfn(start);
+			map.virtual = __phys_to_virt(start);
+			map.length = end - start;
+			map.type = MT_MEMORY_RW;
+
 			create_mapping(&map);
 			create_mapping(&map);
 		} else {
 		} else {
 			/* This better cover the entire kernel */
 			/* This better cover the entire kernel */

+ 91 - 0
arch/arm/mm/pageattr.c

@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. 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.
+ */
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+
+struct page_change_data {
+	pgprot_t set_mask;
+	pgprot_t clear_mask;
+};
+
+static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr,
+			void *data)
+{
+	struct page_change_data *cdata = data;
+	pte_t pte = *ptep;
+
+	pte = clear_pte_bit(pte, cdata->clear_mask);
+	pte = set_pte_bit(pte, cdata->set_mask);
+
+	set_pte_ext(ptep, pte, 0);
+	return 0;
+}
+
+static int change_memory_common(unsigned long addr, int numpages,
+				pgprot_t set_mask, pgprot_t clear_mask)
+{
+	unsigned long start = addr;
+	unsigned long size = PAGE_SIZE*numpages;
+	unsigned long end = start + size;
+	int ret;
+	struct page_change_data data;
+
+	if (!IS_ALIGNED(addr, PAGE_SIZE)) {
+		start &= PAGE_MASK;
+		end = start + size;
+		WARN_ON_ONCE(1);
+	}
+
+	if (!is_module_address(start) || !is_module_address(end - 1))
+		return -EINVAL;
+
+	data.set_mask = set_mask;
+	data.clear_mask = clear_mask;
+
+	ret = apply_to_page_range(&init_mm, start, size, change_page_range,
+					&data);
+
+	flush_tlb_kernel_range(start, end);
+	return ret;
+}
+
+int set_memory_ro(unsigned long addr, int numpages)
+{
+	return change_memory_common(addr, numpages,
+					__pgprot(L_PTE_RDONLY),
+					__pgprot(0));
+}
+
+int set_memory_rw(unsigned long addr, int numpages)
+{
+	return change_memory_common(addr, numpages,
+					__pgprot(0),
+					__pgprot(L_PTE_RDONLY));
+}
+
+int set_memory_nx(unsigned long addr, int numpages)
+{
+	return change_memory_common(addr, numpages,
+					__pgprot(L_PTE_XN),
+					__pgprot(0));
+}
+
+int set_memory_x(unsigned long addr, int numpages)
+{
+	return change_memory_common(addr, numpages,
+					__pgprot(0),
+					__pgprot(L_PTE_XN));
+}

+ 3 - 2
arch/arm/mm/proc-v7.S

@@ -591,9 +591,10 @@ __krait_proc_info:
 	/*
 	/*
 	 * Some Krait processors don't indicate support for SDIV and UDIV
 	 * Some Krait processors don't indicate support for SDIV and UDIV
 	 * instructions in the ARM instruction set, even though they actually
 	 * instructions in the ARM instruction set, even though they actually
-	 * do support them.
+	 * do support them. They also don't indicate support for fused multiply
+	 * instructions even though they actually do support them.
 	 */
 	 */
-	__v7_proc __v7_setup, hwcaps = HWCAP_IDIV
+	__v7_proc __v7_setup, hwcaps = HWCAP_IDIV | HWCAP_VFPv4
 	.size	__krait_proc_info, . - __krait_proc_info
 	.size	__krait_proc_info, . - __krait_proc_info
 
 
 	/*
 	/*

+ 4 - 4
arch/arm/nwfpe/fpmodule.c

@@ -86,20 +86,20 @@ extern void nwfpe_enter(void);
 static int __init fpe_init(void)
 static int __init fpe_init(void)
 {
 {
 	if (sizeof(FPA11) > sizeof(union fp_state)) {
 	if (sizeof(FPA11) > sizeof(union fp_state)) {
-		printk(KERN_ERR "nwfpe: bad structure size\n");
+		pr_err("nwfpe: bad structure size\n");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
 	if (sizeof(FPREG) != 12) {
 	if (sizeof(FPREG) != 12) {
-		printk(KERN_ERR "nwfpe: bad register size\n");
+		pr_err("nwfpe: bad register size\n");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 	if (fpe_type[0] && strcmp(fpe_type, "nwfpe"))
 	if (fpe_type[0] && strcmp(fpe_type, "nwfpe"))
 		return 0;
 		return 0;
 
 
 	/* Display title, version and copyright information. */
 	/* Display title, version and copyright information. */
-	printk(KERN_WARNING "NetWinder Floating Point Emulator V0.97 ("
-	       NWFPE_BITS " precision)\n");
+	pr_info("NetWinder Floating Point Emulator V0.97 ("
+	        NWFPE_BITS " precision)\n");
 
 
 	thread_register_notifier(&nwfpe_notifier_block);
 	thread_register_notifier(&nwfpe_notifier_block);
 
 

+ 6 - 0
arch/arm/vfp/vfphw.S

@@ -197,6 +197,12 @@ look_for_VFP_exceptions:
 	tst	r5, #FPSCR_IXE
 	tst	r5, #FPSCR_IXE
 	bne	process_exception
 	bne	process_exception
 
 
+	tst	r5, #FPSCR_LENGTH_MASK
+	beq	skip
+	orr	r1, r1, #FPEXC_DEX
+	b	process_exception
+skip:
+
 	@ Fall into hand on to next handler - appropriate coproc instr
 	@ Fall into hand on to next handler - appropriate coproc instr
 	@ not recognised by VFP
 	@ not recognised by VFP
 
 

+ 56 - 46
arch/arm/vfp/vfpmodule.c

@@ -738,63 +738,73 @@ static int __init vfp_init(void)
 	vfp_vector = vfp_null_entry;
 	vfp_vector = vfp_null_entry;
 
 
 	pr_info("VFP support v0.3: ");
 	pr_info("VFP support v0.3: ");
-	if (VFP_arch)
+	if (VFP_arch) {
 		pr_cont("not present\n");
 		pr_cont("not present\n");
-	else if (vfpsid & FPSID_NODOUBLE) {
-		pr_cont("no double precision support\n");
-	} else {
-		hotcpu_notifier(vfp_hotplug, 0);
-
-		VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT;  /* Extract the architecture version */
-		pr_cont("implementor %02x architecture %d part %02x variant %x rev %x\n",
-			(vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT,
-			(vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT,
-			(vfpsid & FPSID_PART_MASK) >> FPSID_PART_BIT,
-			(vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT,
-			(vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT);
-
-		vfp_vector = vfp_support_entry;
-
-		thread_register_notifier(&vfp_notifier_block);
-		vfp_pm_init();
-
-		/*
-		 * We detected VFP, and the support code is
-		 * in place; report VFP support to userspace.
-		 */
-		elf_hwcap |= HWCAP_VFP;
-#ifdef CONFIG_VFPv3
-		if (VFP_arch >= 2) {
-			elf_hwcap |= HWCAP_VFPv3;
-
-			/*
-			 * Check for VFPv3 D16 and VFPv4 D16.  CPUs in
-			 * this configuration only have 16 x 64bit
-			 * registers.
-			 */
-			if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1)
-				elf_hwcap |= HWCAP_VFPv3D16; /* also v4-D16 */
-			else
-				elf_hwcap |= HWCAP_VFPD32;
-		}
-#endif
+		return 0;
+	/* Extract the architecture on CPUID scheme */
+	} else if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
+		VFP_arch = vfpsid & FPSID_CPUID_ARCH_MASK;
+		VFP_arch >>= FPSID_ARCH_BIT;
 		/*
 		/*
 		 * Check for the presence of the Advanced SIMD
 		 * Check for the presence of the Advanced SIMD
 		 * load/store instructions, integer and single
 		 * load/store instructions, integer and single
 		 * precision floating point operations. Only check
 		 * precision floating point operations. Only check
 		 * for NEON if the hardware has the MVFR registers.
 		 * for NEON if the hardware has the MVFR registers.
 		 */
 		 */
-		if ((read_cpuid_id() & 0x000f0000) == 0x000f0000) {
-#ifdef CONFIG_NEON
-			if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
-				elf_hwcap |= HWCAP_NEON;
-#endif
-#ifdef CONFIG_VFPv3
+		if (IS_ENABLED(CONFIG_NEON) &&
+		   (fmrx(MVFR1) & 0x000fff00) == 0x00011100)
+			elf_hwcap |= HWCAP_NEON;
+
+		if (IS_ENABLED(CONFIG_VFPv3)) {
+			u32 mvfr0 = fmrx(MVFR0);
+			if (((mvfr0 & MVFR0_DP_MASK) >> MVFR0_DP_BIT) == 0x2 ||
+			    ((mvfr0 & MVFR0_SP_MASK) >> MVFR0_SP_BIT) == 0x2) {
+				elf_hwcap |= HWCAP_VFPv3;
+				/*
+				 * Check for VFPv3 D16 and VFPv4 D16.  CPUs in
+				 * this configuration only have 16 x 64bit
+				 * registers.
+				 */
+				if ((mvfr0 & MVFR0_A_SIMD_MASK) == 1)
+					/* also v4-D16 */
+					elf_hwcap |= HWCAP_VFPv3D16;
+				else
+					elf_hwcap |= HWCAP_VFPD32;
+			}
+
 			if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000)
 			if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000)
 				elf_hwcap |= HWCAP_VFPv4;
 				elf_hwcap |= HWCAP_VFPv4;
-#endif
 		}
 		}
+	/* Extract the architecture version on pre-cpuid scheme */
+	} else {
+		if (vfpsid & FPSID_NODOUBLE) {
+			pr_cont("no double precision support\n");
+			return 0;
+		}
+
+		VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT;
 	}
 	}
+
+	hotcpu_notifier(vfp_hotplug, 0);
+
+	vfp_vector = vfp_support_entry;
+
+	thread_register_notifier(&vfp_notifier_block);
+	vfp_pm_init();
+
+	/*
+	 * We detected VFP, and the support code is
+	 * in place; report VFP support to userspace.
+	 */
+	elf_hwcap |= HWCAP_VFP;
+
+	pr_cont("implementor %02x architecture %d part %02x variant %x rev %x\n",
+		(vfpsid & FPSID_IMPLEMENTER_MASK) >> FPSID_IMPLEMENTER_BIT,
+		VFP_arch,
+		(vfpsid & FPSID_PART_MASK) >> FPSID_PART_BIT,
+		(vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT,
+		(vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT);
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 1
arch/arm/vfp/vfpsingle.c

@@ -290,7 +290,7 @@ u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
 	u32 z, a;
 	u32 z, a;
 
 
 	if ((significand & 0xc0000000) != 0x40000000) {
 	if ((significand & 0xc0000000) != 0x40000000) {
-		printk(KERN_WARNING "VFP: estimate_sqrt: invalid significand\n");
+		pr_warn("VFP: estimate_sqrt: invalid significand\n");
 	}
 	}
 
 
 	a = significand << 1;
 	a = significand << 1;

+ 11 - 4
drivers/amba/bus.c

@@ -95,8 +95,12 @@ static int amba_pm_runtime_suspend(struct device *dev)
 	struct amba_device *pcdev = to_amba_device(dev);
 	struct amba_device *pcdev = to_amba_device(dev);
 	int ret = pm_generic_runtime_suspend(dev);
 	int ret = pm_generic_runtime_suspend(dev);
 
 
-	if (ret == 0 && dev->driver)
-		clk_disable_unprepare(pcdev->pclk);
+	if (ret == 0 && dev->driver) {
+		if (pm_runtime_is_irq_safe(dev))
+			clk_disable(pcdev->pclk);
+		else
+			clk_disable_unprepare(pcdev->pclk);
+	}
 
 
 	return ret;
 	return ret;
 }
 }
@@ -107,7 +111,10 @@ static int amba_pm_runtime_resume(struct device *dev)
 	int ret;
 	int ret;
 
 
 	if (dev->driver) {
 	if (dev->driver) {
-		ret = clk_prepare_enable(pcdev->pclk);
+		if (pm_runtime_is_irq_safe(dev))
+			ret = clk_enable(pcdev->pclk);
+		else
+			ret = clk_prepare_enable(pcdev->pclk);
 		/* Failure is probably fatal to the system, but... */
 		/* Failure is probably fatal to the system, but... */
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
@@ -115,7 +122,7 @@ static int amba_pm_runtime_resume(struct device *dev)
 
 
 	return pm_generic_runtime_resume(dev);
 	return pm_generic_runtime_resume(dev);
 }
 }
-#endif
+#endif /* CONFIG_PM */
 
 
 static const struct dev_pm_ops amba_pm = {
 static const struct dev_pm_ops amba_pm = {
 	.suspend	= pm_generic_suspend,
 	.suspend	= pm_generic_suspend,

+ 95 - 4
drivers/dma/pl330.c

@@ -27,6 +27,7 @@
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/of_dma.h>
 #include <linux/of_dma.h>
 #include <linux/err.h>
 #include <linux/err.h>
+#include <linux/pm_runtime.h>
 
 
 #include "dmaengine.h"
 #include "dmaengine.h"
 #define PL330_MAX_CHAN		8
 #define PL330_MAX_CHAN		8
@@ -265,6 +266,9 @@ static unsigned cmd_line;
 
 
 #define NR_DEFAULT_DESC	16
 #define NR_DEFAULT_DESC	16
 
 
+/* Delay for runtime PM autosuspend, ms */
+#define PL330_AUTOSUSPEND_DELAY 20
+
 /* Populated by the PL330 core driver for DMA API driver's info */
 /* Populated by the PL330 core driver for DMA API driver's info */
 struct pl330_config {
 struct pl330_config {
 	u32	periph_id;
 	u32	periph_id;
@@ -1958,6 +1962,7 @@ static void pl330_tasklet(unsigned long data)
 	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
 	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
 	struct dma_pl330_desc *desc, *_dt;
 	struct dma_pl330_desc *desc, *_dt;
 	unsigned long flags;
 	unsigned long flags;
+	bool power_down = false;
 
 
 	spin_lock_irqsave(&pch->lock, flags);
 	spin_lock_irqsave(&pch->lock, flags);
 
 
@@ -1972,10 +1977,17 @@ static void pl330_tasklet(unsigned long data)
 	/* Try to submit a req imm. next to the last completed cookie */
 	/* Try to submit a req imm. next to the last completed cookie */
 	fill_queue(pch);
 	fill_queue(pch);
 
 
-	/* Make sure the PL330 Channel thread is active */
-	spin_lock(&pch->thread->dmac->lock);
-	_start(pch->thread);
-	spin_unlock(&pch->thread->dmac->lock);
+	if (list_empty(&pch->work_list)) {
+		spin_lock(&pch->thread->dmac->lock);
+		_stop(pch->thread);
+		spin_unlock(&pch->thread->dmac->lock);
+		power_down = true;
+	} else {
+		/* Make sure the PL330 Channel thread is active */
+		spin_lock(&pch->thread->dmac->lock);
+		_start(pch->thread);
+		spin_unlock(&pch->thread->dmac->lock);
+	}
 
 
 	while (!list_empty(&pch->completed_list)) {
 	while (!list_empty(&pch->completed_list)) {
 		dma_async_tx_callback callback;
 		dma_async_tx_callback callback;
@@ -1990,6 +2002,12 @@ static void pl330_tasklet(unsigned long data)
 		if (pch->cyclic) {
 		if (pch->cyclic) {
 			desc->status = PREP;
 			desc->status = PREP;
 			list_move_tail(&desc->node, &pch->work_list);
 			list_move_tail(&desc->node, &pch->work_list);
+			if (power_down) {
+				spin_lock(&pch->thread->dmac->lock);
+				_start(pch->thread);
+				spin_unlock(&pch->thread->dmac->lock);
+				power_down = false;
+			}
 		} else {
 		} else {
 			desc->status = FREE;
 			desc->status = FREE;
 			list_move_tail(&desc->node, &pch->dmac->desc_pool);
 			list_move_tail(&desc->node, &pch->dmac->desc_pool);
@@ -2004,6 +2022,12 @@ static void pl330_tasklet(unsigned long data)
 		}
 		}
 	}
 	}
 	spin_unlock_irqrestore(&pch->lock, flags);
 	spin_unlock_irqrestore(&pch->lock, flags);
+
+	/* If work list empty, power down */
+	if (power_down) {
+		pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
+		pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
+	}
 }
 }
 
 
 bool pl330_filter(struct dma_chan *chan, void *param)
 bool pl330_filter(struct dma_chan *chan, void *param)
@@ -2073,6 +2097,7 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
 
 
 	switch (cmd) {
 	switch (cmd) {
 	case DMA_TERMINATE_ALL:
 	case DMA_TERMINATE_ALL:
+		pm_runtime_get_sync(pl330->ddma.dev);
 		spin_lock_irqsave(&pch->lock, flags);
 		spin_lock_irqsave(&pch->lock, flags);
 
 
 		spin_lock(&pl330->lock);
 		spin_lock(&pl330->lock);
@@ -2099,10 +2124,15 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
 			dma_cookie_complete(&desc->txd);
 			dma_cookie_complete(&desc->txd);
 		}
 		}
 
 
+		if (!list_empty(&pch->work_list))
+			pm_runtime_put(pl330->ddma.dev);
+
 		list_splice_tail_init(&pch->submitted_list, &pl330->desc_pool);
 		list_splice_tail_init(&pch->submitted_list, &pl330->desc_pool);
 		list_splice_tail_init(&pch->work_list, &pl330->desc_pool);
 		list_splice_tail_init(&pch->work_list, &pl330->desc_pool);
 		list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
 		list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
 		spin_unlock_irqrestore(&pch->lock, flags);
 		spin_unlock_irqrestore(&pch->lock, flags);
+		pm_runtime_mark_last_busy(pl330->ddma.dev);
+		pm_runtime_put_autosuspend(pl330->ddma.dev);
 		break;
 		break;
 	case DMA_SLAVE_CONFIG:
 	case DMA_SLAVE_CONFIG:
 		slave_config = (struct dma_slave_config *)arg;
 		slave_config = (struct dma_slave_config *)arg;
@@ -2138,6 +2168,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
 
 
 	tasklet_kill(&pch->task);
 	tasklet_kill(&pch->task);
 
 
+	pm_runtime_get_sync(pch->dmac->ddma.dev);
 	spin_lock_irqsave(&pch->lock, flags);
 	spin_lock_irqsave(&pch->lock, flags);
 
 
 	pl330_release_channel(pch->thread);
 	pl330_release_channel(pch->thread);
@@ -2147,6 +2178,8 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
 		list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
 		list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
 
 
 	spin_unlock_irqrestore(&pch->lock, flags);
 	spin_unlock_irqrestore(&pch->lock, flags);
+	pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
+	pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
 }
 }
 
 
 static enum dma_status
 static enum dma_status
@@ -2162,6 +2195,15 @@ static void pl330_issue_pending(struct dma_chan *chan)
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&pch->lock, flags);
 	spin_lock_irqsave(&pch->lock, flags);
+	if (list_empty(&pch->work_list)) {
+		/*
+		 * Warn on nothing pending. Empty submitted_list may
+		 * break our pm_runtime usage counter as it is
+		 * updated on work_list emptiness status.
+		 */
+		WARN_ON(list_empty(&pch->submitted_list));
+		pm_runtime_get_sync(pch->dmac->ddma.dev);
+	}
 	list_splice_tail_init(&pch->submitted_list, &pch->work_list);
 	list_splice_tail_init(&pch->submitted_list, &pch->work_list);
 	spin_unlock_irqrestore(&pch->lock, flags);
 	spin_unlock_irqrestore(&pch->lock, flags);
 
 
@@ -2594,6 +2636,46 @@ static int pl330_dma_device_slave_caps(struct dma_chan *dchan,
 	return 0;
 	return 0;
 }
 }
 
 
+/*
+ * Runtime PM callbacks are provided by amba/bus.c driver.
+ *
+ * It is assumed here that IRQ safe runtime PM is chosen in probe and amba
+ * bus driver will only disable/enable the clock in runtime PM callbacks.
+ */
+static int __maybe_unused pl330_suspend(struct device *dev)
+{
+	struct amba_device *pcdev = to_amba_device(dev);
+
+	pm_runtime_disable(dev);
+
+	if (!pm_runtime_status_suspended(dev)) {
+		/* amba did not disable the clock */
+		amba_pclk_disable(pcdev);
+	}
+	amba_pclk_unprepare(pcdev);
+
+	return 0;
+}
+
+static int __maybe_unused pl330_resume(struct device *dev)
+{
+	struct amba_device *pcdev = to_amba_device(dev);
+	int ret;
+
+	ret = amba_pclk_prepare(pcdev);
+	if (ret)
+		return ret;
+
+	if (!pm_runtime_status_suspended(dev))
+		ret = amba_pclk_enable(pcdev);
+
+	pm_runtime_enable(dev);
+
+	return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(pl330_pm, pl330_suspend, pl330_resume);
+
 static int
 static int
 pl330_probe(struct amba_device *adev, const struct amba_id *id)
 pl330_probe(struct amba_device *adev, const struct amba_id *id)
 {
 {
@@ -2748,6 +2830,12 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 		pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan,
 		pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan,
 		pcfg->num_peri, pcfg->num_events);
 		pcfg->num_peri, pcfg->num_events);
 
 
+	pm_runtime_irq_safe(&adev->dev);
+	pm_runtime_use_autosuspend(&adev->dev);
+	pm_runtime_set_autosuspend_delay(&adev->dev, PL330_AUTOSUSPEND_DELAY);
+	pm_runtime_mark_last_busy(&adev->dev);
+	pm_runtime_put_autosuspend(&adev->dev);
+
 	return 0;
 	return 0;
 probe_err3:
 probe_err3:
 	/* Idle the DMAC */
 	/* Idle the DMAC */
@@ -2774,6 +2862,8 @@ static int pl330_remove(struct amba_device *adev)
 	struct pl330_dmac *pl330 = amba_get_drvdata(adev);
 	struct pl330_dmac *pl330 = amba_get_drvdata(adev);
 	struct dma_pl330_chan *pch, *_p;
 	struct dma_pl330_chan *pch, *_p;
 
 
+	pm_runtime_get_noresume(pl330->ddma.dev);
+
 	if (adev->dev.of_node)
 	if (adev->dev.of_node)
 		of_dma_controller_free(adev->dev.of_node);
 		of_dma_controller_free(adev->dev.of_node);
 
 
@@ -2812,6 +2902,7 @@ static struct amba_driver pl330_driver = {
 	.drv = {
 	.drv = {
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 		.name = "dma-pl330",
 		.name = "dma-pl330",
+		.pm = &pl330_pm,
 	},
 	},
 	.id_table = pl330_ids,
 	.id_table = pl330_ids,
 	.probe = pl330_probe,
 	.probe = pl330_probe,

+ 1 - 0
drivers/pcmcia/sa1100_generic.c

@@ -93,6 +93,7 @@ static int sa11x0_drv_pcmcia_remove(struct platform_device *dev)
 	for (i = 0; i < sinfo->nskt; i++)
 	for (i = 0; i < sinfo->nskt; i++)
 		soc_pcmcia_remove_one(&sinfo->skt[i]);
 		soc_pcmcia_remove_one(&sinfo->skt[i]);
 
 
+	clk_put(sinfo->clk);
 	kfree(sinfo);
 	kfree(sinfo);
 	return 0;
 	return 0;
 }
 }

+ 7 - 0
drivers/pcmcia/sa1111_generic.c

@@ -145,6 +145,12 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
 			return -ENOMEM;
 			return -ENOMEM;
 
 
 		s->soc.nr = ops->first + i;
 		s->soc.nr = ops->first + i;
+		s->soc.clk = clk_get(&dev->dev, NULL);
+		if (IS_ERR(s->soc.clk)) {
+			ret = PTR_ERR(s->soc.clk);
+			kfree(s);
+			return ret;
+		}
 		soc_pcmcia_init_one(&s->soc, ops, &dev->dev);
 		soc_pcmcia_init_one(&s->soc, ops, &dev->dev);
 		s->dev = dev;
 		s->dev = dev;
 		if (s->soc.nr) {
 		if (s->soc.nr) {
@@ -220,6 +226,7 @@ static int pcmcia_remove(struct sa1111_dev *dev)
 	for (; s; s = next) {
 	for (; s; s = next) {
 		next = s->next;
 		next = s->next;
 		soc_pcmcia_remove_one(&s->soc);
 		soc_pcmcia_remove_one(&s->soc);
+		clk_put(s->soc.clk);
 		kfree(s);
 		kfree(s);
 	}
 	}
 
 

+ 12 - 2
drivers/pcmcia/sa11xx_base.c

@@ -135,14 +135,16 @@ sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
 static int
 static int
 sa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt)
 sa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt)
 {
 {
-	return sa1100_pcmcia_set_mecr(skt, cpufreq_get(0));
+	unsigned long clk = clk_get_rate(skt->clk);
+
+	return sa1100_pcmcia_set_mecr(skt, clk / 1000);
 }
 }
 
 
 static int
 static int
 sa1100_pcmcia_show_timing(struct soc_pcmcia_socket *skt, char *buf)
 sa1100_pcmcia_show_timing(struct soc_pcmcia_socket *skt, char *buf)
 {
 {
 	struct soc_pcmcia_timing timing;
 	struct soc_pcmcia_timing timing;
-	unsigned int clock = cpufreq_get(0);
+	unsigned int clock = clk_get_rate(skt->clk);
 	unsigned long mecr = MECR;
 	unsigned long mecr = MECR;
 	char *p = buf;
 	char *p = buf;
 
 
@@ -218,6 +220,11 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
 	struct skt_dev_info *sinfo;
 	struct skt_dev_info *sinfo;
 	struct soc_pcmcia_socket *skt;
 	struct soc_pcmcia_socket *skt;
 	int i, ret = 0;
 	int i, ret = 0;
+	struct clk *clk;
+
+	clk = clk_get(dev, NULL);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
 
 
 	sa11xx_drv_pcmcia_ops(ops);
 	sa11xx_drv_pcmcia_ops(ops);
 
 
@@ -226,12 +233,14 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	sinfo->nskt = nr;
 	sinfo->nskt = nr;
+	sinfo->clk = clk;
 
 
 	/* Initialize processor specific parameters */
 	/* Initialize processor specific parameters */
 	for (i = 0; i < nr; i++) {
 	for (i = 0; i < nr; i++) {
 		skt = &sinfo->skt[i];
 		skt = &sinfo->skt[i];
 
 
 		skt->nr = first + i;
 		skt->nr = first + i;
+		skt->clk = clk;
 		soc_pcmcia_init_one(skt, ops, dev);
 		soc_pcmcia_init_one(skt, ops, dev);
 
 
 		ret = sa11xx_drv_pcmcia_add_one(skt);
 		ret = sa11xx_drv_pcmcia_add_one(skt);
@@ -242,6 +251,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
 	if (ret) {
 	if (ret) {
 		while (--i >= 0)
 		while (--i >= 0)
 			soc_pcmcia_remove_one(&sinfo->skt[i]);
 			soc_pcmcia_remove_one(&sinfo->skt[i]);
+		clk_put(clk);
 		kfree(sinfo);
 		kfree(sinfo);
 	} else {
 	} else {
 		dev_set_drvdata(dev, sinfo);
 		dev_set_drvdata(dev, sinfo);

+ 4 - 0
drivers/pcmcia/soc_common.c

@@ -120,6 +120,8 @@ static void __soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt,
 
 
 	if (skt->ops->hw_shutdown)
 	if (skt->ops->hw_shutdown)
 		skt->ops->hw_shutdown(skt);
 		skt->ops->hw_shutdown(skt);
+
+	clk_disable_unprepare(skt->clk);
 }
 }
 
 
 static void soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 static void soc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
@@ -131,6 +133,8 @@ static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
 {
 	int ret = 0, i;
 	int ret = 0, i;
 
 
+	clk_prepare_enable(skt->clk);
+
 	if (skt->ops->hw_init) {
 	if (skt->ops->hw_init) {
 		ret = skt->ops->hw_init(skt);
 		ret = skt->ops->hw_init(skt);
 		if (ret)
 		if (ret)

+ 23 - 7
drivers/video/fbdev/sa1100fb.c

@@ -178,6 +178,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
 #include <linux/io.h>
 #include <linux/io.h>
+#include <linux/clk.h>
 
 
 #include <video/sa1100fb.h>
 #include <video/sa1100fb.h>
 
 
@@ -416,9 +417,9 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 		var->transp.offset);
 		var->transp.offset);
 
 
 #ifdef CONFIG_CPU_FREQ
 #ifdef CONFIG_CPU_FREQ
-	dev_dbg(fbi->dev, "dma period = %d ps, clock = %d kHz\n",
+	dev_dbg(fbi->dev, "dma period = %d ps, clock = %ld kHz\n",
 		sa1100fb_display_dma_period(var),
 		sa1100fb_display_dma_period(var),
-		cpufreq_get(smp_processor_id()));
+		clk_get_rate(fbi->clk) / 1000);
 #endif
 #endif
 
 
 	return 0;
 	return 0;
@@ -592,9 +593,10 @@ static struct fb_ops sa1100fb_ops = {
  * Calculate the PCD value from the clock rate (in picoseconds).
  * Calculate the PCD value from the clock rate (in picoseconds).
  * We take account of the PPCR clock setting.
  * We take account of the PPCR clock setting.
  */
  */
-static inline unsigned int get_pcd(unsigned int pixclock, unsigned int cpuclock)
+static inline unsigned int get_pcd(struct sa1100fb_info *fbi,
+		unsigned int pixclock)
 {
 {
-	unsigned int pcd = cpuclock / 100;
+	unsigned int pcd = clk_get_rate(fbi->clk) / 100 / 1000;
 
 
 	pcd *= pixclock;
 	pcd *= pixclock;
 	pcd /= 10000000;
 	pcd /= 10000000;
@@ -673,7 +675,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
 		LCCR2_BegFrmDel(var->upper_margin) +
 		LCCR2_BegFrmDel(var->upper_margin) +
 		LCCR2_EndFrmDel(var->lower_margin);
 		LCCR2_EndFrmDel(var->lower_margin);
 
 
-	pcd = get_pcd(var->pixclock, cpufreq_get(0));
+	pcd = get_pcd(fbi, var->pixclock);
 	new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->inf->lccr3 |
 	new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->inf->lccr3 |
 		(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
 		(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
 		(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
 		(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
@@ -787,6 +789,9 @@ static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
 	fbi->palette_cpu[0] &= 0xcfff;
 	fbi->palette_cpu[0] &= 0xcfff;
 	fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
 	fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
 
 
+	/* enable LCD controller clock */
+	clk_prepare_enable(fbi->clk);
+
 	/* Sequence from 11.7.10 */
 	/* Sequence from 11.7.10 */
 	writel_relaxed(fbi->reg_lccr3, fbi->base + LCCR3);
 	writel_relaxed(fbi->reg_lccr3, fbi->base + LCCR3);
 	writel_relaxed(fbi->reg_lccr2, fbi->base + LCCR2);
 	writel_relaxed(fbi->reg_lccr2, fbi->base + LCCR2);
@@ -831,6 +836,9 @@ static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
 
 
 	schedule_timeout(20 * HZ / 1000);
 	schedule_timeout(20 * HZ / 1000);
 	remove_wait_queue(&fbi->ctrlr_wait, &wait);
 	remove_wait_queue(&fbi->ctrlr_wait, &wait);
+
+	/* disable LCD controller clock */
+	clk_disable_unprepare(fbi->clk);
 }
 }
 
 
 /*
 /*
@@ -1009,7 +1017,6 @@ sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
 			 void *data)
 			 void *data)
 {
 {
 	struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
 	struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
-	struct cpufreq_freqs *f = data;
 	u_int pcd;
 	u_int pcd;
 
 
 	switch (val) {
 	switch (val) {
@@ -1018,7 +1025,7 @@ sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
 		break;
 		break;
 
 
 	case CPUFREQ_POSTCHANGE:
 	case CPUFREQ_POSTCHANGE:
-		pcd = get_pcd(fbi->fb.var.pixclock, f->new);
+		pcd = get_pcd(fbi, fbi->fb.var.pixclock);
 		fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
 		fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
 		set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
 		set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
 		break;
 		break;
@@ -1225,6 +1232,13 @@ static int sa1100fb_probe(struct platform_device *pdev)
 	if (!fbi)
 	if (!fbi)
 		goto failed;
 		goto failed;
 
 
+	fbi->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(fbi->clk)) {
+		ret = PTR_ERR(fbi->clk);
+		fbi->clk = NULL;
+		goto failed;
+	}
+
 	fbi->base = ioremap(res->start, resource_size(res));
 	fbi->base = ioremap(res->start, resource_size(res));
 	if (!fbi->base)
 	if (!fbi->base)
 		goto failed;
 		goto failed;
@@ -1277,6 +1291,8 @@ static int sa1100fb_probe(struct platform_device *pdev)
  failed:
  failed:
 	if (fbi)
 	if (fbi)
 		iounmap(fbi->base);
 		iounmap(fbi->base);
+	if (fbi->clk)
+		clk_put(fbi->clk);
 	kfree(fbi);
 	kfree(fbi);
 	release_mem_region(res->start, resource_size(res));
 	release_mem_region(res->start, resource_size(res));
 	return ret;
 	return ret;

+ 1 - 0
drivers/video/fbdev/sa1100fb.h

@@ -68,6 +68,7 @@ struct sa1100fb_info {
 #endif
 #endif
 
 
 	const struct sa1100fb_mach_info *inf;
 	const struct sa1100fb_mach_info *inf;
+	struct clk *clk;
 };
 };
 
 
 #define TO_INF(ptr,member)	container_of(ptr,struct sa1100fb_info,member)
 #define TO_INF(ptr,member)	container_of(ptr,struct sa1100fb_info,member)

+ 10 - 0
include/linux/amba/bus.h

@@ -97,6 +97,16 @@ void amba_release_regions(struct amba_device *);
 #define amba_pclk_disable(d)	\
 #define amba_pclk_disable(d)	\
 	do { if (!IS_ERR((d)->pclk)) clk_disable((d)->pclk); } while (0)
 	do { if (!IS_ERR((d)->pclk)) clk_disable((d)->pclk); } while (0)
 
 
+static inline int amba_pclk_prepare(struct amba_device *dev)
+{
+	return clk_prepare(dev->pclk);
+}
+
+static inline void amba_pclk_unprepare(struct amba_device *dev)
+{
+	clk_unprepare(dev->pclk);
+}
+
 /* Some drivers don't use the struct amba_device */
 /* Some drivers don't use the struct amba_device */
 #define AMBA_CONFIG_BITS(a) (((a) >> 24) & 0xff)
 #define AMBA_CONFIG_BITS(a) (((a) >> 24) & 0xff)
 #define AMBA_REV_BITS(a) (((a) >> 20) & 0x0f)
 #define AMBA_REV_BITS(a) (((a) >> 20) & 0x0f)

+ 6 - 0
include/linux/pm_runtime.h

@@ -118,6 +118,11 @@ static inline void pm_runtime_mark_last_busy(struct device *dev)
 	ACCESS_ONCE(dev->power.last_busy) = jiffies;
 	ACCESS_ONCE(dev->power.last_busy) = jiffies;
 }
 }
 
 
+static inline bool pm_runtime_is_irq_safe(struct device *dev)
+{
+	return dev->power.irq_safe;
+}
+
 #else /* !CONFIG_PM */
 #else /* !CONFIG_PM */
 
 
 static inline bool queue_pm_work(struct work_struct *work) { return false; }
 static inline bool queue_pm_work(struct work_struct *work) { return false; }
@@ -164,6 +169,7 @@ static inline bool pm_runtime_enabled(struct device *dev) { return false; }
 
 
 static inline void pm_runtime_no_callbacks(struct device *dev) {}
 static inline void pm_runtime_no_callbacks(struct device *dev) {}
 static inline void pm_runtime_irq_safe(struct device *dev) {}
 static inline void pm_runtime_irq_safe(struct device *dev) {}
+static inline bool pm_runtime_is_irq_safe(struct device *dev) { return false; }
 
 
 static inline bool pm_runtime_callbacks_present(struct device *dev) { return false; }
 static inline bool pm_runtime_callbacks_present(struct device *dev) { return false; }
 static inline void pm_runtime_mark_last_busy(struct device *dev) {}
 static inline void pm_runtime_mark_last_busy(struct device *dev) {}