Skip to content

Commit

Permalink
[ARM] 3881/4: xscale: clean up cp0/cp1 handling
Browse files Browse the repository at this point in the history
XScale cores either have a DSP coprocessor (which contains a single
40 bit accumulator register), or an iWMMXt coprocessor (which contains
eight 64 bit registers.)

Because of the small amount of state in the DSP coprocessor, access to
the DSP coprocessor (CP0) is always enabled, and DSP context switching
is done unconditionally on every task switch.  Access to the iWMMXt
coprocessor (CP0/CP1) is enabled only when an iWMMXt instruction is
first issued, and iWMMXt context switching is done lazily.

CONFIG_IWMMXT is supposed to mean 'the cpu we will be running on will
have iWMMXt support', but boards are supposed to select this config
symbol by hand, and at least one pxa27x board doesn't get this right,
so on that board, proc-xscale.S will incorrectly assume that we have a
DSP coprocessor, enable CP0 on boot, and we will then only save the
first iWMMXt register (wR0) on context switches, which is Bad.

This patch redefines CONFIG_IWMMXT as 'the cpu we will be running on
might have iWMMXt support, and we will enable iWMMXt context switching
if it does.'  This means that with this patch, running a CONFIG_IWMMXT=n
kernel on an iWMMXt-capable CPU will no longer potentially corrupt iWMMXt
state over context switches, and running a CONFIG_IWMMXT=y kernel on a
non-iWMMXt capable CPU will still do DSP context save/restore.

These changes should make iWMMXt work on PXA3xx, and as a side effect,
enable proper acc0 save/restore on non-iWMMXt capable xsc3 cores such
as IOP13xx and IXP23xx (which will not have CONFIG_CPU_XSCALE defined),
as well as setting and using HWCAP_IWMMXT properly.

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Acked-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Lennert Buytenhek authored and Russell King committed Dec 3, 2006
1 parent f523622 commit afe4b25
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 124 deletions.
8 changes: 8 additions & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,14 @@ config PLAT_IOP

source arch/arm/mm/Kconfig

config IWMMXT
bool "Enable iWMMXt support"
depends CPU_XSCALE || CPU_XSC3
default y if PXA27x
help
Enable support for iWMMXt context switching at run time if
running on a CPU that supports it.

# bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER
config XSCALE_PMU
bool
Expand Down
4 changes: 3 additions & 1 deletion arch/arm/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o
AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312

obj-$(CONFIG_IWMMXT) += iwmmxt.o iwmmxt-notifier.o
obj-$(CONFIG_CPU_XSCALE) += xscale-cp0.o
obj-$(CONFIG_CPU_XSC3) += xscale-cp0.o
obj-$(CONFIG_IWMMXT) += iwmmxt.o
AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt

ifneq ($(CONFIG_ARCH_EBSA110),y)
Expand Down
9 changes: 0 additions & 9 deletions arch/arm/kernel/entry-armv.S
Original file line number Diff line number Diff line change
Expand Up @@ -589,10 +589,6 @@ ENTRY(__switch_to)
strex r5, r4, [ip] @ Clear exclusive monitor
#endif
#endif
#if defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_IWMMXT)
mra r4, r5, acc0
stmia ip, {r4, r5}
#endif
#if defined(CONFIG_HAS_TLS_REG)
mcr p15, 0, r3, c13, c0, 3 @ set TLS register
#elif !defined(CONFIG_TLS_REG_EMUL)
Expand All @@ -601,11 +597,6 @@ ENTRY(__switch_to)
#endif
#ifdef CONFIG_MMU
mcr p15, 0, r6, c3, c0, 0 @ Set domain register
#endif
#if defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_IWMMXT)
add r4, r2, #TI_CPU_DOMAIN + 40 @ cpu_context_save->extra
ldmib r4, {r4, r5}
mar acc0, r4, r5
#endif
mov r5, r0
add r4, r2, #TI_CPU_SAVE
Expand Down
63 changes: 0 additions & 63 deletions arch/arm/kernel/iwmmxt-notifier.c

This file was deleted.

3 changes: 0 additions & 3 deletions arch/arm/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,9 +357,6 @@ static void __init setup_processor(void)
#ifndef CONFIG_VFP
elf_hwcap &= ~HWCAP_VFP;
#endif
#ifndef CONFIG_IWMMXT
elf_hwcap &= ~HWCAP_IWMMXT;
#endif

cpu_proc_init();
}
Expand Down
179 changes: 179 additions & 0 deletions arch/arm/kernel/xscale-cp0.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
* linux/arch/arm/kernel/xscale-cp0.c
*
* XScale DSP and iWMMXt coprocessor context switching and handling
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/

#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/thread_notify.h>
#include <asm/io.h>

static inline void dsp_save_state(u32 *state)
{
__asm__ __volatile__ (
"mrrc p0, 0, %0, %1, c0\n"
: "=r" (state[0]), "=r" (state[1]));
}

static inline void dsp_load_state(u32 *state)
{
__asm__ __volatile__ (
"mcrr p0, 0, %0, %1, c0\n"
: : "r" (state[0]), "r" (state[1]));
}

static int dsp_do(struct notifier_block *self, unsigned long cmd, void *t)
{
struct thread_info *thread = t;

switch (cmd) {
case THREAD_NOTIFY_FLUSH:
thread->cpu_context.extra[0] = 0;
thread->cpu_context.extra[1] = 0;
break;

case THREAD_NOTIFY_SWITCH:
dsp_save_state(current_thread_info()->cpu_context.extra);
dsp_load_state(thread->cpu_context.extra);
break;
}

return NOTIFY_DONE;
}

static struct notifier_block dsp_notifier_block = {
.notifier_call = dsp_do,
};


#ifdef CONFIG_IWMMXT
static int iwmmxt_do(struct notifier_block *self, unsigned long cmd, void *t)
{
struct thread_info *thread = t;

switch (cmd) {
case THREAD_NOTIFY_FLUSH:
/*
* flush_thread() zeroes thread->fpstate, so no need
* to do anything here.
*
* FALLTHROUGH: Ensure we don't try to overwrite our newly
* initialised state information on the first fault.
*/

case THREAD_NOTIFY_RELEASE:
iwmmxt_task_release(thread);
break;

case THREAD_NOTIFY_SWITCH:
iwmmxt_task_switch(thread);
break;
}

return NOTIFY_DONE;
}

static struct notifier_block iwmmxt_notifier_block = {
.notifier_call = iwmmxt_do,
};
#endif


static u32 __init xscale_cp_access_read(void)
{
u32 value;

__asm__ __volatile__ (
"mrc p15, 0, %0, c15, c1, 0\n\t"
: "=r" (value));

return value;
}

static void __init xscale_cp_access_write(u32 value)
{
u32 temp;

__asm__ __volatile__ (
"mcr p15, 0, %1, c15, c1, 0\n\t"
"mrc p15, 0, %0, c15, c1, 0\n\t"
"mov %0, %0\n\t"
"sub pc, pc, #4\n\t"
: "=r" (temp) : "r" (value));
}

/*
* Detect whether we have a MAC coprocessor (40 bit register) or an
* iWMMXt coprocessor (64 bit registers) by loading 00000100:00000000
* into a coprocessor register and reading it back, and checking
* whether the upper word survived intact.
*/
static int __init cpu_has_iwmmxt(void)
{
u32 lo;
u32 hi;

/*
* This sequence is interpreted by the DSP coprocessor as:
* mar acc0, %2, %3
* mra %0, %1, acc0
*
* And by the iWMMXt coprocessor as:
* tmcrr wR0, %2, %3
* tmrrc %0, %1, wR0
*/
__asm__ __volatile__ (
"mcrr p0, 0, %2, %3, c0\n"
"mrrc p0, 0, %0, %1, c0\n"
: "=r" (lo), "=r" (hi)
: "r" (0), "r" (0x100));

return !!hi;
}


/*
* If we detect that the CPU has iWMMXt (and CONFIG_IWMMXT=y), we
* disable CP0/CP1 on boot, and let call_fpe() and the iWMMXt lazy
* switch code handle iWMMXt context switching. If on the other
* hand the CPU has a DSP coprocessor, we keep access to CP0 enabled
* all the time, and save/restore acc0 on context switch in non-lazy
* fashion.
*/
static int __init xscale_cp0_init(void)
{
u32 cp_access;

cp_access = xscale_cp_access_read() & ~3;
xscale_cp_access_write(cp_access | 1);

if (cpu_has_iwmmxt()) {
#ifndef CONFIG_IWMMXT
printk(KERN_WARNING "CAUTION: XScale iWMMXt coprocessor "
"detected, but kernel support is missing.\n");
#else
printk(KERN_INFO "XScale iWMMXt coprocessor detected.\n");
elf_hwcap |= HWCAP_IWMMXT;
thread_register_notifier(&iwmmxt_notifier_block);
#endif
} else {
printk(KERN_INFO "XScale DSP coprocessor detected.\n");
thread_register_notifier(&dsp_notifier_block);
cp_access |= 1;
}

xscale_cp_access_write(cp_access);

return 0;
}

late_initcall(xscale_cp0_init);
8 changes: 0 additions & 8 deletions arch/arm/mach-pxa/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@ config ARCH_LUBBOCK
config MACH_LOGICPD_PXA270
bool "LogicPD PXA270 Card Engine Development Platform"
select PXA27x
select IWMMXT

config MACH_MAINSTONE
bool "Intel HCDDBBVA0 Development Platform"
select PXA27x
select IWMMXT

config ARCH_PXA_IDP
bool "Accelent Xscale IDP"
Expand Down Expand Up @@ -53,7 +51,6 @@ config PXA_SHARPSL_25x
config PXA_SHARPSL_27x
bool "Sharp PXA270 models (SL-Cxx00)"
select PXA27x
select IWMMXT

endchoice

Expand Down Expand Up @@ -129,11 +126,6 @@ config PXA27x
help
Select code specific to PXA27x variants

config IWMMXT
bool
help
Enable support for iWMMXt

config PXA_SHARP_C7xx
bool
select PXA_SSP
Expand Down
3 changes: 2 additions & 1 deletion arch/arm/mach-pxa/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ int pxa_pm_enter(suspend_state_t state)

#ifdef CONFIG_IWMMXT
/* force any iWMMXt context to ram **/
iwmmxt_task_disable(NULL);
if (elf_hwcap & HWCAP_IWMMXT)
iwmmxt_task_disable(NULL);
#endif

/* preserve current time */
Expand Down
9 changes: 2 additions & 7 deletions arch/arm/mm/proc-xscale.S
Original file line number Diff line number Diff line change
Expand Up @@ -491,12 +491,7 @@ __xscale_setup:
mcr p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB
mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
mcr p15, 0, ip, c8, c7, 0 @ invalidate I, D TLBs
#ifdef CONFIG_IWMMXT
mov r0, #0 @ initially disallow access to CP0/CP1
#else
mov r0, #1 @ Allow access to CP0
#endif
orr r0, r0, #1 << 6 @ cp6 for IOP3xx and Bulverde
mov r0, #1 << 6 @ cp6 for IOP3xx and Bulverde
orr r0, r0, #1 << 13 @ Its undefined whether this
mcr p15, 0, r0, c15, c1, 0 @ affects USR or SVC modes

Expand Down Expand Up @@ -909,7 +904,7 @@ __pxa270_proc_info:
b __xscale_setup
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_IWMMXT
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
.long cpu_pxa270_name
.long xscale_processor_functions
.long v4wbi_tlb_fns
Expand Down
Loading

0 comments on commit afe4b25

Please sign in to comment.