Merge tag 'v3.10.56' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm64 / kernel / process.c
index 0860fc3077fc6515f37178546ba8f693318101cb..ad14dbc07db8d4a135fdb64226b4ae87f87b7ddc 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <stdarg.h>
 
+#include <linux/compat.h>
 #include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/uaccess.h>
 #include <linux/random.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/cpuidle.h>
+#include <linux/leds.h>
 #include <linux/personality.h>
 #include <linux/notifier.h>
+#include <linux/mtk_ram_console.h>
 
 #include <asm/compat.h>
 #include <asm/cacheflush.h>
@@ -50,6 +54,8 @@
 #include <asm/processor.h>
 #include <asm/stacktrace.h>
 
+extern void arch_reset(char mode, const char *cmd);
+
 static void setup_restart(void)
 {
        /*
@@ -84,22 +90,55 @@ EXPORT_SYMBOL_GPL(pm_power_off);
 void (*arm_pm_restart)(char str, const char *cmd);
 EXPORT_SYMBOL_GPL(arm_pm_restart);
 
+/*
+ * This is our default idle handler.
+ */
+
+void (*arm_pm_idle)(void);      
+
+static void default_idle(void)
+{
+       if (arm_pm_idle)
+               arm_pm_idle();
+       else
+               cpu_do_idle();
+       local_irq_enable();
+}
+
 void arch_cpu_idle_prepare(void)
 {
        local_fiq_enable();
 }
 
+void arch_cpu_idle_enter(void)
+{
+       idle_notifier_call_chain(IDLE_START);
+       ledtrig_cpu(CPU_LED_IDLE_START);
+#ifdef CONFIG_PL310_ERRATA_769419
+       wmb();
+#endif
+}
+
+void arch_cpu_idle_exit(void)
+{
+       ledtrig_cpu(CPU_LED_IDLE_END);
+       idle_notifier_call_chain(IDLE_END);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+void arch_cpu_idle_dead(void)
+{
+       cpu_die();
+}
+#endif
+
 /*
- * This is our default idle handler.
+ * Called from the core idle loop.
  */
 void arch_cpu_idle(void)
 {
-       /*
-        * This should do all the clock switching and wait for interrupt
-        * tricks
-        */
-       cpu_do_idle();
-       local_irq_enable();
+       if (cpuidle_idle_call())
+               default_idle();
 }
 
 void machine_shutdown(void)
@@ -115,25 +154,103 @@ void machine_halt(void)
        while (1);
 }
 
+extern int reboot_pid;
+//static int reboot_pid = 0;
+
 void machine_power_off(void)
 {
+       struct task_struct *tsk;
+       /* Disable interrupts first */
+       local_irq_disable();
+       local_fiq_disable();
+       
        machine_shutdown();
+       if(reboot_pid > 1)
+       {
+               tsk = find_task_by_vpid(reboot_pid);
+               if(tsk == NULL)
+                       tsk = current;          
+               dump_stack();
+       }
+       else
+       {
+               tsk = current;
+       }
+
+       if(tsk->real_parent)
+       {
+        if(tsk->real_parent->real_parent)
+        {
+          printk("machine_shutdown: start, Proess(%s:%d). father %s:%d. grandfather %s:%d.\n",
+               tsk->comm, tsk->pid,tsk->real_parent->comm,tsk->real_parent->pid,
+               tsk->real_parent->real_parent->comm,tsk->real_parent->real_parent->pid);
+        }
+        else
+        {
+          printk("machine_shutdown: start, Proess(%s:%d). father %s:%d.\n", 
+               tsk->comm, tsk->pid,tsk->real_parent->comm,tsk->real_parent->pid);
+        }
+       }
+       else
+       {
+         printk("machine_shutdown: start, Proess(%s:%d)\n", tsk->comm, tsk->pid);        
+       }
+
+#ifdef CONFIG_MTK_EMMC_SUPPORT 
+       last_kmsg_store_to_emmc();
+#endif
        if (pm_power_off)
                pm_power_off();
 }
 
 void machine_restart(char *cmd)
 {
-       machine_shutdown();
+       struct task_struct *tsk;        
 
        /* Disable interrupts first */
        local_irq_disable();
        local_fiq_disable();
+       
+       machine_shutdown();
+
+       if(reboot_pid > 1)
+       {
+               tsk = find_task_by_vpid(reboot_pid);
+               if(tsk == NULL)
+                       tsk = current;          
+               dump_stack();
+       }
+       else
+       {
+               tsk = current;
+       }
+
+       if(tsk->real_parent)
+       {
+        if(tsk->real_parent->real_parent)
+        {
+          printk("machine_shutdown: start, Proess(%s:%d). father %s:%d. grandfather %s:%d.\n",
+               tsk->comm, tsk->pid,tsk->real_parent->comm,tsk->real_parent->pid,
+               tsk->real_parent->real_parent->comm,tsk->real_parent->real_parent->pid);
+        }
+        else
+        {
+          printk("machine_shutdown: start, Proess(%s:%d). father %s:%d.\n", 
+               tsk->comm, tsk->pid,tsk->real_parent->comm,tsk->real_parent->pid);
+        }
+       }
+       else
+       {
+         printk("machine_shutdown: start, Proess(%s:%d)\n", tsk->comm, tsk->pid);        
+       }
 
        /* Now call the architecture specific reboot code. */
        if (arm_pm_restart)
                arm_pm_restart('h', cmd);
-
+#ifndef CONFIG_MTK_FPGA
+       else
+               arch_reset('h', cmd);
+#endif
        /*
         * Whoops - the architecture was unable to reboot.
         */
@@ -141,6 +258,70 @@ void machine_restart(char *cmd)
        while (1);
 }
 
+/*
+ * dump a block of kernel memory from around the given address
+ */
+static void show_data(unsigned long addr, int nbytes, const char *name)
+{
+       int     i, j;
+       int     nlines;
+       u32     *p;
+
+       /*
+        * don't attempt to dump non-kernel addresses or
+        * values that are probably just small negative numbers
+        */
+       if (addr < PAGE_OFFSET || addr > -256UL)
+               return;
+
+       printk("\n%s: %#lx:\n", name, addr);
+
+       /*
+        * round address down to a 32 bit boundary
+        * and always dump a multiple of 32 bytes
+        */
+       p = (u32 *)(addr & ~(sizeof(u32) - 1));
+       nbytes += (addr & (sizeof(u32) - 1));
+       nlines = (nbytes + 31) / 32;
+
+
+       for (i = 0; i < nlines; i++) {
+               /*
+                * just display low 16 bits of address to keep
+                * each line of the dump < 80 characters
+                */
+               printk("%04lx ", (unsigned long)p & 0xffff);
+               for (j = 0; j < 8; j++) {
+                       u32     data;
+                       if (probe_kernel_address(p, data)) {
+                               printk(" ********");
+                       } else {
+                               printk(" %08x", data);
+                       }
+                       ++p;
+               }
+               printk("\n");
+       }
+}
+
+static void show_extra_register_data(struct pt_regs *regs, int nbytes)
+{
+       mm_segment_t fs;
+       unsigned int i;
+
+       fs = get_fs();
+       set_fs(KERNEL_DS);
+       show_data(regs->pc - nbytes, nbytes * 2, "PC");
+       show_data(regs->regs[30] - nbytes, nbytes * 2, "LR");
+       show_data(regs->sp - nbytes, nbytes * 2, "SP");
+       for (i = 0; i < 30; i++) {
+               char name[4];
+               snprintf(name, sizeof(name), "X%u", i);
+               show_data(regs->regs[i] - nbytes, nbytes * 2, name);
+       }
+       set_fs(fs);
+}
+
 void __show_regs(struct pt_regs *regs)
 {
        int i;
@@ -156,6 +337,8 @@ void __show_regs(struct pt_regs *regs)
                if (i % 2 == 0)
                        printk("\n");
        }
+       if (!user_mode(regs))
+               show_extra_register_data(regs, 128);
        printk("\n");
 }
 
@@ -202,7 +385,7 @@ void release_thread(struct task_struct *dead_task)
 
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
-       fpsimd_save_state(&current->thread.fpsimd_state);
+       fpsimd_preserve_current_state();
        *dst = *src;
        return 0;
 }