import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm / kernel / process.c
index ac4c2e5e17e4ca5e0e0af30a8d5c70506394ceaa..8832d3939cc525f3941e2d0e96fb3ff14d90aedf 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/cpuidle.h>
 #include <linux/leds.h>
+#include <linux/console.h>
+#include <linux/mtk_ram_console.h>
 
 #include <asm/cacheflush.h>
 #include <asm/idmap.h>
@@ -39,6 +41,7 @@
 #include <asm/thread_notify.h>
 #include <asm/stacktrace.h>
 #include <asm/mach/time.h>
+#include <mach/system.h>
 
 #ifdef CONFIG_CC_STACKPROTECTOR
 #include <linux/stackprotector.h>
@@ -57,9 +60,46 @@ static const char *isa_modes[] = {
   "ARM" , "Thumb" , "Jazelle", "ThumbEE"
 };
 
+#ifdef CONFIG_SMP
+void arch_trigger_all_cpu_backtrace(void)
+{
+       smp_send_all_cpu_backtrace();
+}
+#else
+void arch_trigger_all_cpu_backtrace(void)
+{
+       dump_stack();
+}
+#endif
+
 extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
 typedef void (*phys_reset_t)(unsigned long);
 
+#ifdef CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART
+void arm_machine_flush_console(void)
+{
+       printk("\n");
+       pr_emerg("Restarting %s\n", linux_banner);
+       if (console_trylock()) {
+               console_unlock();
+               return;
+       }
+
+       mdelay(50);
+
+       local_irq_disable();
+       if (!console_trylock())
+               pr_emerg("arm_restart: Console was locked! Busting\n");
+       else
+               pr_emerg("arm_restart: Console was locked!\n");
+       console_unlock();
+}
+#else
+void arm_machine_flush_console(void)
+{
+}
+#endif
+
 /*
  * A temporary stack to use for CPU reset. This is static so that we
  * don't clobber it with the identity mapping. When running with this
@@ -69,6 +109,53 @@ typedef void (*phys_reset_t)(unsigned long);
  */
 static u64 soft_restart_stack[16];
 
+void arm_machine_restart(char mode, const char *cmd)
+{
+        /* Flush the console to make sure all the relevant messages make it
+         * out to the console drivers */
+        arm_machine_flush_console();
+
+        /* Disable interrupts first */
+        local_irq_disable();
+        local_fiq_disable();
+
+        /*
+         * Tell the mm system that we are going to reboot -
+         * we may need it to insert some 1:1 mappings so that
+         * soft boot works.
+         */
+        setup_mm_for_reboot();
+
+        /* When l1 is disabled and l2 is enabled, the spinlock cannot get the lock,
+         * so we need to disable the l2 as well. by Chia-Hao Hsu
+         */
+        outer_flush_all();
+        outer_disable();
+        outer_flush_all();
+
+        /* Clean and invalidate caches */
+        flush_cache_all();
+#ifdef CONFIG_RESTART_DISABLE_CACHE
+        /* Turn off caching */
+ //       cpu_proc_fin();              // Don't turn off cach during reboot phase. CA15 have risk if turn off cach.
+#endif
+        /* Push out any further dirty data, and ensure cache is empty */
+        flush_cache_all();
+
+        /*
+         * Now call the architecture specific reboot code.
+         */
+        arch_reset(mode, cmd);
+
+        /*
+         * Whoops - the architecture was unable to reboot.
+         * Tell the user!
+         */
+        mdelay(1000);
+        printk("Reboot failed -- System halted\n");
+        while (1);
+}
+
 static void __soft_restart(void *addr)
 {
        phys_reset_t phys_reset;
@@ -102,8 +189,10 @@ void soft_restart(unsigned long addr)
        local_fiq_disable();
 
        /* Disable the L2 if we're the last man standing. */
-       if (num_online_cpus() == 1)
+       if (num_online_cpus() == 1) {
+               outer_flush_all();
                outer_disable();
+       }
 
        /* Change to the new stack and continue with the reset. */
        call_with_stack(__soft_restart, (void *)addr, (void *)stack);
@@ -147,6 +236,7 @@ void arch_cpu_idle_prepare(void)
 
 void arch_cpu_idle_enter(void)
 {
+       idle_notifier_call_chain(IDLE_START);
        ledtrig_cpu(CPU_LED_IDLE_START);
 #ifdef CONFIG_PL310_ERRATA_769419
        wmb();
@@ -156,6 +246,7 @@ void arch_cpu_idle_enter(void)
 void arch_cpu_idle_exit(void)
 {
        ledtrig_cpu(CPU_LED_IDLE_END);
+       idle_notifier_call_chain(IDLE_END);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -195,7 +286,20 @@ __setup("reboot=", reboot_setup);
  */
 void machine_shutdown(void)
 {
+#ifdef CONFIG_SMP
+       /*
+        * Disable preemption so we're guaranteed to
+        * run to power off or reboot and prevent
+        * the possibility of switching to another
+        * thread that might wind up blocking on
+        * one of the stopped CPUs.
+        */
+    printk("machine_shutdown: start, Proess(%s:%d)\n", current->comm, current->pid);
+    dump_stack();
+       preempt_disable();
+#endif
        disable_nonboot_cpus();
+    printk("machine_shutdown: done\n");
 }
 
 /*
@@ -211,6 +315,7 @@ void machine_halt(void)
        while (1);
 }
 
+extern int reboot_pid;
 /*
  * Power-off simply requires that the secondary CPUs stop performing any
  * activity (executing tasks, handling interrupts). smp_send_stop()
@@ -219,7 +324,47 @@ void machine_halt(void)
  */
 void machine_power_off(void)
 {
-       smp_send_stop();
+       struct task_struct *tsk;
+
+       /* Disable interrupts first */
+       local_irq_disable();
+       local_fiq_disable();
+       
+       smp_send_stop();        
+       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();
@@ -238,8 +383,48 @@ void machine_power_off(void)
  */
 void machine_restart(char *cmd)
 {
+       struct task_struct *tsk;
+       /* Disable interrupts first */
+       local_irq_disable();
+       local_fiq_disable();
+       
        smp_send_stop();
 
+       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);        
+       }
+
+       /* Flush the console to make sure all the relevant messages make it
+        * out to the console drivers */
+       arm_machine_flush_console();
+
        arm_pm_restart(reboot_mode, cmd);
 
        /* Give a grace period for failure to restart of 1s */
@@ -251,6 +436,77 @@ 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;
+
+       fs = get_fs();
+       set_fs(KERNEL_DS);
+       show_data(regs->ARM_pc - nbytes, nbytes * 2, "PC");
+       show_data(regs->ARM_lr - nbytes, nbytes * 2, "LR");
+       show_data(regs->ARM_sp - nbytes, nbytes * 2, "SP");
+       show_data(regs->ARM_ip - nbytes, nbytes * 2, "IP");
+       show_data(regs->ARM_fp - nbytes, nbytes * 2, "FP");
+       show_data(regs->ARM_r0 - nbytes, nbytes * 2, "R0");
+       show_data(regs->ARM_r1 - nbytes, nbytes * 2, "R1");
+       show_data(regs->ARM_r2 - nbytes, nbytes * 2, "R2");
+       show_data(regs->ARM_r3 - nbytes, nbytes * 2, "R3");
+       show_data(regs->ARM_r4 - nbytes, nbytes * 2, "R4");
+       show_data(regs->ARM_r5 - nbytes, nbytes * 2, "R5");
+       show_data(regs->ARM_r6 - nbytes, nbytes * 2, "R6");
+       show_data(regs->ARM_r7 - nbytes, nbytes * 2, "R7");
+       show_data(regs->ARM_r8 - nbytes, nbytes * 2, "R8");
+       show_data(regs->ARM_r9 - nbytes, nbytes * 2, "R9");
+       show_data(regs->ARM_r10 - nbytes, nbytes * 2, "R10");
+       set_fs(fs);
+}
+
 void __show_regs(struct pt_regs *regs)
 {
        unsigned long flags;
@@ -307,6 +563,8 @@ void __show_regs(struct pt_regs *regs)
                printk("Control: %08x%s\n", ctrl, buf);
        }
 #endif
+
+       show_extra_register_data(regs, 128);
 }
 
 void show_regs(struct pt_regs * regs)