MIPS: Get rid of the use of .macro in C code.

It fails with LTO and probably has always been a fragile.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
Ralf Baechle 2013-02-08 18:13:30 +01:00
parent 0bfbf6a256
commit 02b849f761
3 changed files with 411 additions and 278 deletions

View File

@ -10,34 +10,13 @@
#ifndef _ASM_HAZARDS_H
#define _ASM_HAZARDS_H
#ifdef __ASSEMBLY__
#define ASMMACRO(name, code...) .macro name; code; .endm
#else
#include <linux/stringify.h>
#include <asm/cpu-features.h>
#define ___ssnop \
sll $0, $0, 1
#define ASMMACRO(name, code...) \
__asm__(".macro " #name "; " #code "; .endm"); \
\
static inline void name(void) \
{ \
__asm__ __volatile__ (#name); \
}
/*
* MIPS R2 instruction hazard barrier. Needs to be called as a subroutine.
*/
extern void mips_ihb(void);
#endif
ASMMACRO(_ssnop,
sll $0, $0, 1
)
ASMMACRO(_ehb,
sll $0, $0, 3
)
#define ___ehb \
sll $0, $0, 3
/*
* TLB hazards
@ -48,24 +27,24 @@ ASMMACRO(_ehb,
* MIPSR2 defines ehb for hazard avoidance
*/
ASMMACRO(mtc0_tlbw_hazard,
_ehb
)
ASMMACRO(tlbw_use_hazard,
_ehb
)
ASMMACRO(tlb_probe_hazard,
_ehb
)
ASMMACRO(irq_enable_hazard,
_ehb
)
ASMMACRO(irq_disable_hazard,
_ehb
)
ASMMACRO(back_to_back_c0_hazard,
_ehb
)
#define __mtc0_tlbw_hazard \
___ehb
#define __tlbw_use_hazard \
___ehb
#define __tlb_probe_hazard \
___ehb
#define __irq_enable_hazard \
___ehb
#define __irq_disable_hazard \
___ehb
#define __back_to_back_c0_hazard \
___ehb
/*
* gcc has a tradition of misscompiling the previous construct using the
* address of a label as argument to inline assembler. Gas otoh has the
@ -94,24 +73,42 @@ do { \
* These are slightly complicated by the fact that we guarantee R1 kernels to
* run fine on R2 processors.
*/
ASMMACRO(mtc0_tlbw_hazard,
_ssnop; _ssnop; _ehb
)
ASMMACRO(tlbw_use_hazard,
_ssnop; _ssnop; _ssnop; _ehb
)
ASMMACRO(tlb_probe_hazard,
_ssnop; _ssnop; _ssnop; _ehb
)
ASMMACRO(irq_enable_hazard,
_ssnop; _ssnop; _ssnop; _ehb
)
ASMMACRO(irq_disable_hazard,
_ssnop; _ssnop; _ssnop; _ehb
)
ASMMACRO(back_to_back_c0_hazard,
_ssnop; _ssnop; _ssnop; _ehb
)
#define __mtc0_tlbw_hazard \
___ssnop; \
___ssnop; \
___ehb
#define __tlbw_use_hazard \
___ssnop; \
___ssnop; \
___ssnop; \
___ehb
#define __tlb_probe_hazard \
___ssnop; \
___ssnop; \
___ssnop; \
___ehb
#define __irq_enable_hazard \
___ssnop; \
___ssnop; \
___ssnop; \
___ehb
#define __irq_disable_hazard \
___ssnop; \
___ssnop; \
___ssnop; \
___ehb
#define __back_to_back_c0_hazard \
___ssnop; \
___ssnop; \
___ssnop; \
___ehb
/*
* gcc has a tradition of misscompiling the previous construct using the
* address of a label as argument to inline assembler. Gas otoh has the
@ -147,18 +144,18 @@ do { \
* R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
*/
ASMMACRO(mtc0_tlbw_hazard,
)
ASMMACRO(tlbw_use_hazard,
)
ASMMACRO(tlb_probe_hazard,
)
ASMMACRO(irq_enable_hazard,
)
ASMMACRO(irq_disable_hazard,
)
ASMMACRO(back_to_back_c0_hazard,
)
#define __mtc0_tlbw_hazard
#define __tlbw_use_hazard
#define __tlb_probe_hazard
#define __irq_enable_hazard
#define __irq_disable_hazard
#define __back_to_back_c0_hazard
#define instruction_hazard() do { } while (0)
#elif defined(CONFIG_CPU_SB1)
@ -166,19 +163,21 @@ ASMMACRO(back_to_back_c0_hazard,
/*
* Mostly like R4000 for historic reasons
*/
ASMMACRO(mtc0_tlbw_hazard,
)
ASMMACRO(tlbw_use_hazard,
)
ASMMACRO(tlb_probe_hazard,
)
ASMMACRO(irq_enable_hazard,
)
ASMMACRO(irq_disable_hazard,
_ssnop; _ssnop; _ssnop
)
ASMMACRO(back_to_back_c0_hazard,
)
#define __mtc0_tlbw_hazard
#define __tlbw_use_hazard
#define __tlb_probe_hazard
#define __irq_enable_hazard
#define __irq_disable_hazard \
___ssnop; \
___ssnop; \
___ssnop
#define __back_to_back_c0_hazard
#define instruction_hazard() do { } while (0)
#else
@ -192,24 +191,35 @@ ASMMACRO(back_to_back_c0_hazard,
* hazard so this is nice trick to have an optimal code for a range of
* processors.
*/
ASMMACRO(mtc0_tlbw_hazard,
nop; nop
)
ASMMACRO(tlbw_use_hazard,
nop; nop; nop
)
ASMMACRO(tlb_probe_hazard,
nop; nop; nop
)
ASMMACRO(irq_enable_hazard,
_ssnop; _ssnop; _ssnop;
)
ASMMACRO(irq_disable_hazard,
nop; nop; nop
)
ASMMACRO(back_to_back_c0_hazard,
_ssnop; _ssnop; _ssnop;
)
#define __mtc0_tlbw_hazard \
nop; \
nop
#define __tlbw_use_hazard \
nop; \
nop; \
nop
#define __tlb_probe_hazard \
nop; \
nop; \
nop
#define __irq_enable_hazard \
___ssnop; \
___ssnop; \
___ssnop
#define __irq_disable_hazard \
nop; \
nop; \
nop
#define __back_to_back_c0_hazard \
___ssnop; \
___ssnop; \
___ssnop
#define instruction_hazard() do { } while (0)
#endif
@ -218,32 +228,137 @@ ASMMACRO(back_to_back_c0_hazard,
/* FPU hazards */
#if defined(CONFIG_CPU_SB1)
ASMMACRO(enable_fpu_hazard,
.set push;
.set mips64;
.set noreorder;
_ssnop;
bnezl $0, .+4;
_ssnop;
.set pop
)
ASMMACRO(disable_fpu_hazard,
)
#define __enable_fpu_hazard \
.set push; \
.set mips64; \
.set noreorder; \
___ssnop; \
bnezl $0, .+4; \
___ssnop; \
.set pop
#define __disable_fpu_hazard
#elif defined(CONFIG_CPU_MIPSR2)
ASMMACRO(enable_fpu_hazard,
_ehb
)
ASMMACRO(disable_fpu_hazard,
_ehb
)
#define __enable_fpu_hazard \
___ehb
#define __disable_fpu_hazard \
___ehb
#else
ASMMACRO(enable_fpu_hazard,
nop; nop; nop; nop
)
ASMMACRO(disable_fpu_hazard,
_ehb
)
#define __enable_fpu_hazard \
nop; \
nop; \
nop; \
nop
#define __disable_fpu_hazard \
___ehb
#endif
#ifdef __ASSEMBLY__
#define _ssnop ___ssnop
#define _ehb ___ehb
#define mtc0_tlbw_hazard __mtc0_tlbw_hazard
#define tlbw_use_hazard __tlbw_use_hazard
#define tlb_probe_hazard __tlb_probe_hazard
#define irq_enable_hazard __irq_enable_hazard
#define irq_disable_hazard __irq_disable_hazard
#define back_to_back_c0_hazard __back_to_back_c0_hazard
#define enable_fpu_hazard __enable_fpu_hazard
#define disable_fpu_hazard __disable_fpu_hazard
#else
#define _ssnop() \
do { \
__asm__ __volatile__( \
__stringify(___ssnop) \
); \
} while (0)
#define _ehb() \
do { \
__asm__ __volatile__( \
__stringify(___ehb) \
); \
} while (0)
#define mtc0_tlbw_hazard() \
do { \
__asm__ __volatile__( \
__stringify(__mtc0_tlbw_hazard) \
); \
} while (0)
#define tlbw_use_hazard() \
do { \
__asm__ __volatile__( \
__stringify(__tlbw_use_hazard) \
); \
} while (0)
#define tlb_probe_hazard() \
do { \
__asm__ __volatile__( \
__stringify(__tlb_probe_hazard) \
); \
} while (0)
#define irq_enable_hazard() \
do { \
__asm__ __volatile__( \
__stringify(__irq_enable_hazard) \
); \
} while (0)
#define irq_disable_hazard() \
do { \
__asm__ __volatile__( \
__stringify(__irq_disable_hazard) \
); \
} while (0)
#define back_to_back_c0_hazard() \
do { \
__asm__ __volatile__( \
__stringify(__back_to_back_c0_hazard) \
); \
} while (0)
#define enable_fpu_hazard() \
do { \
__asm__ __volatile__( \
__stringify(__enable_fpu_hazard) \
); \
} while (0)
#define disable_fpu_hazard() \
do { \
__asm__ __volatile__( \
__stringify(__disable_fpu_hazard) \
); \
} while (0)
/*
* MIPS R2 instruction hazard barrier. Needs to be called as a subroutine.
*/
extern void mips_ihb(void);
#endif /* __ASSEMBLY__ */
#endif /* _ASM_HAZARDS_H */

View File

@ -14,53 +14,48 @@
#ifndef __ASSEMBLY__
#include <linux/compiler.h>
#include <linux/stringify.h>
#include <asm/hazards.h>
#if defined(CONFIG_CPU_MIPSR2) && !defined(CONFIG_MIPS_MT_SMTC)
__asm__(
" .macro arch_local_irq_disable\n"
" .set push \n"
" .set noat \n"
" di \n"
" irq_disable_hazard \n"
" .set pop \n"
" .endm \n");
static inline void arch_local_irq_disable(void)
{
__asm__ __volatile__(
"arch_local_irq_disable"
: /* no outputs */
: /* no inputs */
: "memory");
}
__asm__(
" .macro arch_local_irq_save result \n"
" .set push \n"
" .set reorder \n"
" .set noat \n"
" di \\result \n"
" andi \\result, 1 \n"
" irq_disable_hazard \n"
" di \n"
" " __stringify(__irq_disable_hazard) " \n"
" .set pop \n"
" .endm \n");
: /* no outputs */
: /* no inputs */
: "memory");
}
static inline unsigned long arch_local_irq_save(void)
{
unsigned long flags;
asm volatile("arch_local_irq_save\t%0"
: "=r" (flags)
: /* no inputs */
: "memory");
asm __volatile__(
" .set push \n"
" .set reorder \n"
" .set noat \n"
" di %[flags] \n"
" andi %[flags], 1 \n"
" " __stringify(__irq_disable_hazard) " \n"
" .set pop \n"
: [flags] "=r" (flags)
: /* no inputs */
: "memory");
return flags;
}
static inline void arch_local_irq_restore(unsigned long flags)
{
unsigned long __tmp1;
__asm__(
" .macro arch_local_irq_restore flags \n"
__asm__ __volatile__(
" .set push \n"
" .set noreorder \n"
" .set noat \n"
@ -69,7 +64,7 @@ __asm__(
* Slow, but doesn't suffer from a relatively unlikely race
* condition we're having since days 1.
*/
" beqz \\flags, 1f \n"
" beqz %[flags], 1f \n"
" di \n"
" ei \n"
"1: \n"
@ -78,33 +73,44 @@ __asm__(
* Fast, dangerous. Life is fun, life is good.
*/
" mfc0 $1, $12 \n"
" ins $1, \\flags, 0, 1 \n"
" ins $1, %[flags], 0, 1 \n"
" mtc0 $1, $12 \n"
#endif
" irq_disable_hazard \n"
" " __stringify(__irq_disable_hazard) " \n"
" .set pop \n"
" .endm \n");
static inline void arch_local_irq_restore(unsigned long flags)
{
unsigned long __tmp1;
__asm__ __volatile__(
"arch_local_irq_restore\t%0"
: "=r" (__tmp1)
: "0" (flags)
: "memory");
: [flags] "=r" (__tmp1)
: "0" (flags)
: "memory");
}
static inline void __arch_local_irq_restore(unsigned long flags)
{
unsigned long __tmp1;
__asm__ __volatile__(
"arch_local_irq_restore\t%0"
: "=r" (__tmp1)
: "0" (flags)
: "memory");
" .set push \n"
" .set noreorder \n"
" .set noat \n"
#if defined(CONFIG_IRQ_CPU)
/*
* Slow, but doesn't suffer from a relatively unlikely race
* condition we're having since days 1.
*/
" beqz %[flags], 1f \n"
" di \n"
" ei \n"
"1: \n"
#else
/*
* Fast, dangerous. Life is fun, life is good.
*/
" mfc0 $1, $12 \n"
" ins $1, %[flags], 0, 1 \n"
" mtc0 $1, $12 \n"
#endif
" " __stringify(__irq_disable_hazard) " \n"
" .set pop \n"
: [flags] "=r" (flags)
: "0" (flags)
: "memory");
}
#else
/* Functions that require preempt_{dis,en}able() are in mips-atomic.c */
@ -115,8 +121,18 @@ void __arch_local_irq_restore(unsigned long flags);
#endif /* if defined(CONFIG_CPU_MIPSR2) && !defined(CONFIG_MIPS_MT_SMTC) */
__asm__(
" .macro arch_local_irq_enable \n"
extern void smtc_ipi_replay(void);
static inline void arch_local_irq_enable(void)
{
#ifdef CONFIG_MIPS_MT_SMTC
/*
* SMTC kernel needs to do a software replay of queued
* IPIs, at the cost of call overhead on each local_irq_enable()
*/
smtc_ipi_replay();
#endif
__asm__ __volatile__(
" .set push \n"
" .set reorder \n"
" .set noat \n"
@ -133,45 +149,28 @@ __asm__(
" xori $1,0x1e \n"
" mtc0 $1,$12 \n"
#endif
" irq_enable_hazard \n"
" " __stringify(__irq_enable_hazard) " \n"
" .set pop \n"
" .endm");
extern void smtc_ipi_replay(void);
static inline void arch_local_irq_enable(void)
{
#ifdef CONFIG_MIPS_MT_SMTC
/*
* SMTC kernel needs to do a software replay of queued
* IPIs, at the cost of call overhead on each local_irq_enable()
*/
smtc_ipi_replay();
#endif
__asm__ __volatile__(
"arch_local_irq_enable"
: /* no outputs */
: /* no inputs */
: "memory");
: /* no outputs */
: /* no inputs */
: "memory");
}
__asm__(
" .macro arch_local_save_flags flags \n"
" .set push \n"
" .set reorder \n"
#ifdef CONFIG_MIPS_MT_SMTC
" mfc0 \\flags, $2, 1 \n"
#else
" mfc0 \\flags, $12 \n"
#endif
" .set pop \n"
" .endm \n");
static inline unsigned long arch_local_save_flags(void)
{
unsigned long flags;
asm volatile("arch_local_save_flags %0" : "=r" (flags));
asm __volatile__(
" .set push \n"
" .set reorder \n"
#ifdef CONFIG_MIPS_MT_SMTC
" mfc0 %[flags], $2, 1 \n"
#else
" mfc0 %[flags], $12 \n"
#endif
" .set pop \n"
: [flags] "=r" (flags));
return flags;
}

View File

@ -13,6 +13,7 @@
#include <linux/compiler.h>
#include <linux/preempt.h>
#include <linux/export.h>
#include <linux/stringify.h>
#if !defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT_SMTC)
@ -34,8 +35,11 @@
*
* Workaround: mask EXL bit of the result or place a nop before mfc0.
*/
__asm__(
" .macro arch_local_irq_disable\n"
notrace void arch_local_irq_disable(void)
{
preempt_disable();
__asm__ __volatile__(
" .set push \n"
" .set noat \n"
#ifdef CONFIG_MIPS_MT_SMTC
@ -52,89 +56,54 @@ __asm__(
" .set noreorder \n"
" mtc0 $1,$12 \n"
#endif
" irq_disable_hazard \n"
" " __stringify(__irq_disable_hazard) " \n"
" .set pop \n"
" .endm \n");
: /* no outputs */
: /* no inputs */
: "memory");
notrace void arch_local_irq_disable(void)
{
preempt_disable();
__asm__ __volatile__(
"arch_local_irq_disable"
: /* no outputs */
: /* no inputs */
: "memory");
preempt_enable();
}
EXPORT_SYMBOL(arch_local_irq_disable);
__asm__(
" .macro arch_local_irq_save result \n"
notrace unsigned long arch_local_irq_save(void)
{
unsigned long flags;
preempt_disable();
__asm__ __volatile__(
" .set push \n"
" .set reorder \n"
" .set noat \n"
#ifdef CONFIG_MIPS_MT_SMTC
" mfc0 \\result, $2, 1 \n"
" ori $1, \\result, 0x400 \n"
" mfc0 %[flags], $2, 1 \n"
" ori $1, %[flags], 0x400 \n"
" .set noreorder \n"
" mtc0 $1, $2, 1 \n"
" andi \\result, \\result, 0x400 \n"
" andi %[flags], %[flags], 0x400 \n"
#elif defined(CONFIG_CPU_MIPSR2)
/* see irqflags.h for inline function */
#else
" mfc0 \\result, $12 \n"
" ori $1, \\result, 0x1f \n"
" mfc0 %[flags], $12 \n"
" ori $1, %[flags], 0x1f \n"
" xori $1, 0x1f \n"
" .set noreorder \n"
" mtc0 $1, $12 \n"
#endif
" irq_disable_hazard \n"
" " __stringify(__irq_disable_hazard) " \n"
" .set pop \n"
" .endm \n");
: [flags] "=r" (flags)
: /* no inputs */
: "memory");
notrace unsigned long arch_local_irq_save(void)
{
unsigned long flags;
preempt_disable();
asm volatile("arch_local_irq_save\t%0"
: "=r" (flags)
: /* no inputs */
: "memory");
preempt_enable();
return flags;
}
EXPORT_SYMBOL(arch_local_irq_save);
__asm__(
" .macro arch_local_irq_restore flags \n"
" .set push \n"
" .set noreorder \n"
" .set noat \n"
#ifdef CONFIG_MIPS_MT_SMTC
"mfc0 $1, $2, 1 \n"
"andi \\flags, 0x400 \n"
"ori $1, 0x400 \n"
"xori $1, 0x400 \n"
"or \\flags, $1 \n"
"mtc0 \\flags, $2, 1 \n"
#elif defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU)
/* see irqflags.h for inline function */
#elif defined(CONFIG_CPU_MIPSR2)
/* see irqflags.h for inline function */
#else
" mfc0 $1, $12 \n"
" andi \\flags, 1 \n"
" ori $1, 0x1f \n"
" xori $1, 0x1f \n"
" or \\flags, $1 \n"
" mtc0 \\flags, $12 \n"
#endif
" irq_disable_hazard \n"
" .set pop \n"
" .endm \n");
notrace void arch_local_irq_restore(unsigned long flags)
{
unsigned long __tmp1;
@ -149,11 +118,36 @@ notrace void arch_local_irq_restore(unsigned long flags)
smtc_ipi_replay();
#endif
preempt_disable();
__asm__ __volatile__(
"arch_local_irq_restore\t%0"
: "=r" (__tmp1)
: "0" (flags)
: "memory");
" .set push \n"
" .set noreorder \n"
" .set noat \n"
#ifdef CONFIG_MIPS_MT_SMTC
" mfc0 $1, $2, 1 \n"
" andi %[flags], 0x400 \n"
" ori $1, 0x400 \n"
" xori $1, 0x400 \n"
" or %[flags], $1 \n"
" mtc0 %[flags], $2, 1 \n"
#elif defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU)
/* see irqflags.h for inline function */
#elif defined(CONFIG_CPU_MIPSR2)
/* see irqflags.h for inline function */
#else
" mfc0 $1, $12 \n"
" andi %[flags], 1 \n"
" ori $1, 0x1f \n"
" xori $1, 0x1f \n"
" or %[flags], $1 \n"
" mtc0 %[flags], $12 \n"
#endif
" " __stringify(__irq_disable_hazard) " \n"
" .set pop \n"
: [flags] "=r" (__tmp1)
: "0" (flags)
: "memory");
preempt_enable();
}
EXPORT_SYMBOL(arch_local_irq_restore);
@ -164,11 +158,36 @@ notrace void __arch_local_irq_restore(unsigned long flags)
unsigned long __tmp1;
preempt_disable();
__asm__ __volatile__(
"arch_local_irq_restore\t%0"
: "=r" (__tmp1)
: "0" (flags)
: "memory");
" .set push \n"
" .set noreorder \n"
" .set noat \n"
#ifdef CONFIG_MIPS_MT_SMTC
" mfc0 $1, $2, 1 \n"
" andi %[flags], 0x400 \n"
" ori $1, 0x400 \n"
" xori $1, 0x400 \n"
" or %[flags], $1 \n"
" mtc0 %[flags], $2, 1 \n"
#elif defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU)
/* see irqflags.h for inline function */
#elif defined(CONFIG_CPU_MIPSR2)
/* see irqflags.h for inline function */
#else
" mfc0 $1, $12 \n"
" andi %[flags], 1 \n"
" ori $1, 0x1f \n"
" xori $1, 0x1f \n"
" or %[flags], $1 \n"
" mtc0 %[flags], $12 \n"
#endif
" " __stringify(__irq_disable_hazard) " \n"
" .set pop \n"
: [flags] "=r" (__tmp1)
: "0" (flags)
: "memory");
preempt_enable();
}
EXPORT_SYMBOL(__arch_local_irq_restore);