]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
Merge branch 'fixes' into for-linus
authorRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 11 Oct 2012 09:55:04 +0000 (10:55 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 11 Oct 2012 09:55:04 +0000 (10:55 +0100)
Conflicts:
arch/arm/kernel/smp.c

1  2 
arch/arm/include/asm/glue-cache.h
arch/arm/kernel/Makefile
arch/arm/kernel/head.S
arch/arm/kernel/setup.c
arch/arm/kernel/smp.c
arch/arm/mm/cache-v7.S

index 2d6a7de87a88bcf9de7a1588b47da2043eeffd9f,4f8d2c0dc4419f702449132e46ae7f89bcf2865a..cca9f15704ed82bb2726ce8898611be42d28b5ff
  #endif
  
  #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K)
//# ifdef _CACHE
+ # ifdef _CACHE
  #  define MULTI_CACHE 1
//# else
//#  define _CACHE v6
//# endif
+ # else
+ #  define _CACHE v6
+ # endif
  #endif
  
  #if defined(CONFIG_CPU_V7)
//# ifdef _CACHE
+ # ifdef _CACHE
  #  define MULTI_CACHE 1
//# else
//#  define _CACHE v7
//# endif
+ # else
+ #  define _CACHE v7
+ # endif
  #endif
  
  #if !defined(_CACHE) && !defined(MULTI_CACHE)
  #ifndef MULTI_CACHE
  #define __cpuc_flush_icache_all               __glue(_CACHE,_flush_icache_all)
  #define __cpuc_flush_kern_all         __glue(_CACHE,_flush_kern_cache_all)
 +#define __cpuc_flush_kern_louis               __glue(_CACHE,_flush_kern_cache_louis)
  #define __cpuc_flush_user_all         __glue(_CACHE,_flush_user_cache_all)
  #define __cpuc_flush_user_range               __glue(_CACHE,_flush_user_cache_range)
  #define __cpuc_coherent_kern_range    __glue(_CACHE,_coherent_kern_range)
diff --combined arch/arm/kernel/Makefile
index 49b61a3f5b29c486b962abacb1f65462cd821a68,5dfef9d97ed92b960d8d359997a20108759d60c8..5bbec7b8183e46e0d5ba4f078ba146789f409be1
@@@ -19,9 -19,10 +19,10 @@@ obj-y               := elf.o entry-armv.o entry-comm
                   process.o ptrace.o return_address.o sched_clock.o \
                   setup.o signal.o stacktrace.o sys_arm.o time.o traps.o
  
- obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o
+ obj-$(CONFIG_ATAGS)           += atags_parse.o
+ obj-$(CONFIG_ATAGS_PROC)      += atags_proc.o
+ obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += atags_compat.o
  
- obj-$(CONFIG_LEDS)            += leds.o
  obj-$(CONFIG_OC_ETM)          += etm.o
  obj-$(CONFIG_CPU_IDLE)                += cpuidle.o
  obj-$(CONFIG_ISA_DMA_API)     += dma.o
@@@ -52,7 -53,6 +53,6 @@@ test-kprobes-objs             += kprobes-test-thum
  else
  test-kprobes-objs             += kprobes-test-arm.o
  endif
- obj-$(CONFIG_ATAGS_PROC)      += atags.o
  obj-$(CONFIG_OABI_COMPAT)     += sys_oabi-compat.o
  obj-$(CONFIG_ARM_THUMBEE)     += thumbee.o
  obj-$(CONFIG_KGDB)            += kgdb.o
@@@ -69,8 -69,7 +69,7 @@@ obj-$(CONFIG_CPU_XSC3)                += xscale-cp0.
  obj-$(CONFIG_CPU_MOHAWK)      += xscale-cp0.o
  obj-$(CONFIG_CPU_PJ4)         += pj4-cp0.o
  obj-$(CONFIG_IWMMXT)          += iwmmxt.o
- obj-$(CONFIG_CPU_HAS_PMU)     += pmu.o
- obj-$(CONFIG_HW_PERF_EVENTS)  += perf_event.o
+ obj-$(CONFIG_HW_PERF_EVENTS)  += perf_event.o perf_event_cpu.o
  AFLAGS_iwmmxt.o                       := -Wa,-mcpu=iwmmxt
  obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o
  
@@@ -82,6 -81,4 +81,6 @@@ head-y                        := head$(MMUEXT).
  obj-$(CONFIG_DEBUG_LL)        += debug.o
  obj-$(CONFIG_EARLY_PRINTK)    += early_printk.o
  
 +obj-$(CONFIG_ARM_VIRT_EXT)    += hyp-stub.o
 +
  extra-y := $(head-y) vmlinux.lds
diff --combined arch/arm/kernel/head.S
index 27093e4feef8f225d5a13d8a3a7316731c36ba12,9874d074119118f1d42abeee662beaa3433ca052..4eee351f4668e2bbee54c3771a5389ce8900c10c
@@@ -23,8 -23,8 +23,8 @@@
  #include <asm/thread_info.h>
  #include <asm/pgtable.h>
  
- #ifdef CONFIG_DEBUG_LL
- #include <mach/debug-macro.S>
+ #if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_SEMIHOSTING)
+ #include CONFIG_DEBUG_LL_INCLUDE
  #endif
  
  /*
@@@ -83,12 -83,8 +83,12 @@@ ENTRY(stext
   THUMB(       .thumb                  )       @ switch to Thumb now.
   THUMB(1:                     )
  
 -      setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
 -                                              @ and irqs disabled
 +#ifdef CONFIG_ARM_VIRT_EXT
 +      bl      __hyp_stub_install
 +#endif
 +      @ ensure svc mode and all interrupts masked
 +      safe_svcmode_maskall r9
 +
        mrc     p15, 0, r9, c0, c0              @ get processor id
        bl      __lookup_processor_type         @ r5=procinfo r9=cpuid
        movs    r10, r5                         @ invalid processor (r5=0)?
@@@ -330,11 -326,7 +330,11 @@@ ENTRY(secondary_startup
         * the processor type - there is no need to check the machine type
         * as it has already been validated by the primary processor.
         */
 -      setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
 +#ifdef CONFIG_ARM_VIRT_EXT
 +      bl      __hyp_stub_install
 +#endif
 +      safe_svcmode_maskall r9
 +
        mrc     p15, 0, r9, c0, c0              @ get processor id
        bl      __lookup_processor_type
        movs    r10, r5                         @ invalid processor?
diff --combined arch/arm/kernel/setup.c
index 04fd01feea86ed82672a406fa5343f6144023875,febafa0f552d6a75e2bc51755054a8b6e68cf5a8..da1d1aa20ad957ccd7021815014d12530de4f3a1
  #include <linux/init.h>
  #include <linux/kexec.h>
  #include <linux/of_fdt.h>
- #include <linux/root_dev.h>
  #include <linux/cpu.h>
  #include <linux/interrupt.h>
  #include <linux/smp.h>
- #include <linux/fs.h>
  #include <linux/proc_fs.h>
  #include <linux/memblock.h>
  #include <linux/bug.h>
  #include <asm/traps.h>
  #include <asm/unwind.h>
  #include <asm/memblock.h>
 +#include <asm/virt.h>
  
- #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
- #include "compat.h"
- #endif
  #include "atags.h"
  #include "tcm.h"
  
- #ifndef MEM_SIZE
- #define MEM_SIZE      (16*1024*1024)
- #endif
  
  #if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
  char fpe_type[8];
@@@ -146,7 -137,6 +138,6 @@@ static const char *machine_name
  static char __initdata cmd_line[COMMAND_LINE_SIZE];
  struct machine_desc *machine_desc __initdata;
  
- static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
  static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } };
  #define ENDIANNESS ((char)endian_test.l)
  
@@@ -584,21 -574,6 +575,6 @@@ static int __init early_mem(char *p
  }
  early_param("mem", early_mem);
  
- static void __init
- setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
- {
- #ifdef CONFIG_BLK_DEV_RAM
-       extern int rd_size, rd_image_start, rd_prompt, rd_doload;
-       rd_image_start = image_start;
-       rd_prompt = prompt;
-       rd_doload = doload;
-       if (rd_sz)
-               rd_size = rd_sz;
- #endif
- }
  static void __init request_standard_resources(struct machine_desc *mdesc)
  {
        struct memblock_region *region;
                request_resource(&ioport_resource, &lp2);
  }
  
- /*
-  *  Tag parsing.
-  *
-  * This is the new way of passing data to the kernel at boot time.  Rather
-  * than passing a fixed inflexible structure to the kernel, we pass a list
-  * of variable-sized tags to the kernel.  The first tag must be a ATAG_CORE
-  * tag for the list to be recognised (to distinguish the tagged list from
-  * a param_struct).  The list is terminated with a zero-length tag (this tag
-  * is not parsed in any way).
-  */
- static int __init parse_tag_core(const struct tag *tag)
- {
-       if (tag->hdr.size > 2) {
-               if ((tag->u.core.flags & 1) == 0)
-                       root_mountflags &= ~MS_RDONLY;
-               ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
-       }
-       return 0;
- }
- __tagtable(ATAG_CORE, parse_tag_core);
- static int __init parse_tag_mem32(const struct tag *tag)
- {
-       return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
- }
- __tagtable(ATAG_MEM, parse_tag_mem32);
  #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
  struct screen_info screen_info = {
   .orig_video_lines    = 30,
   .orig_video_isVGA    = 1,
   .orig_video_points   = 8
  };
- static int __init parse_tag_videotext(const struct tag *tag)
- {
-       screen_info.orig_x            = tag->u.videotext.x;
-       screen_info.orig_y            = tag->u.videotext.y;
-       screen_info.orig_video_page   = tag->u.videotext.video_page;
-       screen_info.orig_video_mode   = tag->u.videotext.video_mode;
-       screen_info.orig_video_cols   = tag->u.videotext.video_cols;
-       screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
-       screen_info.orig_video_lines  = tag->u.videotext.video_lines;
-       screen_info.orig_video_isVGA  = tag->u.videotext.video_isvga;
-       screen_info.orig_video_points = tag->u.videotext.video_points;
-       return 0;
- }
- __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
- #endif
- static int __init parse_tag_ramdisk(const struct tag *tag)
- {
-       setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
-                     (tag->u.ramdisk.flags & 2) == 0,
-                     tag->u.ramdisk.start, tag->u.ramdisk.size);
-       return 0;
- }
- __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
- static int __init parse_tag_serialnr(const struct tag *tag)
- {
-       system_serial_low = tag->u.serialnr.low;
-       system_serial_high = tag->u.serialnr.high;
-       return 0;
- }
- __tagtable(ATAG_SERIAL, parse_tag_serialnr);
- static int __init parse_tag_revision(const struct tag *tag)
- {
-       system_rev = tag->u.revision.rev;
-       return 0;
- }
- __tagtable(ATAG_REVISION, parse_tag_revision);
- static int __init parse_tag_cmdline(const struct tag *tag)
- {
- #if defined(CONFIG_CMDLINE_EXTEND)
-       strlcat(default_command_line, " ", COMMAND_LINE_SIZE);
-       strlcat(default_command_line, tag->u.cmdline.cmdline,
-               COMMAND_LINE_SIZE);
- #elif defined(CONFIG_CMDLINE_FORCE)
-       pr_warning("Ignoring tag cmdline (using the default kernel command line)\n");
- #else
-       strlcpy(default_command_line, tag->u.cmdline.cmdline,
-               COMMAND_LINE_SIZE);
  #endif
-       return 0;
- }
- __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
- /*
-  * Scan the tag table for this tag, and call its parse function.
-  * The tag table is built by the linker from all the __tagtable
-  * declarations.
-  */
- static int __init parse_tag(const struct tag *tag)
- {
-       extern struct tagtable __tagtable_begin, __tagtable_end;
-       struct tagtable *t;
-       for (t = &__tagtable_begin; t < &__tagtable_end; t++)
-               if (tag->hdr.tag == t->tag) {
-                       t->parse(tag);
-                       break;
-               }
-       return t < &__tagtable_end;
- }
- /*
-  * Parse all tags in the list, checking both the global and architecture
-  * specific tag tables.
-  */
- static void __init parse_tags(const struct tag *t)
- {
-       for (; t->hdr.size; t = tag_next(t))
-               if (!parse_tag(t))
-                       printk(KERN_WARNING
-                               "Ignoring unrecognised tag 0x%08x\n",
-                               t->hdr.tag);
- }
- /*
-  * This holds our defaults.
-  */
- static struct init_tags {
-       struct tag_header hdr1;
-       struct tag_core   core;
-       struct tag_header hdr2;
-       struct tag_mem32  mem;
-       struct tag_header hdr3;
- } init_tags __initdata = {
-       { tag_size(tag_core), ATAG_CORE },
-       { 1, PAGE_SIZE, 0xff },
-       { tag_size(tag_mem32), ATAG_MEM },
-       { MEM_SIZE },
-       { 0, ATAG_NONE }
- };
  
  static int __init customize_machine(void)
  {
@@@ -859,78 -696,6 +697,6 @@@ static void __init reserve_crashkernel(
  static inline void reserve_crashkernel(void) {}
  #endif /* CONFIG_KEXEC */
  
- static void __init squash_mem_tags(struct tag *tag)
- {
-       for (; tag->hdr.size; tag = tag_next(tag))
-               if (tag->hdr.tag == ATAG_MEM)
-                       tag->hdr.tag = ATAG_NONE;
- }
- static struct machine_desc * __init setup_machine_tags(unsigned int nr)
- {
-       struct tag *tags = (struct tag *)&init_tags;
-       struct machine_desc *mdesc = NULL, *p;
-       char *from = default_command_line;
-       init_tags.mem.start = PHYS_OFFSET;
-       /*
-        * locate machine in the list of supported machines.
-        */
-       for_each_machine_desc(p)
-               if (nr == p->nr) {
-                       printk("Machine: %s\n", p->name);
-                       mdesc = p;
-                       break;
-               }
-       if (!mdesc) {
-               early_print("\nError: unrecognized/unsupported machine ID"
-                       " (r1 = 0x%08x).\n\n", nr);
-               dump_machine_table(); /* does not return */
-       }
-       if (__atags_pointer)
-               tags = phys_to_virt(__atags_pointer);
-       else if (mdesc->atag_offset)
-               tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);
- #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
-       /*
-        * If we have the old style parameters, convert them to
-        * a tag list.
-        */
-       if (tags->hdr.tag != ATAG_CORE)
-               convert_to_tag_list(tags);
- #endif
-       if (tags->hdr.tag != ATAG_CORE) {
- #if defined(CONFIG_OF)
-               /*
-                * If CONFIG_OF is set, then assume this is a reasonably
-                * modern system that should pass boot parameters
-                */
-               early_print("Warning: Neither atags nor dtb found\n");
- #endif
-               tags = (struct tag *)&init_tags;
-       }
-       if (mdesc->fixup)
-               mdesc->fixup(tags, &from, &meminfo);
-       if (tags->hdr.tag == ATAG_CORE) {
-               if (meminfo.nr_banks != 0)
-                       squash_mem_tags(tags);
-               save_atags(tags);
-               parse_tags(tags);
-       }
-       /* parse_early_param needs a boot_command_line */
-       strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
-       return mdesc;
- }
  static int __init meminfo_cmp(const void *_a, const void *_b)
  {
        const struct membank *a = _a, *b = _b;
        return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
  }
  
 +void __init hyp_mode_check(void)
 +{
 +#ifdef CONFIG_ARM_VIRT_EXT
 +      if (is_hyp_mode_available()) {
 +              pr_info("CPU: All CPU(s) started in HYP mode.\n");
 +              pr_info("CPU: Virtualization extensions available.\n");
 +      } else if (is_hyp_mode_mismatched()) {
 +              pr_warn("CPU: WARNING: CPU(s) started in wrong/inconsistent modes (primary CPU mode 0x%x)\n",
 +                      __boot_cpu_mode & MODE_MASK);
 +              pr_warn("CPU: This may indicate a broken bootloader or firmware.\n");
 +      } else
 +              pr_info("CPU: All CPU(s) started in SVC mode.\n");
 +#endif
 +}
 +
  void __init setup_arch(char **cmdline_p)
  {
        struct machine_desc *mdesc;
        setup_processor();
        mdesc = setup_machine_fdt(__atags_pointer);
        if (!mdesc)
-               mdesc = setup_machine_tags(machine_arch_type);
+               mdesc = setup_machine_tags(__atags_pointer, machine_arch_type);
        machine_desc = mdesc;
        machine_name = mdesc->name;
  
        unflatten_device_tree();
  
  #ifdef CONFIG_SMP
-       if (is_smp())
+       if (is_smp()) {
+               smp_set_ops(mdesc->smp);
                smp_init_cpus();
+       }
  #endif
 +
 +      if (!is_smp())
 +              hyp_mode_check();
 +
        reserve_crashkernel();
  
        tcm_init();
diff --combined arch/arm/kernel/smp.c
index f34514a0834e53b13a177a49a9d178153ff9088e,d100eacdb7983f8e490a8dc88d4f830b7fab3b8c..8e20754dd31d5946f5297aae2023ae2c8d5cd572
  #include <linux/mm.h>
  #include <linux/err.h>
  #include <linux/cpu.h>
- #include <linux/smp.h>
  #include <linux/seq_file.h>
  #include <linux/irq.h>
  #include <linux/percpu.h>
  #include <linux/clockchips.h>
  #include <linux/completion.h>
+ #include <linux/cpufreq.h>
  
  #include <linux/atomic.h>
+ #include <asm/smp.h>
  #include <asm/cacheflush.h>
  #include <asm/cpu.h>
  #include <asm/cputype.h>
@@@ -42,7 -43,7 +43,8 @@@
  #include <asm/ptrace.h>
  #include <asm/localtimer.h>
  #include <asm/smp_plat.h>
 +#include <asm/virt.h>
+ #include <asm/mach/arch.h>
  
  /*
   * as from 2.5, kernels no longer have an init_tasks structure
   */
  struct secondary_data secondary_data;
  
+ /*
+  * control for which core is the next to come out of the secondary
+  * boot "holding pen"
+  */
+ volatile int __cpuinitdata pen_release = -1;
  enum ipi_msg_type {
-       IPI_TIMER = 2,
+       IPI_WAKEUP,
+       IPI_TIMER,
        IPI_RESCHEDULE,
        IPI_CALL_FUNC,
        IPI_CALL_FUNC_SINGLE,
  
  static DECLARE_COMPLETION(cpu_running);
  
+ static struct smp_operations smp_ops;
+ void __init smp_set_ops(struct smp_operations *ops)
+ {
+       if (ops)
+               smp_ops = *ops;
+ };
  int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
  {
        int ret;
        return ret;
  }
  
+ /* platform specific SMP operations */
+ void __init smp_init_cpus(void)
+ {
+       if (smp_ops.smp_init_cpus)
+               smp_ops.smp_init_cpus();
+ }
+ static void __init platform_smp_prepare_cpus(unsigned int max_cpus)
+ {
+       if (smp_ops.smp_prepare_cpus)
+               smp_ops.smp_prepare_cpus(max_cpus);
+ }
+ static void __cpuinit platform_secondary_init(unsigned int cpu)
+ {
+       if (smp_ops.smp_secondary_init)
+               smp_ops.smp_secondary_init(cpu);
+ }
+ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+ {
+       if (smp_ops.smp_boot_secondary)
+               return smp_ops.smp_boot_secondary(cpu, idle);
+       return -ENOSYS;
+ }
  #ifdef CONFIG_HOTPLUG_CPU
  static void percpu_timer_stop(void);
  
+ static int platform_cpu_kill(unsigned int cpu)
+ {
+       if (smp_ops.cpu_kill)
+               return smp_ops.cpu_kill(cpu);
+       return 1;
+ }
+ static void platform_cpu_die(unsigned int cpu)
+ {
+       if (smp_ops.cpu_die)
+               smp_ops.cpu_die(cpu);
+ }
+ static int platform_cpu_disable(unsigned int cpu)
+ {
+       if (smp_ops.cpu_disable)
+               return smp_ops.cpu_disable(cpu);
+       /*
+        * By default, allow disabling all CPUs except the first one,
+        * since this is special on a lot of platforms, e.g. because
+        * of clock tick interrupts.
+        */
+       return cpu == 0 ? -EPERM : 0;
+ }
  /*
   * __cpu_disable runs on the processor to be shutdown.
   */
- int __cpu_disable(void)
+ int __cpuinit __cpu_disable(void)
  {
        unsigned int cpu = smp_processor_id();
        int ret;
        /*
         * Flush user cache and TLB mappings, and then remove this CPU
         * from the vm mask set of all processes.
 +       *
 +       * Caches are flushed to the Level of Unification Inner Shareable
 +       * to write-back dirty lines to unified caches shared by all CPUs.
         */
 -      flush_cache_all();
 +      flush_cache_louis();
        local_flush_tlb_all();
  
        clear_tasks_mm_cpumask(cpu);
@@@ -153,7 -217,7 +221,7 @@@ static DECLARE_COMPLETION(cpu_died)
   * called on the thread which is asking for a CPU to be shutdown -
   * waits until shutdown has completed, or it is timed out.
   */
- void __cpu_die(unsigned int cpu)
+ void __cpuinit __cpu_die(unsigned int cpu)
  {
        if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) {
                pr_err("CPU%u: cpu didn't die\n", cpu);
@@@ -291,8 -355,6 +359,8 @@@ void __init smp_cpus_done(unsigned int 
               num_online_cpus(),
               bogosum / (500000/HZ),
               (bogosum / (5000/HZ)) % 100);
 +
 +      hyp_mode_check();
  }
  
  void __init smp_prepare_boot_cpu(void)
@@@ -353,7 -415,8 +421,8 @@@ void arch_send_call_function_single_ipi
  }
  
  static const char *ipi_types[NR_IPI] = {
- #define S(x,s)        [x - IPI_TIMER] = s
+ #define S(x,s)        [x] = s
+       S(IPI_WAKEUP, "CPU wakeup interrupts"),
        S(IPI_TIMER, "Timer broadcast interrupts"),
        S(IPI_RESCHEDULE, "Rescheduling interrupts"),
        S(IPI_CALL_FUNC, "Function call interrupts"),
@@@ -506,10 -569,13 +575,13 @@@ void handle_IPI(int ipinr, struct pt_re
        unsigned int cpu = smp_processor_id();
        struct pt_regs *old_regs = set_irq_regs(regs);
  
-       if (ipinr >= IPI_TIMER && ipinr < IPI_TIMER + NR_IPI)
-               __inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_TIMER]);
+       if (ipinr < NR_IPI)
+               __inc_irq_stat(cpu, ipi_irqs[ipinr]);
  
        switch (ipinr) {
+       case IPI_WAKEUP:
+               break;
        case IPI_TIMER:
                irq_enter();
                ipi_timer();
@@@ -590,3 -656,56 +662,56 @@@ int setup_profiling_timer(unsigned int 
  {
        return -EINVAL;
  }
+ #ifdef CONFIG_CPU_FREQ
+ static DEFINE_PER_CPU(unsigned long, l_p_j_ref);
+ static DEFINE_PER_CPU(unsigned long, l_p_j_ref_freq);
+ static unsigned long global_l_p_j_ref;
+ static unsigned long global_l_p_j_ref_freq;
+ static int cpufreq_callback(struct notifier_block *nb,
+                                       unsigned long val, void *data)
+ {
+       struct cpufreq_freqs *freq = data;
+       int cpu = freq->cpu;
+       if (freq->flags & CPUFREQ_CONST_LOOPS)
+               return NOTIFY_OK;
+       if (!per_cpu(l_p_j_ref, cpu)) {
+               per_cpu(l_p_j_ref, cpu) =
+                       per_cpu(cpu_data, cpu).loops_per_jiffy;
+               per_cpu(l_p_j_ref_freq, cpu) = freq->old;
+               if (!global_l_p_j_ref) {
+                       global_l_p_j_ref = loops_per_jiffy;
+                       global_l_p_j_ref_freq = freq->old;
+               }
+       }
+       if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
+           (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
+           (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
+               loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
+                                               global_l_p_j_ref_freq,
+                                               freq->new);
+               per_cpu(cpu_data, cpu).loops_per_jiffy =
+                       cpufreq_scale(per_cpu(l_p_j_ref, cpu),
+                                       per_cpu(l_p_j_ref_freq, cpu),
+                                       freq->new);
+       }
+       return NOTIFY_OK;
+ }
+ static struct notifier_block cpufreq_notifier = {
+       .notifier_call  = cpufreq_callback,
+ };
+ static int __init register_cpufreq_notifier(void)
+ {
+       return cpufreq_register_notifier(&cpufreq_notifier,
+                                               CPUFREQ_TRANSITION_NOTIFIER);
+ }
+ core_initcall(register_cpufreq_notifier);
+ #endif
diff --combined arch/arm/mm/cache-v7.S
index 140b294bbd9b61fbefa1f79b9056be9b3c6c3d0a,3b172275262e2c87070af4047a1123c2a6a1a6aa..cd956647c21a800d69ed3215a774b086fed008a1
@@@ -33,24 -33,6 +33,24 @@@ ENTRY(v7_flush_icache_all
        mov     pc, lr
  ENDPROC(v7_flush_icache_all)
  
 + /*
 + *     v7_flush_dcache_louis()
 + *
 + *     Flush the D-cache up to the Level of Unification Inner Shareable
 + *
 + *     Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
 + */
 +
 +ENTRY(v7_flush_dcache_louis)
 +      dmb                                     @ ensure ordering with previous memory accesses
 +      mrc     p15, 1, r0, c0, c0, 1           @ read clidr, r0 = clidr
 +      ands    r3, r0, #0xe00000               @ extract LoUIS from clidr
 +      mov     r3, r3, lsr #20                 @ r3 = LoUIS * 2
 +      moveq   pc, lr                          @ return if level == 0
 +      mov     r10, #0                         @ r10 (starting level) = 0
 +      b       flush_levels                    @ start flushing cache levels
 +ENDPROC(v7_flush_dcache_louis)
 +
  /*
   *    v7_flush_dcache_all()
   *
@@@ -67,7 -49,7 +67,7 @@@ ENTRY(v7_flush_dcache_all
        mov     r3, r3, lsr #23                 @ left align loc bit field
        beq     finished                        @ if loc is 0, then no need to clean
        mov     r10, #0                         @ start clean at cache level 0
 -loop1:
 +flush_levels:
        add     r2, r10, r10, lsr #1            @ work out 3x current cache level
        mov     r1, r0, lsr r2                  @ extract cache type bits from clidr
        and     r1, r1, #7                      @ mask of the bits for current cache only
@@@ -89,9 -71,9 +89,9 @@@
        clz     r5, r4                          @ find bit position of way size increment
        ldr     r7, =0x7fff
        ands    r7, r7, r1, lsr #13             @ extract max number of the index size
 -loop2:
 +loop1:
        mov     r9, r4                          @ create working copy of max way size
 -loop3:
 +loop2:
   ARM( orr     r11, r10, r9, lsl r5    )       @ factor way and cache number into r11
   THUMB(       lsl     r6, r9, r5              )
   THUMB(       orr     r11, r10, r6            )       @ factor way and cache number into r11
   THUMB(       orr     r11, r11, r6            )       @ factor index number into r11
        mcr     p15, 0, r11, c7, c14, 2         @ clean & invalidate by set/way
        subs    r9, r9, #1                      @ decrement the way
 -      bge     loop3
 -      subs    r7, r7, #1                      @ decrement the index
        bge     loop2
 +      subs    r7, r7, #1                      @ decrement the index
 +      bge     loop1
  skip:
        add     r10, r10, #2                    @ increment cache number
        cmp     r3, r10
 -      bgt     loop1
 +      bgt     flush_levels
  finished:
        mov     r10, #0                         @ swith back to cache level 0
        mcr     p15, 2, r10, c0, c0, 0          @ select current cache level in cssr
@@@ -138,24 -120,6 +138,24 @@@ ENTRY(v7_flush_kern_cache_all
        mov     pc, lr
  ENDPROC(v7_flush_kern_cache_all)
  
 + /*
 + *     v7_flush_kern_cache_louis(void)
 + *
 + *     Flush the data cache up to Level of Unification Inner Shareable.
 + *     Invalidate the I-cache to the point of unification.
 + */
 +ENTRY(v7_flush_kern_cache_louis)
 + ARM( stmfd   sp!, {r4-r5, r7, r9-r11, lr}    )
 + THUMB(       stmfd   sp!, {r4-r7, r9-r11, lr}        )
 +      bl      v7_flush_dcache_louis
 +      mov     r0, #0
 +      ALT_SMP(mcr     p15, 0, r0, c7, c1, 0)  @ invalidate I-cache inner shareable
 +      ALT_UP(mcr      p15, 0, r0, c7, c5, 0)  @ I+BTB cache invalidate
 + ARM( ldmfd   sp!, {r4-r5, r7, r9-r11, lr}    )
 + THUMB(       ldmfd   sp!, {r4-r7, r9-r11, lr}        )
 +      mov     pc, lr
 +ENDPROC(v7_flush_kern_cache_louis)
 +
  /*
   *    v7_flush_cache_all()
   *
@@@ -247,6 -211,9 +247,9 @@@ ENTRY(v7_coherent_user_range
   * isn't mapped, fail with -EFAULT.
   */
  9001:
+ #ifdef CONFIG_ARM_ERRATA_775420
+       dsb
+ #endif
        mov     r0, #-EFAULT
        mov     pc, lr
   UNWIND(.fnend                )