forked from Minki/linux
602bf40971
There is a system hang issue on imx6q which can easily be seen with running a cpu hotplug stress testing (hotplug secondary cores from user space via sysfs interface for thousands iterations). It turns out that the issue is caused by coherency of the cpu that is being shut down. When shutting down a cpu, we need to have the cpu exit coherency to prevent it from receiving cache, TLB, or BTB maintenance operations broadcast by other CPUs in the cluster. Copy cpu_enter_lowpower() and cpu_leave_lowpower() from mach-vexpress to have coherency properly handled in platform_cpu_die(), thus fix the issue. Signed-off-by: Shawn Guo <shawn.guo@linaro.org> Cc: stable@kernel.org
85 lines
1.7 KiB
C
85 lines
1.7 KiB
C
/*
|
|
* Copyright 2011 Freescale Semiconductor, Inc.
|
|
* Copyright 2011 Linaro Ltd.
|
|
*
|
|
* The code contained herein is licensed under the GNU General Public
|
|
* License. You may obtain a copy of the GNU General Public License
|
|
* Version 2 or later at the following locations:
|
|
*
|
|
* http://www.opensource.org/licenses/gpl-license.html
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*/
|
|
|
|
#include <linux/errno.h>
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/cp15.h>
|
|
#include <mach/common.h>
|
|
|
|
int platform_cpu_kill(unsigned int cpu)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static inline void cpu_enter_lowpower(void)
|
|
{
|
|
unsigned int v;
|
|
|
|
flush_cache_all();
|
|
asm volatile(
|
|
"mcr p15, 0, %1, c7, c5, 0\n"
|
|
" mcr p15, 0, %1, c7, c10, 4\n"
|
|
/*
|
|
* Turn off coherency
|
|
*/
|
|
" mrc p15, 0, %0, c1, c0, 1\n"
|
|
" bic %0, %0, %3\n"
|
|
" mcr p15, 0, %0, c1, c0, 1\n"
|
|
" mrc p15, 0, %0, c1, c0, 0\n"
|
|
" bic %0, %0, %2\n"
|
|
" mcr p15, 0, %0, c1, c0, 0\n"
|
|
: "=&r" (v)
|
|
: "r" (0), "Ir" (CR_C), "Ir" (0x40)
|
|
: "cc");
|
|
}
|
|
|
|
static inline void cpu_leave_lowpower(void)
|
|
{
|
|
unsigned int v;
|
|
|
|
asm volatile(
|
|
"mrc p15, 0, %0, c1, c0, 0\n"
|
|
" orr %0, %0, %1\n"
|
|
" mcr p15, 0, %0, c1, c0, 0\n"
|
|
" mrc p15, 0, %0, c1, c0, 1\n"
|
|
" orr %0, %0, %2\n"
|
|
" mcr p15, 0, %0, c1, c0, 1\n"
|
|
: "=&r" (v)
|
|
: "Ir" (CR_C), "Ir" (0x40)
|
|
: "cc");
|
|
}
|
|
|
|
/*
|
|
* platform-specific code to shutdown a CPU
|
|
*
|
|
* Called with IRQs disabled
|
|
*/
|
|
void platform_cpu_die(unsigned int cpu)
|
|
{
|
|
cpu_enter_lowpower();
|
|
imx_enable_cpu(cpu, false);
|
|
cpu_do_idle();
|
|
cpu_leave_lowpower();
|
|
|
|
/* We should never return from idle */
|
|
panic("cpu %d unexpectedly exit from shutdown\n", cpu);
|
|
}
|
|
|
|
int platform_cpu_disable(unsigned int cpu)
|
|
{
|
|
/*
|
|
* we don't allow CPU 0 to be shutdown (it is still too special
|
|
* e.g. clock tick interrupts)
|
|
*/
|
|
return cpu == 0 ? -EPERM : 0;
|
|
}
|