2005-04-16 15:20:36 -07:00
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
2007-07-28 00:49:58 +01:00
* Copyright ( C ) 2003 , 04 , 07 Ralf Baechle < ralf @ linux - mips . org >
2006-03-13 16:16:29 +00:00
* Copyright ( C ) MIPS Technologies , Inc .
* written by Ralf Baechle < ralf @ linux - mips . org >
2005-04-16 15:20:36 -07:00
*/
# ifndef _ASM_HAZARDS_H
# define _ASM_HAZARDS_H
2013-02-08 18:13:30 +01:00
# include <linux/stringify.h>
2014-11-13 11:52:22 +00:00
# include <asm/compiler.h>
2005-04-16 15:20:36 -07:00
2013-02-08 18:13:30 +01:00
# define ___ssnop \
sll $ 0 , $ 0 , 1
2006-09-08 04:13:49 +02:00
2013-02-08 18:13:30 +01:00
# define ___ehb \
sll $ 0 , $ 0 , 3
2006-09-08 04:13:49 +02:00
2005-04-16 15:20:36 -07:00
/*
2006-09-08 04:13:49 +02:00
* TLB hazards
2005-04-16 15:20:36 -07:00
*/
2014-11-13 11:52:22 +00:00
# if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) && !defined(CONFIG_CPU_CAVIUM_OCTEON)
2005-04-16 15:20:36 -07:00
/*
2006-09-08 04:13:49 +02:00
* MIPSR2 defines ehb for hazard avoidance
2005-04-16 15:20:36 -07:00
*/
2013-02-08 18:13:30 +01:00
# 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
2005-04-16 15:20:36 -07:00
/*
2006-09-08 04:13:49 +02:00
* gcc has a tradition of misscompiling the previous construct using the
2013-01-22 12:59:30 +01:00
* address of a label as argument to inline assembler . Gas otoh has the
2006-09-08 04:13:49 +02:00
* annoying difference between la and dla which are only usable for 32 - bit
* rsp . 64 - bit code , so can ' t be used without conditional compilation .
* The alterantive is switching the assembler to 64 - bit code which happens
* to work right even for 32 - bit code . . .
2005-04-16 15:20:36 -07:00
*/
2006-09-08 04:13:49 +02:00
# define instruction_hazard() \
do { \
unsigned long tmp ; \
\
__asm__ __volatile__ ( \
2014-11-13 11:52:22 +00:00
" .set " MIPS_ISA_LEVEL " \n " \
2006-09-08 04:13:49 +02:00
" dla %0, 1f \n " \
" jr.hb %0 \n " \
" .set mips0 \n " \
" 1: \n " \
: " =r " ( tmp ) ) ; \
} while ( 0 )
2005-04-16 15:20:36 -07:00
2011-11-16 01:25:40 +00:00
# elif (defined(CONFIG_CPU_MIPSR1) && !defined(CONFIG_MIPS_ALCHEMY)) || \
defined ( CONFIG_CPU_BMIPS )
2007-09-21 13:05:44 +01:00
/*
* These are slightly complicated by the fact that we guarantee R1 kernels to
* run fine on R2 processors .
*/
2013-02-08 18:13:30 +01:00
# 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
2007-09-21 13:05:44 +01:00
/*
* gcc has a tradition of misscompiling the previous construct using the
2013-01-22 12:59:30 +01:00
* address of a label as argument to inline assembler . Gas otoh has the
2007-09-21 13:05:44 +01:00
* annoying difference between la and dla which are only usable for 32 - bit
* rsp . 64 - bit code , so can ' t be used without conditional compilation .
* The alterantive is switching the assembler to 64 - bit code which happens
* to work right even for 32 - bit code . . .
*/
# define __instruction_hazard() \
do { \
unsigned long tmp ; \
\
__asm__ __volatile__ ( \
" .set mips64r2 \n " \
" dla %0, 1f \n " \
" jr.hb %0 \n " \
" .set mips0 \n " \
" 1: \n " \
: " =r " ( tmp ) ) ; \
} while ( 0 )
# define instruction_hazard() \
do { \
2014-11-13 11:52:22 +00:00
if ( cpu_has_mips_r2_r6 ) \
2007-09-21 13:05:44 +01:00
__instruction_hazard ( ) ; \
} while ( 0 )
2010-07-15 21:45:04 +02:00
# elif defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_CPU_CAVIUM_OCTEON) || \
2011-11-10 22:30:25 -08:00
defined ( CONFIG_CPU_LOONGSON2 ) | | defined ( CONFIG_CPU_R10000 ) | | \
2013-01-14 15:11:59 +00:00
defined ( CONFIG_CPU_R5500 ) | | defined ( CONFIG_CPU_XLR )
2005-04-16 15:20:36 -07:00
/*
2006-09-08 04:13:49 +02:00
* R10000 rocks - all hazards handled in hardware , so this becomes a nobrainer .
2005-04-16 15:20:36 -07:00
*/
2013-02-08 18:13:30 +01:00
# 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
2006-09-08 04:13:49 +02:00
# define instruction_hazard() do { } while (0)
2005-04-16 15:20:36 -07:00
2006-09-08 04:13:49 +02:00
# elif defined(CONFIG_CPU_SB1)
2005-04-16 15:20:36 -07:00
/*
2006-09-08 04:13:49 +02:00
* Mostly like R4000 for historic reasons
2005-04-16 15:20:36 -07:00
*/
2013-02-08 18:13:30 +01:00
# 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
2006-09-08 04:13:49 +02:00
# define instruction_hazard() do { } while (0)
2005-03-01 18:12:06 +00:00
2005-04-16 15:20:36 -07:00
# else
/*
2006-09-08 04:13:49 +02:00
* Finally the catchall case for all other processors including R4000 , R4400 ,
* R4600 , R4700 , R5000 , RM7000 , NEC VR41xx etc .
2006-03-13 16:16:29 +00:00
*
2006-09-08 04:13:49 +02:00
* The taken branch will result in a two cycle penalty for the two killed
* instructions on R4000 / R4400 . Other processors only have a single cycle
* hazard so this is nice trick to have an optimal code for a range of
* processors .
2005-12-22 13:41:29 +01:00
*/
2013-02-08 18:13:30 +01:00
# 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
2005-07-12 18:35:38 +00:00
# define instruction_hazard() do { } while (0)
2006-04-05 09:45:45 +01:00
2006-09-08 04:13:49 +02:00
# endif
2005-04-16 15:20:36 -07:00
2007-05-08 16:09:13 +01:00
/* FPU hazards */
# if defined(CONFIG_CPU_SB1)
2013-02-08 18:13:30 +01:00
# define __enable_fpu_hazard \
. set push ; \
. set mips64 ; \
. set noreorder ; \
___ssnop ; \
bnezl $ 0 , . + 4 ; \
___ssnop ; \
. set pop
# define __disable_fpu_hazard
2007-05-08 16:09:13 +01:00
2014-11-13 11:52:22 +00:00
# elif defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
2013-02-08 18:13:30 +01:00
# define __enable_fpu_hazard \
___ehb
# define __disable_fpu_hazard \
___ehb
2007-05-08 16:09:13 +01:00
# else
2013-02-08 18:13:30 +01:00
# define __enable_fpu_hazard \
nop ; \
nop ; \
nop ; \
nop
# define __disable_fpu_hazard \
___ehb
2007-05-08 16:09:13 +01:00
# endif
2013-02-08 18:13:30 +01:00
# 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__ */
2005-04-16 15:20:36 -07:00
# endif /* _ASM_HAZARDS_H */