Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney...
[pandora-kernel.git] / arch / blackfin / kernel / process.c
index 023dc80..77800dd 100644 (file)
@@ -31,8 +31,9 @@
 #include <linux/smp_lock.h>
 #include <linux/unistd.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/tick.h>
 #include <linux/fs.h>
 #include <linux/err.h>
 
@@ -70,33 +71,44 @@ EXPORT_SYMBOL(pm_power_off);
  * The idle loop on BFIN
  */
 #ifdef CONFIG_IDLE_L1
-void default_idle(void)__attribute__((l1_text));
+static void default_idle(void)__attribute__((l1_text));
 void cpu_idle(void)__attribute__((l1_text));
 #endif
 
-void default_idle(void)
+/*
+ * This is our default idle handler.  We need to disable
+ * interrupts here to ensure we don't miss a wakeup call.
+ */
+static void default_idle(void)
 {
-       while (!need_resched()) {
-               local_irq_disable();
-               if (likely(!need_resched()))
-                       idle_with_irq_disabled();
-               local_irq_enable();
-       }
-}
+       local_irq_disable();
+       if (!need_resched())
+               idle_with_irq_disabled();
 
-void (*idle)(void) = default_idle;
+       local_irq_enable();
+}
 
 /*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
+ * The idle thread.  We try to conserve power, while trying to keep
+ * overall latency low.  The architecture specific idle is passed
+ * a value to indicate the level of "idleness" of the system.
  */
 void cpu_idle(void)
 {
        /* endless idle loop with no priority at all */
        while (1) {
-               idle();
+               void (*idle)(void) = pm_idle;
+
+#ifdef CONFIG_HOTPLUG_CPU
+               if (cpu_is_offline(smp_processor_id()))
+                       cpu_die();
+#endif
+               if (!idle)
+                       idle = default_idle;
+               tick_nohz_stop_sched_tick(1);
+               while (!need_resched())
+                       idle();
+               tick_nohz_restart_sched_tick();
                preempt_enable_no_resched();
                schedule();
                preempt_disable();
@@ -190,7 +202,7 @@ copy_thread(int nr, unsigned long clone_flags,
  * sys_execve() executes a new program.
  */
 
-asmlinkage int sys_execve(char *name, char **argv, char **envp)
+asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp)
 {
        int error;
        char *filename;
@@ -233,23 +245,25 @@ unsigned long get_wchan(struct task_struct *p)
 
 void finish_atomic_sections (struct pt_regs *regs)
 {
+       int __user *up0 = (int __user *)regs->p0;
+
        if (regs->pc < ATOMIC_SEQS_START || regs->pc >= ATOMIC_SEQS_END)
                return;
 
        switch (regs->pc) {
        case ATOMIC_XCHG32 + 2:
-               put_user(regs->r1, (int *)regs->p0);
+               put_user(regs->r1, up0);
                regs->pc += 2;
                break;
 
        case ATOMIC_CAS32 + 2:
        case ATOMIC_CAS32 + 4:
                if (regs->r0 == regs->r1)
-                       put_user(regs->r2, (int *)regs->p0);
+                       put_user(regs->r2, up0);
                regs->pc = ATOMIC_CAS32 + 8;
                break;
        case ATOMIC_CAS32 + 6:
-               put_user(regs->r2, (int *)regs->p0);
+               put_user(regs->r2, up0);
                regs->pc += 2;
                break;
 
@@ -257,7 +271,7 @@ void finish_atomic_sections (struct pt_regs *regs)
                regs->r0 = regs->r1 + regs->r0;
                /* fall through */
        case ATOMIC_ADD32 + 4:
-               put_user(regs->r0, (int *)regs->p0);
+               put_user(regs->r0, up0);
                regs->pc = ATOMIC_ADD32 + 6;
                break;
 
@@ -265,7 +279,7 @@ void finish_atomic_sections (struct pt_regs *regs)
                regs->r0 = regs->r1 - regs->r0;
                /* fall through */
        case ATOMIC_SUB32 + 4:
-               put_user(regs->r0, (int *)regs->p0);
+               put_user(regs->r0, up0);
                regs->pc = ATOMIC_SUB32 + 6;
                break;
 
@@ -273,7 +287,7 @@ void finish_atomic_sections (struct pt_regs *regs)
                regs->r0 = regs->r1 | regs->r0;
                /* fall through */
        case ATOMIC_IOR32 + 4:
-               put_user(regs->r0, (int *)regs->p0);
+               put_user(regs->r0, up0);
                regs->pc = ATOMIC_IOR32 + 6;
                break;
 
@@ -281,7 +295,7 @@ void finish_atomic_sections (struct pt_regs *regs)
                regs->r0 = regs->r1 & regs->r0;
                /* fall through */
        case ATOMIC_AND32 + 4:
-               put_user(regs->r0, (int *)regs->p0);
+               put_user(regs->r0, up0);
                regs->pc = ATOMIC_AND32 + 6;
                break;
 
@@ -289,7 +303,7 @@ void finish_atomic_sections (struct pt_regs *regs)
                regs->r0 = regs->r1 ^ regs->r0;
                /* fall through */
        case ATOMIC_XOR32 + 4:
-               put_user(regs->r0, (int *)regs->p0);
+               put_user(regs->r0, up0);
                regs->pc = ATOMIC_XOR32 + 6;
                break;
        }
@@ -310,6 +324,12 @@ int _access_ok(unsigned long addr, unsigned long size)
                return 1;
        if (addr >= memory_mtd_end && (addr + size) <= physical_mem_end)
                return 1;
+
+#ifdef CONFIG_ROMFS_MTD_FS
+       /* For XIP, allow user space to use pointers within the ROMFS.  */
+       if (addr >= memory_mtd_start && (addr + size) <= memory_mtd_end)
+               return 1;
+#endif
 #else
        if (addr >= memory_start && (addr + size) <= physical_mem_end)
                return 1;