提交 661af35e 编写于 作者: R Ralf Baechle

Merge branch 'mipsr6-for-3.20' of...

Merge branch 'mipsr6-for-3.20' of git://git.linux-mips.org/pub/scm/mchandras/linux into mips-for-linux-next
......@@ -377,8 +377,10 @@ config MIPS_MALTA
select SYS_HAS_CPU_MIPS32_R1
select SYS_HAS_CPU_MIPS32_R2
select SYS_HAS_CPU_MIPS32_R3_5
select SYS_HAS_CPU_MIPS32_R6
select SYS_HAS_CPU_MIPS64_R1
select SYS_HAS_CPU_MIPS64_R2
select SYS_HAS_CPU_MIPS64_R6
select SYS_HAS_CPU_NEVADA
select SYS_HAS_CPU_RM7000
select SYS_SUPPORTS_32BIT_KERNEL
......@@ -1034,6 +1036,9 @@ config MIPS_MACHINE
config NO_IOPORT_MAP
def_bool n
config GENERIC_CSUM
bool
config GENERIC_ISA_DMA
bool
select ZONE_DMA if GENERIC_ISA_DMA_SUPPORT_BROKEN=n
......@@ -1147,6 +1152,9 @@ config SOC_PNX8335
bool
select SOC_PNX833X
config MIPS_SPRAM
bool
config SWAP_IO_SPACE
bool
......@@ -1305,6 +1313,22 @@ config CPU_MIPS32_R2
specific type of processor in your system, choose those that one
otherwise CPU_MIPS32_R1 is a safe bet for any MIPS32 system.
config CPU_MIPS32_R6
bool "MIPS32 Release 6 (EXPERIMENTAL)"
depends on SYS_HAS_CPU_MIPS32_R6
select CPU_HAS_PREFETCH
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
select CPU_SUPPORTS_MSA
select GENERIC_CSUM
select HAVE_KVM
select MIPS_O32_FP64_SUPPORT
help
Choose this option to build a kernel for release 6 or later of the
MIPS32 architecture. New MIPS processors, starting with the Warrior
family, are based on a MIPS32r6 processor. If you own an older
processor, you probably need to select MIPS32r1 or MIPS32r2 instead.
config CPU_MIPS64_R1
bool "MIPS64 Release 1"
depends on SYS_HAS_CPU_MIPS64_R1
......@@ -1340,6 +1364,21 @@ config CPU_MIPS64_R2
specific type of processor in your system, choose those that one
otherwise CPU_MIPS64_R1 is a safe bet for any MIPS64 system.
config CPU_MIPS64_R6
bool "MIPS64 Release 6 (EXPERIMENTAL)"
depends on SYS_HAS_CPU_MIPS64_R6
select CPU_HAS_PREFETCH
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
select CPU_SUPPORTS_MSA
select GENERIC_CSUM
help
Choose this option to build a kernel for release 6 or later of the
MIPS64 architecture. New MIPS processors, starting with the Warrior
family, are based on a MIPS64r6 processor. If you own an older
processor, you probably need to select MIPS64r1 or MIPS64r2 instead.
config CPU_R3000
bool "R3000"
depends on SYS_HAS_CPU_R3000
......@@ -1540,7 +1579,7 @@ endchoice
config CPU_MIPS32_3_5_FEATURES
bool "MIPS32 Release 3.5 Features"
depends on SYS_HAS_CPU_MIPS32_R3_5
depends on CPU_MIPS32_R2
depends on CPU_MIPS32_R2 || CPU_MIPS32_R6
help
Choose this option to build a kernel for release 2 or later of the
MIPS32 architecture including features from the 3.5 release such as
......@@ -1660,12 +1699,18 @@ config SYS_HAS_CPU_MIPS32_R2
config SYS_HAS_CPU_MIPS32_R3_5
bool
config SYS_HAS_CPU_MIPS32_R6
bool
config SYS_HAS_CPU_MIPS64_R1
bool
config SYS_HAS_CPU_MIPS64_R2
bool
config SYS_HAS_CPU_MIPS64_R6
bool
config SYS_HAS_CPU_R3000
bool
......@@ -1765,11 +1810,11 @@ endmenu
#
config CPU_MIPS32
bool
default y if CPU_MIPS32_R1 || CPU_MIPS32_R2
default y if CPU_MIPS32_R1 || CPU_MIPS32_R2 || CPU_MIPS32_R6
config CPU_MIPS64
bool
default y if CPU_MIPS64_R1 || CPU_MIPS64_R2
default y if CPU_MIPS64_R1 || CPU_MIPS64_R2 || CPU_MIPS64_R6
#
# These two indicate the revision of the architecture, either Release 1 or Release 2
......@@ -1781,6 +1826,12 @@ config CPU_MIPSR1
config CPU_MIPSR2
bool
default y if CPU_MIPS32_R2 || CPU_MIPS64_R2 || CPU_CAVIUM_OCTEON
select MIPS_SPRAM
config CPU_MIPSR6
bool
default y if CPU_MIPS32_R6 || CPU_MIPS64_R6
select MIPS_SPRAM
config EVA
bool
......@@ -2014,6 +2065,19 @@ config MIPS_MT_FPAFF
default y
depends on MIPS_MT_SMP
config MIPSR2_TO_R6_EMULATOR
bool "MIPS R2-to-R6 emulator"
depends on CPU_MIPSR6 && !SMP
default y
help
Choose this option if you want to run non-R6 MIPS userland code.
Even if you say 'Y' here, the emulator will still be disabled by
default. You can enable it using the 'mipsr2emul' kernel option.
The only reason this is a build-time option is to save ~14K from the
final kernel image.
comment "MIPS R2-to-R6 emulator is only available for UP kernels"
depends on SMP && CPU_MIPSR6
config MIPS_VPE_LOADER
bool "VPE loader support."
depends on SYS_SUPPORTS_MULTITHREADING && MODULES
......@@ -2149,7 +2213,7 @@ config CPU_HAS_SMARTMIPS
here.
config CPU_MICROMIPS
depends on 32BIT && SYS_SUPPORTS_MICROMIPS
depends on 32BIT && SYS_SUPPORTS_MICROMIPS && !CPU_MIPSR6
bool "microMIPS"
help
When this option is enabled the kernel will be built using the
......
......@@ -122,17 +122,4 @@ config SPINLOCK_TEST
help
Add several files to the debugfs to test spinlock speed.
config FP32XX_HYBRID_FPRS
bool "Run FP32 & FPXX code with hybrid FPRs"
depends on MIPS_O32_FP64_SUPPORT
help
The hybrid FPR scheme is normally used only when a program needs to
execute a mix of FP32 & FP64A code, since the trapping & emulation
that it entails is expensive. When enabled, this option will lead
to the kernel running programs which use the FP32 & FPXX FP ABIs
using the hybrid FPR scheme, which can be useful for debugging
purposes.
If unsure, say N.
endmenu
......@@ -138,10 +138,12 @@ cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS
-Wa,-mips32 -Wa,--trap
cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
-Wa,-mips32r2 -Wa,--trap
cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap
cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips64 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
-Wa,-mips64 -Wa,--trap
cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips64r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
-Wa,-mips64r2 -Wa,--trap
cflags-$(CONFIG_CPU_MIPS64_R6) += -march=mips64r6 -Wa,--trap
cflags-$(CONFIG_CPU_R5000) += -march=r5000 -Wa,--trap
cflags-$(CONFIG_CPU_R5432) += $(call cc-option,-march=r5400,-march=r5000) \
-Wa,--trap
......
CONFIG_MIPS_MALTA=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32_R6=y
CONFIG_PAGE_SIZE_16KB=y
CONFIG_HZ_100=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_AUDIT=y
CONFIG_NO_HZ=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=15
CONFIG_SYSCTL_SYSCALL=y
CONFIG_EMBEDDED=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_PCI=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM_USER=m
CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_NET_IPIP=m
CONFIG_IP_MROUTE=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
# CONFIG_INET_LRO is not set
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
CONFIG_IPV6_TUNNEL=m
CONFIG_BRIDGE=m
CONFIG_VLAN_8021Q=m
CONFIG_ATALK=m
CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
CONFIG_NET_SCH_HFSC=m
CONFIG_NET_SCH_PRIO=m
CONFIG_NET_SCH_RED=m
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
CONFIG_NET_SCH_TBF=m
CONFIG_NET_SCH_GRED=m
CONFIG_NET_SCH_DSMARK=m
CONFIG_NET_SCH_NETEM=m
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_CLS_BASIC=m
CONFIG_NET_CLS_TCINDEX=m
CONFIG_NET_CLS_ROUTE4=m
CONFIG_NET_CLS_FW=m
CONFIG_NET_CLS_U32=m
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_CLS_IND=y
# CONFIG_WIRELESS is not set
CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_IDE=y
# CONFIG_IDE_PROC_FS is not set
# CONFIG_IDEPCI_PCIBUS_ORDER is not set
CONFIG_BLK_DEV_GENERIC=y
CONFIG_BLK_DEV_PIIX=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_ADAPTEC is not set
# CONFIG_NET_VENDOR_ALTEON is not set
CONFIG_PCNET32=y
# CONFIG_NET_VENDOR_ATHEROS is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_BROCADE is not set
# CONFIG_NET_VENDOR_CHELSIO is not set
# CONFIG_NET_VENDOR_CISCO is not set
# CONFIG_NET_VENDOR_DEC is not set
# CONFIG_NET_VENDOR_DLINK is not set
# CONFIG_NET_VENDOR_EMULEX is not set
# CONFIG_NET_VENDOR_EXAR is not set
# CONFIG_NET_VENDOR_HP is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MELLANOX is not set
# CONFIG_NET_VENDOR_MICREL is not set
# CONFIG_NET_VENDOR_MYRI is not set
# CONFIG_NET_VENDOR_NATSEMI is not set
# CONFIG_NET_VENDOR_NVIDIA is not set
# CONFIG_NET_VENDOR_OKI is not set
# CONFIG_NET_PACKET_ENGINE is not set
# CONFIG_NET_VENDOR_QLOGIC is not set
# CONFIG_NET_VENDOR_REALTEK is not set
# CONFIG_NET_VENDOR_RDC is not set
# CONFIG_NET_VENDOR_SEEQ is not set
# CONFIG_NET_VENDOR_SILAN is not set
# CONFIG_NET_VENDOR_SIS is not set
# CONFIG_NET_VENDOR_SMSC is not set
# CONFIG_NET_VENDOR_STMICRO is not set
# CONFIG_NET_VENDOR_SUN is not set
# CONFIG_NET_VENDOR_TEHUTI is not set
# CONFIG_NET_VENDOR_TI is not set
# CONFIG_NET_VENDOR_TOSHIBA is not set
# CONFIG_NET_VENDOR_VIA is not set
# CONFIG_NET_VENDOR_WIZNET is not set
# CONFIG_WLAN is not set
# CONFIG_VT is not set
CONFIG_LEGACY_PTY_COUNT=4
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_HW_RANDOM=y
# CONFIG_HWMON is not set
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_MATROX=y
CONFIG_FB_MATROX_G=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
CONFIG_USB_UHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_IDE_DISK=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_CMOS=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_XFS_FS=y
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_QUOTA=y
CONFIG_QFMT_V2=y
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
CONFIG_CIFS=m
CONFIG_CIFS_WEAK_PW_HASH=y
CONFIG_CIFS_XATTR=y
CONFIG_CIFS_POSIX=y
CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_ISO8859_1=m
# CONFIG_FTRACE is not set
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
# CONFIG_CRYPTO_HW is not set
# MIPS headers
generic-(CONFIG_GENERIC_CSUM) += checksum.h
generic-y += cputime.h
generic-y += current.h
generic-y += dma-contiguous.h
......
......@@ -19,7 +19,7 @@
#include <asm/asmmacro-64.h>
#endif
#ifdef CONFIG_CPU_MIPSR2
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
.macro local_irq_enable reg=t0
ei
irq_enable_hazard
......@@ -104,7 +104,8 @@
.endm
.macro fpu_save_double thread status tmp
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \
defined(CONFIG_CPU_MIPS32_R6)
sll \tmp, \status, 5
bgez \tmp, 10f
fpu_save_16odd \thread
......@@ -160,7 +161,8 @@
.endm
.macro fpu_restore_double thread status tmp
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \
defined(CONFIG_CPU_MIPS32_R6)
sll \tmp, \status, 5
bgez \tmp, 10f # 16 register mode?
......@@ -170,16 +172,16 @@
fpu_restore_16even \thread \tmp
.endm
#ifdef CONFIG_CPU_MIPSR2
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
.macro _EXT rd, rs, p, s
ext \rd, \rs, \p, \s
.endm
#else /* !CONFIG_CPU_MIPSR2 */
#else /* !CONFIG_CPU_MIPSR2 || !CONFIG_CPU_MIPSR6 */
.macro _EXT rd, rs, p, s
srl \rd, \rs, \p
andi \rd, \rd, (1 << \s) - 1
.endm
#endif /* !CONFIG_CPU_MIPSR2 */
#endif /* !CONFIG_CPU_MIPSR2 || !CONFIG_CPU_MIPSR6 */
/*
* Temporary until all gas have MT ASE support
......@@ -304,7 +306,7 @@
.set push
.set noat
SET_HARDFLOAT
add $1, \base, \off
addu $1, \base, \off
.word LDD_MSA_INSN | (\wd << 6)
.set pop
.endm
......@@ -313,7 +315,7 @@
.set push
.set noat
SET_HARDFLOAT
add $1, \base, \off
addu $1, \base, \off
.word STD_MSA_INSN | (\wd << 6)
.set pop
.endm
......
......@@ -54,19 +54,19 @@ static __inline__ void atomic_##op(int i, atomic_t * v) \
" sc %0, %1 \n" \
" beqzl %0, 1b \n" \
" .set mips0 \n" \
: "=&r" (temp), "+" GCC_OFF12_ASM() (v->counter) \
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \
: "Ir" (i)); \
} else if (kernel_uses_llsc) { \
int temp; \
\
do { \
__asm__ __volatile__( \
" .set arch=r4000 \n" \
" .set "MIPS_ISA_LEVEL" \n" \
" ll %0, %1 # atomic_" #op "\n" \
" " #asm_op " %0, %2 \n" \
" sc %0, %1 \n" \
" .set mips0 \n" \
: "=&r" (temp), "+" GCC_OFF12_ASM() (v->counter) \
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \
: "Ir" (i)); \
} while (unlikely(!temp)); \
} else { \
......@@ -97,20 +97,20 @@ static __inline__ int atomic_##op##_return(int i, atomic_t * v) \
" " #asm_op " %0, %1, %3 \n" \
" .set mips0 \n" \
: "=&r" (result), "=&r" (temp), \
"+" GCC_OFF12_ASM() (v->counter) \
"+" GCC_OFF_SMALL_ASM() (v->counter) \
: "Ir" (i)); \
} else if (kernel_uses_llsc) { \
int temp; \
\
do { \
__asm__ __volatile__( \
" .set arch=r4000 \n" \
" .set "MIPS_ISA_LEVEL" \n" \
" ll %1, %2 # atomic_" #op "_return \n" \
" " #asm_op " %0, %1, %3 \n" \
" sc %0, %2 \n" \
" .set mips0 \n" \
: "=&r" (result), "=&r" (temp), \
"+" GCC_OFF12_ASM() (v->counter) \
"+" GCC_OFF_SMALL_ASM() (v->counter) \
: "Ir" (i)); \
} while (unlikely(!result)); \
\
......@@ -171,14 +171,14 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
"1: \n"
" .set mips0 \n"
: "=&r" (result), "=&r" (temp),
"+" GCC_OFF12_ASM() (v->counter)
: "Ir" (i), GCC_OFF12_ASM() (v->counter)
"+" GCC_OFF_SMALL_ASM() (v->counter)
: "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter)
: "memory");
} else if (kernel_uses_llsc) {
int temp;
__asm__ __volatile__(
" .set arch=r4000 \n"
" .set "MIPS_ISA_LEVEL" \n"
"1: ll %1, %2 # atomic_sub_if_positive\n"
" subu %0, %1, %3 \n"
" bltz %0, 1f \n"
......@@ -190,7 +190,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
"1: \n"
" .set mips0 \n"
: "=&r" (result), "=&r" (temp),
"+" GCC_OFF12_ASM() (v->counter)
"+" GCC_OFF_SMALL_ASM() (v->counter)
: "Ir" (i));
} else {
unsigned long flags;
......@@ -333,19 +333,19 @@ static __inline__ void atomic64_##op(long i, atomic64_t * v) \
" scd %0, %1 \n" \
" beqzl %0, 1b \n" \
" .set mips0 \n" \
: "=&r" (temp), "+" GCC_OFF12_ASM() (v->counter) \
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \
: "Ir" (i)); \
} else if (kernel_uses_llsc) { \
long temp; \
\
do { \
__asm__ __volatile__( \
" .set arch=r4000 \n" \
" .set "MIPS_ISA_LEVEL" \n" \
" lld %0, %1 # atomic64_" #op "\n" \
" " #asm_op " %0, %2 \n" \
" scd %0, %1 \n" \
" .set mips0 \n" \
: "=&r" (temp), "+" GCC_OFF12_ASM() (v->counter) \
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter) \
: "Ir" (i)); \
} while (unlikely(!temp)); \
} else { \
......@@ -376,21 +376,21 @@ static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \
" " #asm_op " %0, %1, %3 \n" \
" .set mips0 \n" \
: "=&r" (result), "=&r" (temp), \
"+" GCC_OFF12_ASM() (v->counter) \
"+" GCC_OFF_SMALL_ASM() (v->counter) \
: "Ir" (i)); \
} else if (kernel_uses_llsc) { \
long temp; \
\
do { \
__asm__ __volatile__( \
" .set arch=r4000 \n" \
" .set "MIPS_ISA_LEVEL" \n" \
" lld %1, %2 # atomic64_" #op "_return\n" \
" " #asm_op " %0, %1, %3 \n" \
" scd %0, %2 \n" \
" .set mips0 \n" \
: "=&r" (result), "=&r" (temp), \
"=" GCC_OFF12_ASM() (v->counter) \
: "Ir" (i), GCC_OFF12_ASM() (v->counter) \
"=" GCC_OFF_SMALL_ASM() (v->counter) \
: "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter) \
: "memory"); \
} while (unlikely(!result)); \
\
......@@ -452,14 +452,14 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
"1: \n"
" .set mips0 \n"
: "=&r" (result), "=&r" (temp),
"=" GCC_OFF12_ASM() (v->counter)
: "Ir" (i), GCC_OFF12_ASM() (v->counter)
"=" GCC_OFF_SMALL_ASM() (v->counter)
: "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter)
: "memory");
} else if (kernel_uses_llsc) {
long temp;
__asm__ __volatile__(
" .set arch=r4000 \n"
" .set "MIPS_ISA_LEVEL" \n"
"1: lld %1, %2 # atomic64_sub_if_positive\n"
" dsubu %0, %1, %3 \n"
" bltz %0, 1f \n"
......@@ -471,7 +471,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
"1: \n"
" .set mips0 \n"
: "=&r" (result), "=&r" (temp),
"+" GCC_OFF12_ASM() (v->counter)
"+" GCC_OFF_SMALL_ASM() (v->counter)
: "Ir" (i));
} else {
unsigned long flags;
......
......@@ -79,28 +79,28 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
" " __SC "%0, %1 \n"
" beqzl %0, 1b \n"
" .set mips0 \n"
: "=&r" (temp), "=" GCC_OFF12_ASM() (*m)
: "ir" (1UL << bit), GCC_OFF12_ASM() (*m));
#ifdef CONFIG_CPU_MIPSR2
: "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*m)
: "ir" (1UL << bit), GCC_OFF_SMALL_ASM() (*m));
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
} else if (kernel_uses_llsc && __builtin_constant_p(bit)) {
do {
__asm__ __volatile__(
" " __LL "%0, %1 # set_bit \n"
" " __INS "%0, %3, %2, 1 \n"
" " __SC "%0, %1 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m)
: "ir" (bit), "r" (~0));
} while (unlikely(!temp));
#endif /* CONFIG_CPU_MIPSR2 */
#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */
} else if (kernel_uses_llsc) {
do {
__asm__ __volatile__(
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
" " __LL "%0, %1 # set_bit \n"
" or %0, %2 \n"
" " __SC "%0, %1 \n"
" .set mips0 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m)
: "ir" (1UL << bit));
} while (unlikely(!temp));
} else
......@@ -131,28 +131,28 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
" " __SC "%0, %1 \n"
" beqzl %0, 1b \n"
" .set mips0 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m)
: "ir" (~(1UL << bit)));
#ifdef CONFIG_CPU_MIPSR2
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
} else if (kernel_uses_llsc && __builtin_constant_p(bit)) {
do {
__asm__ __volatile__(
" " __LL "%0, %1 # clear_bit \n"
" " __INS "%0, $0, %2, 1 \n"
" " __SC "%0, %1 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m)
: "ir" (bit));
} while (unlikely(!temp));
#endif /* CONFIG_CPU_MIPSR2 */
#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */
} else if (kernel_uses_llsc) {
do {
__asm__ __volatile__(
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
" " __LL "%0, %1 # clear_bit \n"
" and %0, %2 \n"
" " __SC "%0, %1 \n"
" .set mips0 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m)
: "ir" (~(1UL << bit)));
} while (unlikely(!temp));
} else
......@@ -197,7 +197,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
" " __SC "%0, %1 \n"
" beqzl %0, 1b \n"
" .set mips0 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m)
: "ir" (1UL << bit));
} else if (kernel_uses_llsc) {
unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
......@@ -205,12 +205,12 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
do {
__asm__ __volatile__(
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
" " __LL "%0, %1 # change_bit \n"
" xor %0, %2 \n"
" " __SC "%0, %1 \n"
" .set mips0 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m)
: "ir" (1UL << bit));
} while (unlikely(!temp));
} else
......@@ -245,7 +245,7 @@ static inline int test_and_set_bit(unsigned long nr,
" beqzl %2, 1b \n"
" and %2, %0, %3 \n"
" .set mips0 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m), "=&r" (res)
: "r" (1UL << bit)
: "memory");
} else if (kernel_uses_llsc) {
......@@ -254,12 +254,12 @@ static inline int test_and_set_bit(unsigned long nr,
do {
__asm__ __volatile__(
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
" " __LL "%0, %1 # test_and_set_bit \n"
" or %2, %0, %3 \n"
" " __SC "%2, %1 \n"
" .set mips0 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m), "=&r" (res)
: "r" (1UL << bit)
: "memory");
} while (unlikely(!res));
......@@ -308,12 +308,12 @@ static inline int test_and_set_bit_lock(unsigned long nr,
do {
__asm__ __volatile__(
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
" " __LL "%0, %1 # test_and_set_bit \n"
" or %2, %0, %3 \n"
" " __SC "%2, %1 \n"
" .set mips0 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m), "=&r" (res)
: "r" (1UL << bit)
: "memory");
} while (unlikely(!res));
......@@ -355,10 +355,10 @@ static inline int test_and_clear_bit(unsigned long nr,
" beqzl %2, 1b \n"
" and %2, %0, %3 \n"
" .set mips0 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m), "=&r" (res)
: "r" (1UL << bit)
: "memory");
#ifdef CONFIG_CPU_MIPSR2
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
} else if (kernel_uses_llsc && __builtin_constant_p(nr)) {
unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
unsigned long temp;
......@@ -369,7 +369,7 @@ static inline int test_and_clear_bit(unsigned long nr,
" " __EXT "%2, %0, %3, 1 \n"
" " __INS "%0, $0, %3, 1 \n"
" " __SC "%0, %1 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m), "=&r" (res)
: "ir" (bit)
: "memory");
} while (unlikely(!temp));
......@@ -380,13 +380,13 @@ static inline int test_and_clear_bit(unsigned long nr,
do {
__asm__ __volatile__(
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
" " __LL "%0, %1 # test_and_clear_bit \n"
" or %2, %0, %3 \n"
" xor %2, %3 \n"
" " __SC "%2, %1 \n"
" .set mips0 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m), "=&r" (res)
: "r" (1UL << bit)
: "memory");
} while (unlikely(!res));
......@@ -428,7 +428,7 @@ static inline int test_and_change_bit(unsigned long nr,
" beqzl %2, 1b \n"
" and %2, %0, %3 \n"
" .set mips0 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m), "=&r" (res)
: "r" (1UL << bit)
: "memory");
} else if (kernel_uses_llsc) {
......@@ -437,12 +437,12 @@ static inline int test_and_change_bit(unsigned long nr,
do {
__asm__ __volatile__(
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
" " __LL "%0, %1 # test_and_change_bit \n"
" xor %2, %0, %3 \n"
" " __SC "\t%2, %1 \n"
" .set mips0 \n"
: "=&r" (temp), "+" GCC_OFF12_ASM() (*m), "=&r" (res)
: "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (*m), "=&r" (res)
: "r" (1UL << bit)
: "memory");
} while (unlikely(!res));
......@@ -485,7 +485,7 @@ static inline unsigned long __fls(unsigned long word)
__builtin_constant_p(cpu_has_clo_clz) && cpu_has_clo_clz) {
__asm__(
" .set push \n"
" .set mips32 \n"
" .set "MIPS_ISA_LEVEL" \n"
" clz %0, %1 \n"
" .set pop \n"
: "=r" (num)
......@@ -498,7 +498,7 @@ static inline unsigned long __fls(unsigned long word)
__builtin_constant_p(cpu_has_mips64) && cpu_has_mips64) {
__asm__(
" .set push \n"
" .set mips64 \n"
" .set "MIPS_ISA_LEVEL" \n"
" dclz %0, %1 \n"
" .set pop \n"
: "=r" (num)
......@@ -562,7 +562,7 @@ static inline int fls(int x)
if (__builtin_constant_p(cpu_has_clo_clz) && cpu_has_clo_clz) {
__asm__(
" .set push \n"
" .set mips32 \n"
" .set "MIPS_ISA_LEVEL" \n"
" clz %0, %1 \n"
" .set pop \n"
: "=r" (x)
......
......@@ -12,6 +12,10 @@
#ifndef _ASM_CHECKSUM_H
#define _ASM_CHECKSUM_H
#ifdef CONFIG_GENERIC_CSUM
#include <asm-generic/checksum.h>
#else
#include <linux/in6.h>
#include <asm/uaccess.h>
......@@ -274,5 +278,6 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
}
#include <asm-generic/checksum.h>
#endif /* CONFIG_GENERIC_CSUM */
#endif /* _ASM_CHECKSUM_H */
......@@ -31,24 +31,24 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
" sc %2, %1 \n"
" beqzl %2, 1b \n"
" .set mips0 \n"
: "=&r" (retval), "=" GCC_OFF12_ASM() (*m), "=&r" (dummy)
: GCC_OFF12_ASM() (*m), "Jr" (val)
: "=&r" (retval), "=" GCC_OFF_SMALL_ASM() (*m), "=&r" (dummy)
: GCC_OFF_SMALL_ASM() (*m), "Jr" (val)
: "memory");
} else if (kernel_uses_llsc) {
unsigned long dummy;
do {
__asm__ __volatile__(
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
" ll %0, %3 # xchg_u32 \n"
" .set mips0 \n"
" move %2, %z4 \n"
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
" sc %2, %1 \n"
" .set mips0 \n"
: "=&r" (retval), "=" GCC_OFF12_ASM() (*m),
: "=&r" (retval), "=" GCC_OFF_SMALL_ASM() (*m),
"=&r" (dummy)
: GCC_OFF12_ASM() (*m), "Jr" (val)
: GCC_OFF_SMALL_ASM() (*m), "Jr" (val)
: "memory");
} while (unlikely(!dummy));
} else {
......@@ -82,22 +82,22 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
" scd %2, %1 \n"
" beqzl %2, 1b \n"
" .set mips0 \n"
: "=&r" (retval), "=" GCC_OFF12_ASM() (*m), "=&r" (dummy)
: GCC_OFF12_ASM() (*m), "Jr" (val)
: "=&r" (retval), "=" GCC_OFF_SMALL_ASM() (*m), "=&r" (dummy)
: GCC_OFF_SMALL_ASM() (*m), "Jr" (val)
: "memory");
} else if (kernel_uses_llsc) {
unsigned long dummy;
do {
__asm__ __volatile__(
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
" lld %0, %3 # xchg_u64 \n"
" move %2, %z4 \n"
" scd %2, %1 \n"
" .set mips0 \n"
: "=&r" (retval), "=" GCC_OFF12_ASM() (*m),
: "=&r" (retval), "=" GCC_OFF_SMALL_ASM() (*m),
"=&r" (dummy)
: GCC_OFF12_ASM() (*m), "Jr" (val)
: GCC_OFF_SMALL_ASM() (*m), "Jr" (val)
: "memory");
} while (unlikely(!dummy));
} else {
......@@ -158,25 +158,25 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
" beqzl $1, 1b \n" \
"2: \n" \
" .set pop \n" \
: "=&r" (__ret), "=" GCC_OFF12_ASM() (*m) \
: GCC_OFF12_ASM() (*m), "Jr" (old), "Jr" (new) \
: "=&r" (__ret), "=" GCC_OFF_SMALL_ASM() (*m) \
: GCC_OFF_SMALL_ASM() (*m), "Jr" (old), "Jr" (new) \
: "memory"); \
} else if (kernel_uses_llsc) { \
__asm__ __volatile__( \
" .set push \n" \
" .set noat \n" \
" .set arch=r4000 \n" \
" .set "MIPS_ISA_ARCH_LEVEL" \n" \
"1: " ld " %0, %2 # __cmpxchg_asm \n" \
" bne %0, %z3, 2f \n" \
" .set mips0 \n" \
" move $1, %z4 \n" \
" .set arch=r4000 \n" \
" .set "MIPS_ISA_ARCH_LEVEL" \n" \
" " st " $1, %1 \n" \
" beqz $1, 1b \n" \
" .set pop \n" \
"2: \n" \
: "=&r" (__ret), "=" GCC_OFF12_ASM() (*m) \
: GCC_OFF12_ASM() (*m), "Jr" (old), "Jr" (new) \
: "=&r" (__ret), "=" GCC_OFF_SMALL_ASM() (*m) \
: GCC_OFF_SMALL_ASM() (*m), "Jr" (old), "Jr" (new) \
: "memory"); \
} else { \
unsigned long __flags; \
......
......@@ -16,12 +16,30 @@
#define GCC_REG_ACCUM "accum"
#endif
#ifdef CONFIG_CPU_MIPSR6
/* All MIPS R6 toolchains support the ZC constrain */
#define GCC_OFF_SMALL_ASM() "ZC"
#else
#ifndef CONFIG_CPU_MICROMIPS
#define GCC_OFF12_ASM() "R"
#define GCC_OFF_SMALL_ASM() "R"
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
#define GCC_OFF12_ASM() "ZC"
#define GCC_OFF_SMALL_ASM() "ZC"
#else
#error "microMIPS compilation unsupported with GCC older than 4.9"
#endif
#endif /* CONFIG_CPU_MICROMIPS */
#endif /* CONFIG_CPU_MIPSR6 */
#ifdef CONFIG_CPU_MIPSR6
#define MIPS_ISA_LEVEL "mips64r6"
#define MIPS_ISA_ARCH_LEVEL MIPS_ISA_LEVEL
#define MIPS_ISA_LEVEL_RAW mips64r6
#define MIPS_ISA_ARCH_LEVEL_RAW MIPS_ISA_LEVEL_RAW
#else
/* MIPS64 is a superset of MIPS32 */
#define MIPS_ISA_LEVEL "mips64r2"
#define MIPS_ISA_ARCH_LEVEL "arch=r4000"
#define MIPS_ISA_LEVEL_RAW mips64r2
#define MIPS_ISA_ARCH_LEVEL_RAW MIPS_ISA_LEVEL_RAW
#endif /* CONFIG_CPU_MIPSR6 */
#endif /* _ASM_COMPILER_H */
......@@ -38,6 +38,9 @@
#ifndef cpu_has_maar
#define cpu_has_maar (cpu_data[0].options & MIPS_CPU_MAAR)
#endif
#ifndef cpu_has_rw_llb
#define cpu_has_rw_llb (cpu_data[0].options & MIPS_CPU_RW_LLB)
#endif
/*
* For the moment we don't consider R6000 and R8000 so we can assume that
......@@ -171,6 +174,9 @@
#endif
#endif
#ifndef cpu_has_mips_1
# define cpu_has_mips_1 (!cpu_has_mips_r6)
#endif
#ifndef cpu_has_mips_2
# define cpu_has_mips_2 (cpu_data[0].isa_level & MIPS_CPU_ISA_II)
#endif
......@@ -189,12 +195,18 @@
#ifndef cpu_has_mips32r2
# define cpu_has_mips32r2 (cpu_data[0].isa_level & MIPS_CPU_ISA_M32R2)
#endif
#ifndef cpu_has_mips32r6
# define cpu_has_mips32r6 (cpu_data[0].isa_level & MIPS_CPU_ISA_M32R6)
#endif
#ifndef cpu_has_mips64r1
# define cpu_has_mips64r1 (cpu_data[0].isa_level & MIPS_CPU_ISA_M64R1)
#endif
#ifndef cpu_has_mips64r2
# define cpu_has_mips64r2 (cpu_data[0].isa_level & MIPS_CPU_ISA_M64R2)
#endif
#ifndef cpu_has_mips64r6
# define cpu_has_mips64r6 (cpu_data[0].isa_level & MIPS_CPU_ISA_M64R6)
#endif
/*
* Shortcuts ...
......@@ -208,17 +220,23 @@
#define cpu_has_mips_4_5_r (cpu_has_mips_4 | cpu_has_mips_5_r)
#define cpu_has_mips_5_r (cpu_has_mips_5 | cpu_has_mips_r)
#define cpu_has_mips_4_5_r2 (cpu_has_mips_4_5 | cpu_has_mips_r2)
#define cpu_has_mips_4_5_r2_r6 (cpu_has_mips_4_5 | cpu_has_mips_r2 | \
cpu_has_mips_r6)
#define cpu_has_mips32 (cpu_has_mips32r1 | cpu_has_mips32r2)
#define cpu_has_mips64 (cpu_has_mips64r1 | cpu_has_mips64r2)
#define cpu_has_mips32 (cpu_has_mips32r1 | cpu_has_mips32r2 | cpu_has_mips32r6)
#define cpu_has_mips64 (cpu_has_mips64r1 | cpu_has_mips64r2 | cpu_has_mips64r6)
#define cpu_has_mips_r1 (cpu_has_mips32r1 | cpu_has_mips64r1)
#define cpu_has_mips_r2 (cpu_has_mips32r2 | cpu_has_mips64r2)
#define cpu_has_mips_r6 (cpu_has_mips32r6 | cpu_has_mips64r6)
#define cpu_has_mips_r (cpu_has_mips32r1 | cpu_has_mips32r2 | \
cpu_has_mips64r1 | cpu_has_mips64r2)
cpu_has_mips32r6 | cpu_has_mips64r1 | \
cpu_has_mips64r2 | cpu_has_mips64r6)
/* MIPSR2 and MIPSR6 have a lot of similarities */
#define cpu_has_mips_r2_r6 (cpu_has_mips_r2 | cpu_has_mips_r6)
#ifndef cpu_has_mips_r2_exec_hazard
#define cpu_has_mips_r2_exec_hazard cpu_has_mips_r2
#define cpu_has_mips_r2_exec_hazard (cpu_has_mips_r2 | cpu_has_mips_r6)
#endif
/*
......
......@@ -54,6 +54,13 @@ static inline int __pure __get_cpu_type(const int cpu_type)
case CPU_M5150:
#endif
#if defined(CONFIG_SYS_HAS_CPU_MIPS32_R2) || \
defined(CONFIG_SYS_HAS_CPU_MIPS32_R6) || \
defined(CONFIG_SYS_HAS_CPU_MIPS64_R2) || \
defined(CONFIG_SYS_HAS_CPU_MIPS64_R6)
case CPU_QEMU_GENERIC:
#endif
#ifdef CONFIG_SYS_HAS_CPU_MIPS64_R1
case CPU_5KC:
case CPU_5KE:
......
......@@ -93,6 +93,7 @@
* These are the PRID's for when 23:16 == PRID_COMP_MIPS
*/
#define PRID_IMP_QEMU_GENERIC 0x0000
#define PRID_IMP_4KC 0x8000
#define PRID_IMP_5KC 0x8100
#define PRID_IMP_20KC 0x8200
......@@ -312,6 +313,8 @@ enum cpu_type_enum {
CPU_LOONGSON3, CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS,
CPU_CAVIUM_OCTEON2, CPU_CAVIUM_OCTEON3, CPU_XLR, CPU_XLP,
CPU_QEMU_GENERIC,
CPU_LAST
};
......@@ -329,11 +332,14 @@ enum cpu_type_enum {
#define MIPS_CPU_ISA_M32R2 0x00000020
#define MIPS_CPU_ISA_M64R1 0x00000040
#define MIPS_CPU_ISA_M64R2 0x00000080
#define MIPS_CPU_ISA_M32R6 0x00000100
#define MIPS_CPU_ISA_M64R6 0x00000200
#define MIPS_CPU_ISA_32BIT (MIPS_CPU_ISA_II | MIPS_CPU_ISA_M32R1 | \
MIPS_CPU_ISA_M32R2)
MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M32R6)
#define MIPS_CPU_ISA_64BIT (MIPS_CPU_ISA_III | MIPS_CPU_ISA_IV | \
MIPS_CPU_ISA_V | MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)
MIPS_CPU_ISA_V | MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2 | \
MIPS_CPU_ISA_M64R6)
/*
* CPU Option encodings
......@@ -370,6 +376,7 @@ enum cpu_type_enum {
#define MIPS_CPU_RIXIEX 0x200000000ull /* CPU has unique exception codes for {Read, Execute}-Inhibit exceptions */
#define MIPS_CPU_MAAR 0x400000000ull /* MAAR(I) registers are present */
#define MIPS_CPU_FRE 0x800000000ull /* FRE & UFE bits implemented */
#define MIPS_CPU_RW_LLB 0x1000000000ull /* LLADDR/LLB writes are allowed */
/*
* CPU ASE encodings
......
......@@ -26,8 +26,8 @@ static inline void atomic_scrub(void *va, u32 size)
" sc %0, %1 \n"
" beqz %0, 1b \n"
" .set mips0 \n"
: "=&r" (temp), "=" GCC_OFF12_ASM() (*virt_addr)
: GCC_OFF12_ASM() (*virt_addr));
: "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*virt_addr)
: GCC_OFF_SMALL_ASM() (*virt_addr));
virt_addr++;
}
......
......@@ -417,13 +417,15 @@ extern unsigned long arch_randomize_brk(struct mm_struct *mm);
struct arch_elf_state {
int fp_abi;
int interp_fp_abi;
int overall_abi;
int overall_fp_mode;
};
#define MIPS_ABI_FP_UNKNOWN (-1) /* Unknown FP ABI (kernel internal) */
#define INIT_ARCH_ELF_STATE { \
.fp_abi = -1, \
.interp_fp_abi = -1, \
.overall_abi = -1, \
.fp_abi = MIPS_ABI_FP_UNKNOWN, \
.interp_fp_abi = MIPS_ABI_FP_UNKNOWN, \
.overall_fp_mode = -1, \
}
extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf,
......
......@@ -68,7 +68,8 @@ static inline int __enable_fpu(enum fpu_mode mode)
goto fr_common;
case FPU_64BIT:
#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_64BIT))
#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_CPU_MIPS32_R6) \
|| defined(CONFIG_64BIT))
/* we only have a 32-bit FPU */
return SIGFPE;
#endif
......
......@@ -45,19 +45,19 @@
" "__UA_ADDR "\t2b, 4b \n" \
" .previous \n" \
: "=r" (ret), "=&r" (oldval), \
"=" GCC_OFF12_ASM() (*uaddr) \
: "0" (0), GCC_OFF12_ASM() (*uaddr), "Jr" (oparg), \
"=" GCC_OFF_SMALL_ASM() (*uaddr) \
: "0" (0), GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oparg), \
"i" (-EFAULT) \
: "memory"); \
} else if (cpu_has_llsc) { \
__asm__ __volatile__( \
" .set push \n" \
" .set noat \n" \
" .set arch=r4000 \n" \
" .set "MIPS_ISA_ARCH_LEVEL" \n" \
"1: "user_ll("%1", "%4")" # __futex_atomic_op\n" \
" .set mips0 \n" \
" " insn " \n" \
" .set arch=r4000 \n" \
" .set "MIPS_ISA_ARCH_LEVEL" \n" \
"2: "user_sc("$1", "%2")" \n" \
" beqz $1, 1b \n" \
__WEAK_LLSC_MB \
......@@ -74,8 +74,8 @@
" "__UA_ADDR "\t2b, 4b \n" \
" .previous \n" \
: "=r" (ret), "=&r" (oldval), \
"=" GCC_OFF12_ASM() (*uaddr) \
: "0" (0), GCC_OFF12_ASM() (*uaddr), "Jr" (oparg), \
"=" GCC_OFF_SMALL_ASM() (*uaddr) \
: "0" (0), GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oparg), \
"i" (-EFAULT) \
: "memory"); \
} else \
......@@ -174,8 +174,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
" "__UA_ADDR "\t1b, 4b \n"
" "__UA_ADDR "\t2b, 4b \n"
" .previous \n"
: "+r" (ret), "=&r" (val), "=" GCC_OFF12_ASM() (*uaddr)
: GCC_OFF12_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),
: "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr)
: GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),
"i" (-EFAULT)
: "memory");
} else if (cpu_has_llsc) {
......@@ -183,12 +183,12 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
"# futex_atomic_cmpxchg_inatomic \n"
" .set push \n"
" .set noat \n"
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
"1: "user_ll("%1", "%3")" \n"
" bne %1, %z4, 3f \n"
" .set mips0 \n"
" move $1, %z5 \n"
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
"2: "user_sc("$1", "%2")" \n"
" beqz $1, 1b \n"
__WEAK_LLSC_MB
......@@ -203,8 +203,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
" "__UA_ADDR "\t1b, 4b \n"
" "__UA_ADDR "\t2b, 4b \n"
" .previous \n"
: "+r" (ret), "=&r" (val), "=" GCC_OFF12_ASM() (*uaddr)
: GCC_OFF12_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),
: "+r" (ret), "=&r" (val), "=" GCC_OFF_SMALL_ASM() (*uaddr)
: GCC_OFF_SMALL_ASM() (*uaddr), "Jr" (oldval), "Jr" (newval),
"i" (-EFAULT)
: "memory");
} else
......
......@@ -11,6 +11,7 @@
#define _ASM_HAZARDS_H
#include <linux/stringify.h>
#include <asm/compiler.h>
#define ___ssnop \
sll $0, $0, 1
......@@ -21,7 +22,7 @@
/*
* TLB hazards
*/
#if defined(CONFIG_CPU_MIPSR2) && !defined(CONFIG_CPU_CAVIUM_OCTEON)
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) && !defined(CONFIG_CPU_CAVIUM_OCTEON)
/*
* MIPSR2 defines ehb for hazard avoidance
......@@ -58,7 +59,7 @@ do { \
unsigned long tmp; \
\
__asm__ __volatile__( \
" .set mips64r2 \n" \
" .set "MIPS_ISA_LEVEL" \n" \
" dla %0, 1f \n" \
" jr.hb %0 \n" \
" .set mips0 \n" \
......@@ -132,7 +133,7 @@ do { \
#define instruction_hazard() \
do { \
if (cpu_has_mips_r2) \
if (cpu_has_mips_r2_r6) \
__instruction_hazard(); \
} while (0)
......@@ -240,7 +241,7 @@ do { \
#define __disable_fpu_hazard
#elif defined(CONFIG_CPU_MIPSR2)
#elif defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
#define __enable_fpu_hazard \
___ehb
......
......@@ -15,9 +15,10 @@
#include <linux/compiler.h>
#include <linux/stringify.h>
#include <asm/compiler.h>
#include <asm/hazards.h>
#ifdef CONFIG_CPU_MIPSR2
#if defined(CONFIG_CPU_MIPSR2) || defined (CONFIG_CPU_MIPSR6)
static inline void arch_local_irq_disable(void)
{
......@@ -118,7 +119,7 @@ void arch_local_irq_disable(void);
unsigned long arch_local_irq_save(void);
void arch_local_irq_restore(unsigned long flags);
void __arch_local_irq_restore(unsigned long flags);
#endif /* CONFIG_CPU_MIPSR2 */
#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */
static inline void arch_local_irq_enable(void)
{
......@@ -126,7 +127,7 @@ static inline void arch_local_irq_enable(void)
" .set push \n"
" .set reorder \n"
" .set noat \n"
#if defined(CONFIG_CPU_MIPSR2)
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
" ei \n"
#else
" mfc0 $1,$12 \n"
......
......@@ -5,6 +5,7 @@
#include <linux/bitops.h>
#include <linux/atomic.h>
#include <asm/cmpxchg.h>
#include <asm/compiler.h>
#include <asm/war.h>
typedef struct
......@@ -47,7 +48,7 @@ static __inline__ long local_add_return(long i, local_t * l)
unsigned long temp;
__asm__ __volatile__(
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
"1:" __LL "%1, %2 # local_add_return \n"
" addu %0, %1, %3 \n"
__SC "%0, %2 \n"
......@@ -92,7 +93,7 @@ static __inline__ long local_sub_return(long i, local_t * l)
unsigned long temp;
__asm__ __volatile__(
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
"1:" __LL "%1, %2 # local_sub_return \n"
" subu %0, %1, %3 \n"
__SC "%0, %2 \n"
......
......@@ -85,8 +85,8 @@ static inline void set_value_reg32(volatile u32 *const addr,
" "__beqz"%0, 1b \n"
" nop \n"
" .set pop \n"
: "=&r" (temp), "=" GCC_OFF12_ASM() (*addr)
: "ir" (~mask), "ir" (value), GCC_OFF12_ASM() (*addr));
: "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*addr)
: "ir" (~mask), "ir" (value), GCC_OFF_SMALL_ASM() (*addr));
}
/*
......@@ -106,8 +106,8 @@ static inline void set_reg32(volatile u32 *const addr,
" "__beqz"%0, 1b \n"
" nop \n"
" .set pop \n"
: "=&r" (temp), "=" GCC_OFF12_ASM() (*addr)
: "ir" (mask), GCC_OFF12_ASM() (*addr));
: "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*addr)
: "ir" (mask), GCC_OFF_SMALL_ASM() (*addr));
}
/*
......@@ -127,8 +127,8 @@ static inline void clear_reg32(volatile u32 *const addr,
" "__beqz"%0, 1b \n"
" nop \n"
" .set pop \n"
: "=&r" (temp), "=" GCC_OFF12_ASM() (*addr)
: "ir" (~mask), GCC_OFF12_ASM() (*addr));
: "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*addr)
: "ir" (~mask), GCC_OFF_SMALL_ASM() (*addr));
}
/*
......@@ -148,8 +148,8 @@ static inline void toggle_reg32(volatile u32 *const addr,
" "__beqz"%0, 1b \n"
" nop \n"
" .set pop \n"
: "=&r" (temp), "=" GCC_OFF12_ASM() (*addr)
: "ir" (mask), GCC_OFF12_ASM() (*addr));
: "=&r" (temp), "=" GCC_OFF_SMALL_ASM() (*addr)
: "ir" (mask), GCC_OFF_SMALL_ASM() (*addr));
}
/*
......@@ -220,8 +220,8 @@ static inline u32 blocking_read_reg32(volatile u32 *const addr)
" .set arch=r4000 \n" \
"1: ll %0, %1 #custom_read_reg32 \n" \
" .set pop \n" \
: "=r" (tmp), "=" GCC_OFF12_ASM() (*address) \
: GCC_OFF12_ASM() (*address))
: "=r" (tmp), "=" GCC_OFF_SMALL_ASM() (*address) \
: GCC_OFF_SMALL_ASM() (*address))
#define custom_write_reg32(address, tmp) \
__asm__ __volatile__( \
......@@ -231,7 +231,7 @@ static inline u32 blocking_read_reg32(volatile u32 *const addr)
" "__beqz"%0, 1b \n" \
" nop \n" \
" .set pop \n" \
: "=&r" (tmp), "=" GCC_OFF12_ASM() (*address) \
: "0" (tmp), GCC_OFF12_ASM() (*address))
: "=&r" (tmp), "=" GCC_OFF_SMALL_ASM() (*address) \
: "0" (tmp), GCC_OFF_SMALL_ASM() (*address))
#endif /* __ASM_REGOPS_H__ */
/*
* 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.
*
* Copyright (c) 2014 Imagination Technologies Ltd.
* Author: Markos Chandras <markos.chandras@imgtec.com>
*/
#ifndef __ASM_MIPS_R2_TO_R6_EMUL_H
#define __ASM_MIPS_R2_TO_R6_EMUL_H
struct mips_r2_emulator_stats {
u64 movs;
u64 hilo;
u64 muls;
u64 divs;
u64 dsps;
u64 bops;
u64 traps;
u64 fpus;
u64 loads;
u64 stores;
u64 llsc;
u64 dsemul;
};
struct mips_r2br_emulator_stats {
u64 jrs;
u64 bltzl;
u64 bgezl;
u64 bltzll;
u64 bgezll;
u64 bltzall;
u64 bgezall;
u64 bltzal;
u64 bgezal;
u64 beql;
u64 bnel;
u64 blezl;
u64 bgtzl;
};
#ifdef CONFIG_DEBUG_FS
#define MIPS_R2_STATS(M) \
do { \
u32 nir; \
int err; \
\
preempt_disable(); \
__this_cpu_inc(mipsr2emustats.M); \
err = __get_user(nir, (u32 __user *)regs->cp0_epc); \
if (!err) { \
if (nir == BREAK_MATH) \
__this_cpu_inc(mipsr2bdemustats.M); \
} \
preempt_enable(); \
} while (0)
#define MIPS_R2BR_STATS(M) \
do { \
preempt_disable(); \
__this_cpu_inc(mipsr2bremustats.M); \
preempt_enable(); \
} while (0)
#else
#define MIPS_R2_STATS(M) do { } while (0)
#define MIPS_R2BR_STATS(M) do { } while (0)
#endif /* CONFIG_DEBUG_FS */
struct r2_decoder_table {
u32 mask;
u32 code;
int (*func)(struct pt_regs *regs, u32 inst);
};
extern void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
const char *str);
#ifndef CONFIG_MIPSR2_TO_R6_EMULATOR
static int mipsr2_emulation;
static __maybe_unused int mipsr2_decoder(struct pt_regs *regs, u32 inst) { return 0; };
#else
/* MIPS R2 Emulator ON/OFF */
extern int mipsr2_emulation;
extern int mipsr2_decoder(struct pt_regs *regs, u32 inst);
#endif /* CONFIG_MIPSR2_TO_R6_EMULATOR */
#define NO_R6EMU (cpu_has_mips_r6 && !mipsr2_emulation)
#endif /* __ASM_MIPS_R2_TO_R6_EMUL_H */
......@@ -653,6 +653,7 @@
#define MIPS_CONF5_NF (_ULCAST_(1) << 0)
#define MIPS_CONF5_UFR (_ULCAST_(1) << 2)
#define MIPS_CONF5_MRP (_ULCAST_(1) << 3)
#define MIPS_CONF5_LLB (_ULCAST_(1) << 4)
#define MIPS_CONF5_MVH (_ULCAST_(1) << 5)
#define MIPS_CONF5_FRE (_ULCAST_(1) << 8)
#define MIPS_CONF5_UFE (_ULCAST_(1) << 9)
......@@ -1127,6 +1128,8 @@ do { \
#define write_c0_config6(val) __write_32bit_c0_register($16, 6, val)
#define write_c0_config7(val) __write_32bit_c0_register($16, 7, val)
#define read_c0_lladdr() __read_ulong_c0_register($17, 0)
#define write_c0_lladdr(val) __write_ulong_c0_register($17, 0, val)
#define read_c0_maar() __read_ulong_c0_register($17, 1)
#define write_c0_maar(val) __write_ulong_c0_register($17, 1, val)
#define read_c0_maari() __read_32bit_c0_register($17, 2)
......
......@@ -88,10 +88,14 @@ search_module_dbetables(unsigned long addr)
#define MODULE_PROC_FAMILY "MIPS32_R1 "
#elif defined CONFIG_CPU_MIPS32_R2
#define MODULE_PROC_FAMILY "MIPS32_R2 "
#elif defined CONFIG_CPU_MIPS32_R6
#define MODULE_PROC_FAMILY "MIPS32_R6 "
#elif defined CONFIG_CPU_MIPS64_R1
#define MODULE_PROC_FAMILY "MIPS64_R1 "
#elif defined CONFIG_CPU_MIPS64_R2
#define MODULE_PROC_FAMILY "MIPS64_R2 "
#elif defined CONFIG_CPU_MIPS64_R6
#define MODULE_PROC_FAMILY "MIPS64_R6 "
#elif defined CONFIG_CPU_R3000
#define MODULE_PROC_FAMILY "R3000 "
#elif defined CONFIG_CPU_TX39XX
......
......@@ -275,7 +275,7 @@ static inline void __cvmx_cmd_queue_lock(cvmx_cmd_queue_id_t queue_id,
" lbu %[ticket], %[now_serving]\n"
"4:\n"
".set pop\n" :
[ticket_ptr] "=" GCC_OFF12_ASM()(__cvmx_cmd_queue_state_ptr->ticket[__cvmx_cmd_queue_get_index(queue_id)]),
[ticket_ptr] "=" GCC_OFF_SMALL_ASM()(__cvmx_cmd_queue_state_ptr->ticket[__cvmx_cmd_queue_get_index(queue_id)]),
[now_serving] "=m"(qptr->now_serving), [ticket] "=r"(tmp),
[my_ticket] "=r"(my_ticket)
);
......
......@@ -14,6 +14,7 @@
#include <asm/asm.h>
#include <asm/cacheops.h>
#include <asm/compiler.h>
#include <asm/cpu-features.h>
#include <asm/cpu-type.h>
#include <asm/mipsmtregs.h>
......@@ -39,7 +40,7 @@ extern void (*r4k_blast_icache)(void);
__asm__ __volatile__( \
" .set push \n" \
" .set noreorder \n" \
" .set arch=r4000 \n" \
" .set "MIPS_ISA_ARCH_LEVEL" \n" \
" cache %0, %1 \n" \
" .set pop \n" \
: \
......@@ -147,7 +148,7 @@ static inline void flush_scache_line(unsigned long addr)
__asm__ __volatile__( \
" .set push \n" \
" .set noreorder \n" \
" .set arch=r4000 \n" \
" .set "MIPS_ISA_ARCH_LEVEL" \n" \
"1: cache %0, (%1) \n" \
"2: .set pop \n" \
" .section __ex_table,\"a\" \n" \
......@@ -218,6 +219,7 @@ static inline void invalidate_tcache_page(unsigned long addr)
cache_op(Page_Invalidate_T, addr);
}
#ifndef CONFIG_CPU_MIPSR6
#define cache16_unroll32(base,op) \
__asm__ __volatile__( \
" .set push \n" \
......@@ -322,6 +324,150 @@ static inline void invalidate_tcache_page(unsigned long addr)
: "r" (base), \
"i" (op));
#else
/*
* MIPS R6 changed the cache opcode and moved to a 8-bit offset field.
* This means we now need to increment the base register before we flush
* more cache lines
*/
#define cache16_unroll32(base,op) \
__asm__ __volatile__( \
" .set push\n" \
" .set noreorder\n" \
" .set mips64r6\n" \
" .set noat\n" \
" cache %1, 0x000(%0); cache %1, 0x010(%0)\n" \
" cache %1, 0x020(%0); cache %1, 0x030(%0)\n" \
" cache %1, 0x040(%0); cache %1, 0x050(%0)\n" \
" cache %1, 0x060(%0); cache %1, 0x070(%0)\n" \
" cache %1, 0x080(%0); cache %1, 0x090(%0)\n" \
" cache %1, 0x0a0(%0); cache %1, 0x0b0(%0)\n" \
" cache %1, 0x0c0(%0); cache %1, 0x0d0(%0)\n" \
" cache %1, 0x0e0(%0); cache %1, 0x0f0(%0)\n" \
" addiu $1, $0, 0x100 \n" \
" cache %1, 0x000($1); cache %1, 0x010($1)\n" \
" cache %1, 0x020($1); cache %1, 0x030($1)\n" \
" cache %1, 0x040($1); cache %1, 0x050($1)\n" \
" cache %1, 0x060($1); cache %1, 0x070($1)\n" \
" cache %1, 0x080($1); cache %1, 0x090($1)\n" \
" cache %1, 0x0a0($1); cache %1, 0x0b0($1)\n" \
" cache %1, 0x0c0($1); cache %1, 0x0d0($1)\n" \
" cache %1, 0x0e0($1); cache %1, 0x0f0($1)\n" \
" .set pop\n" \
: \
: "r" (base), \
"i" (op));
#define cache32_unroll32(base,op) \
__asm__ __volatile__( \
" .set push\n" \
" .set noreorder\n" \
" .set mips64r6\n" \
" .set noat\n" \
" cache %1, 0x000(%0); cache %1, 0x020(%0)\n" \
" cache %1, 0x040(%0); cache %1, 0x060(%0)\n" \
" cache %1, 0x080(%0); cache %1, 0x0a0(%0)\n" \
" cache %1, 0x0c0(%0); cache %1, 0x0e0(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000($1); cache %1, 0x020($1)\n" \
" cache %1, 0x040($1); cache %1, 0x060($1)\n" \
" cache %1, 0x080($1); cache %1, 0x0a0($1)\n" \
" cache %1, 0x0c0($1); cache %1, 0x0e0($1)\n" \
" addiu $1, $1, 0x100\n" \
" cache %1, 0x000($1); cache %1, 0x020($1)\n" \
" cache %1, 0x040($1); cache %1, 0x060($1)\n" \
" cache %1, 0x080($1); cache %1, 0x0a0($1)\n" \
" cache %1, 0x0c0($1); cache %1, 0x0e0($1)\n" \
" addiu $1, $1, 0x100\n" \
" cache %1, 0x000($1); cache %1, 0x020($1)\n" \
" cache %1, 0x040($1); cache %1, 0x060($1)\n" \
" cache %1, 0x080($1); cache %1, 0x0a0($1)\n" \
" cache %1, 0x0c0($1); cache %1, 0x0e0($1)\n" \
" .set pop\n" \
: \
: "r" (base), \
"i" (op));
#define cache64_unroll32(base,op) \
__asm__ __volatile__( \
" .set push\n" \
" .set noreorder\n" \
" .set mips64r6\n" \
" .set noat\n" \
" cache %1, 0x000(%0); cache %1, 0x040(%0)\n" \
" cache %1, 0x080(%0); cache %1, 0x0c0(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000($1); cache %1, 0x040($1)\n" \
" cache %1, 0x080($1); cache %1, 0x0c0($1)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000($1); cache %1, 0x040($1)\n" \
" cache %1, 0x080($1); cache %1, 0x0c0($1)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000($1); cache %1, 0x040($1)\n" \
" cache %1, 0x080($1); cache %1, 0x0c0($1)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000($1); cache %1, 0x040($1)\n" \
" cache %1, 0x080($1); cache %1, 0x0c0($1)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000($1); cache %1, 0x040($1)\n" \
" cache %1, 0x080($1); cache %1, 0x0c0($1)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000($1); cache %1, 0x040($1)\n" \
" cache %1, 0x080($1); cache %1, 0x0c0($1)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000($1); cache %1, 0x040($1)\n" \
" cache %1, 0x080($1); cache %1, 0x0c0($1)\n" \
" .set pop\n" \
: \
: "r" (base), \
"i" (op));
#define cache128_unroll32(base,op) \
__asm__ __volatile__( \
" .set push\n" \
" .set noreorder\n" \
" .set mips64r6\n" \
" .set noat\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" cache %1, 0x000(%0); cache %1, 0x080(%0)\n" \
" addiu $1, %0, 0x100\n" \
" .set pop\n" \
: \
: "r" (base), \
"i" (op));
#endif /* CONFIG_CPU_MIPSR6 */
/*
* Perform the cache operation specified by op using a user mode virtual
* address while in kernel mode.
......
......@@ -89,7 +89,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
" subu %[ticket], %[ticket], 1 \n"
" .previous \n"
" .set pop \n"
: [ticket_ptr] "+" GCC_OFF12_ASM() (lock->lock),
: [ticket_ptr] "+" GCC_OFF_SMALL_ASM() (lock->lock),
[serving_now_ptr] "+m" (lock->h.serving_now),
[ticket] "=&r" (tmp),
[my_ticket] "=&r" (my_ticket)
......@@ -122,7 +122,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
" subu %[ticket], %[ticket], 1 \n"
" .previous \n"
" .set pop \n"
: [ticket_ptr] "+" GCC_OFF12_ASM() (lock->lock),
: [ticket_ptr] "+" GCC_OFF_SMALL_ASM() (lock->lock),
[serving_now_ptr] "+m" (lock->h.serving_now),
[ticket] "=&r" (tmp),
[my_ticket] "=&r" (my_ticket)
......@@ -164,7 +164,7 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock)
" li %[ticket], 0 \n"
" .previous \n"
" .set pop \n"
: [ticket_ptr] "+" GCC_OFF12_ASM() (lock->lock),
: [ticket_ptr] "+" GCC_OFF_SMALL_ASM() (lock->lock),
[ticket] "=&r" (tmp),
[my_ticket] "=&r" (tmp2),
[now_serving] "=&r" (tmp3)
......@@ -188,7 +188,7 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock)
" li %[ticket], 0 \n"
" .previous \n"
" .set pop \n"
: [ticket_ptr] "+" GCC_OFF12_ASM() (lock->lock),
: [ticket_ptr] "+" GCC_OFF_SMALL_ASM() (lock->lock),
[ticket] "=&r" (tmp),
[my_ticket] "=&r" (tmp2),
[now_serving] "=&r" (tmp3)
......@@ -235,8 +235,8 @@ static inline void arch_read_lock(arch_rwlock_t *rw)
" beqzl %1, 1b \n"
" nop \n"
" .set reorder \n"
: "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp)
: GCC_OFF12_ASM() (rw->lock)
: "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp)
: GCC_OFF_SMALL_ASM() (rw->lock)
: "memory");
} else {
do {
......@@ -245,8 +245,8 @@ static inline void arch_read_lock(arch_rwlock_t *rw)
" bltz %1, 1b \n"
" addu %1, 1 \n"
"2: sc %1, %0 \n"
: "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp)
: GCC_OFF12_ASM() (rw->lock)
: "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp)
: GCC_OFF_SMALL_ASM() (rw->lock)
: "memory");
} while (unlikely(!tmp));
}
......@@ -254,9 +254,6 @@ static inline void arch_read_lock(arch_rwlock_t *rw)
smp_llsc_mb();
}
/* Note the use of sub, not subu which will make the kernel die with an
overflow exception if we ever try to unlock an rwlock that is already
unlocked or is being held by a writer. */
static inline void arch_read_unlock(arch_rwlock_t *rw)
{
unsigned int tmp;
......@@ -266,20 +263,20 @@ static inline void arch_read_unlock(arch_rwlock_t *rw)
if (R10000_LLSC_WAR) {
__asm__ __volatile__(
"1: ll %1, %2 # arch_read_unlock \n"
" sub %1, 1 \n"
" addiu %1, 1 \n"
" sc %1, %0 \n"
" beqzl %1, 1b \n"
: "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp)
: GCC_OFF12_ASM() (rw->lock)
: "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp)
: GCC_OFF_SMALL_ASM() (rw->lock)
: "memory");
} else {
do {
__asm__ __volatile__(
"1: ll %1, %2 # arch_read_unlock \n"
" sub %1, 1 \n"
" addiu %1, -1 \n"
" sc %1, %0 \n"
: "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp)
: GCC_OFF12_ASM() (rw->lock)
: "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp)
: GCC_OFF_SMALL_ASM() (rw->lock)
: "memory");
} while (unlikely(!tmp));
}
......@@ -299,8 +296,8 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
" beqzl %1, 1b \n"
" nop \n"
" .set reorder \n"
: "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp)
: GCC_OFF12_ASM() (rw->lock)
: "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp)
: GCC_OFF_SMALL_ASM() (rw->lock)
: "memory");
} else {
do {
......@@ -309,8 +306,8 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
" bnez %1, 1b \n"
" lui %1, 0x8000 \n"
"2: sc %1, %0 \n"
: "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp)
: GCC_OFF12_ASM() (rw->lock)
: "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp)
: GCC_OFF_SMALL_ASM() (rw->lock)
: "memory");
} while (unlikely(!tmp));
}
......@@ -349,8 +346,8 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
__WEAK_LLSC_MB
" li %2, 1 \n"
"2: \n"
: "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret)
: GCC_OFF12_ASM() (rw->lock)
: "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret)
: GCC_OFF_SMALL_ASM() (rw->lock)
: "memory");
} else {
__asm__ __volatile__(
......@@ -366,8 +363,8 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
__WEAK_LLSC_MB
" li %2, 1 \n"
"2: \n"
: "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret)
: GCC_OFF12_ASM() (rw->lock)
: "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret)
: GCC_OFF_SMALL_ASM() (rw->lock)
: "memory");
}
......@@ -393,8 +390,8 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
" li %2, 1 \n"
" .set reorder \n"
"2: \n"
: "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret)
: GCC_OFF12_ASM() (rw->lock)
: "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp), "=&r" (ret)
: GCC_OFF_SMALL_ASM() (rw->lock)
: "memory");
} else {
do {
......@@ -406,9 +403,9 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
" sc %1, %0 \n"
" li %2, 1 \n"
"2: \n"
: "=" GCC_OFF12_ASM() (rw->lock), "=&r" (tmp),
: "=" GCC_OFF_SMALL_ASM() (rw->lock), "=&r" (tmp),
"=&r" (ret)
: GCC_OFF12_ASM() (rw->lock)
: GCC_OFF_SMALL_ASM() (rw->lock)
: "memory");
} while (unlikely(!tmp));
......
#ifndef _MIPS_SPRAM_H
#define _MIPS_SPRAM_H
#ifdef CONFIG_CPU_MIPSR2
#if defined(CONFIG_MIPS_SPRAM)
extern __init void spram_config(void);
#else
static inline void spram_config(void) { };
#endif /* CONFIG_CPU_MIPSR2 */
#endif /* CONFIG_MIPS_SPRAM */
#endif /* _MIPS_SPRAM_H */
......@@ -40,7 +40,7 @@
LONG_S v1, PT_HI(sp)
mflhxu v1
LONG_S v1, PT_ACX(sp)
#else
#elif !defined(CONFIG_CPU_MIPSR6)
mfhi v1
#endif
#ifdef CONFIG_32BIT
......@@ -50,7 +50,7 @@
LONG_S $10, PT_R10(sp)
LONG_S $11, PT_R11(sp)
LONG_S $12, PT_R12(sp)
#ifndef CONFIG_CPU_HAS_SMARTMIPS
#if !defined(CONFIG_CPU_HAS_SMARTMIPS) && !defined(CONFIG_CPU_MIPSR6)
LONG_S v1, PT_HI(sp)
mflo v1
#endif
......@@ -58,7 +58,7 @@
LONG_S $14, PT_R14(sp)
LONG_S $15, PT_R15(sp)
LONG_S $24, PT_R24(sp)
#ifndef CONFIG_CPU_HAS_SMARTMIPS
#if !defined(CONFIG_CPU_HAS_SMARTMIPS) && !defined(CONFIG_CPU_MIPSR6)
LONG_S v1, PT_LO(sp)
#endif
#ifdef CONFIG_CPU_CAVIUM_OCTEON
......@@ -226,7 +226,7 @@
mtlhx $24
LONG_L $24, PT_LO(sp)
mtlhx $24
#else
#elif !defined(CONFIG_CPU_MIPSR6)
LONG_L $24, PT_LO(sp)
mtlo $24
LONG_L $24, PT_HI(sp)
......
......@@ -75,9 +75,12 @@ do { \
#endif
#define __clear_software_ll_bit() \
do { \
if (!__builtin_constant_p(cpu_has_llsc) || !cpu_has_llsc) \
ll_bit = 0; \
do { if (cpu_has_rw_llb) { \
write_c0_lladdr(0); \
} else { \
if (!__builtin_constant_p(cpu_has_llsc) || !cpu_has_llsc)\
ll_bit = 0; \
} \
} while (0)
#define switch_to(prev, next, last) \
......
......@@ -28,7 +28,7 @@ struct thread_info {
unsigned long tp_value; /* thread pointer */
__u32 cpu; /* current CPU */
int preempt_count; /* 0 => preemptable, <0 => BUG */
int r2_emul_return; /* 1 => Returning from R2 emulator */
mm_segment_t addr_limit; /*
* thread address space limit:
* 0x7fffffff for user-thead
......
......@@ -21,20 +21,20 @@
enum major_op {
spec_op, bcond_op, j_op, jal_op,
beq_op, bne_op, blez_op, bgtz_op,
addi_op, addiu_op, slti_op, sltiu_op,
addi_op, cbcond0_op = addi_op, addiu_op, slti_op, sltiu_op,
andi_op, ori_op, xori_op, lui_op,
cop0_op, cop1_op, cop2_op, cop1x_op,
beql_op, bnel_op, blezl_op, bgtzl_op,
daddi_op, daddiu_op, ldl_op, ldr_op,
daddi_op, cbcond1_op = daddi_op, daddiu_op, ldl_op, ldr_op,
spec2_op, jalx_op, mdmx_op, spec3_op,
lb_op, lh_op, lwl_op, lw_op,
lbu_op, lhu_op, lwr_op, lwu_op,
sb_op, sh_op, swl_op, sw_op,
sdl_op, sdr_op, swr_op, cache_op,
ll_op, lwc1_op, lwc2_op, pref_op,
lld_op, ldc1_op, ldc2_op, ld_op,
sc_op, swc1_op, swc2_op, major_3b_op,
scd_op, sdc1_op, sdc2_op, sd_op
ll_op, lwc1_op, lwc2_op, bc6_op = lwc2_op, pref_op,
lld_op, ldc1_op, ldc2_op, beqzcjic_op = ldc2_op, ld_op,
sc_op, swc1_op, swc2_op, balc6_op = swc2_op, major_3b_op,
scd_op, sdc1_op, sdc2_op, bnezcjialc_op = sdc2_op, sd_op
};
/*
......@@ -83,9 +83,12 @@ enum spec3_op {
swe_op = 0x1f, bshfl_op = 0x20,
swle_op = 0x21, swre_op = 0x22,
prefe_op = 0x23, dbshfl_op = 0x24,
lbue_op = 0x28, lhue_op = 0x29,
lbe_op = 0x2c, lhe_op = 0x2d,
lle_op = 0x2e, lwe_op = 0x2f,
cache6_op = 0x25, sc6_op = 0x26,
scd6_op = 0x27, lbue_op = 0x28,
lhue_op = 0x29, lbe_op = 0x2c,
lhe_op = 0x2d, lle_op = 0x2e,
lwe_op = 0x2f, pref6_op = 0x35,
ll6_op = 0x36, lld6_op = 0x37,
rdhwr_op = 0x3b
};
......@@ -112,7 +115,8 @@ enum cop_op {
mfhc_op = 0x03, mtc_op = 0x04,
dmtc_op = 0x05, ctc_op = 0x06,
mthc0_op = 0x06, mthc_op = 0x07,
bc_op = 0x08, cop_op = 0x10,
bc_op = 0x08, bc1eqz_op = 0x09,
bc1nez_op = 0x0d, cop_op = 0x10,
copm_op = 0x18
};
......
......@@ -52,7 +52,7 @@ obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o
obj-$(CONFIG_MIPS_CMP) += smp-cmp.o
obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o
obj-$(CONFIG_MIPS_GIC_IPI) += smp-gic.o
obj-$(CONFIG_CPU_MIPSR2) += spram.o
obj-$(CONFIG_MIPS_SPRAM) += spram.o
obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o
obj-$(CONFIG_MIPS_VPE_LOADER_CMP) += vpe-cmp.o
......@@ -90,6 +90,7 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_EARLY_PRINTK_8250) += early_printk_8250.o
obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o
obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o
obj-$(CONFIG_MIPSR2_TO_R6_EMULATOR) += mips-r2-to-r6-emul.o
CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -x c /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
......
......@@ -97,6 +97,7 @@ void output_thread_info_defines(void)
OFFSET(TI_TP_VALUE, thread_info, tp_value);
OFFSET(TI_CPU, thread_info, cpu);
OFFSET(TI_PRE_COUNT, thread_info, preempt_count);
OFFSET(TI_R2_EMUL_RET, thread_info, r2_emul_return);
OFFSET(TI_ADDR_LIMIT, thread_info, addr_limit);
OFFSET(TI_RESTART_BLOCK, thread_info, restart_block);
OFFSET(TI_REGS, thread_info, regs);
......
......@@ -16,6 +16,7 @@
#include <asm/fpu.h>
#include <asm/fpu_emulator.h>
#include <asm/inst.h>
#include <asm/mips-r2-to-r6-emul.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>
......@@ -399,11 +400,21 @@ int __MIPS16e_compute_return_epc(struct pt_regs *regs)
* @returns: -EFAULT on error and forces SIGBUS, and on success
* returns 0 or BRANCH_LIKELY_TAKEN as appropriate after
* evaluating the branch.
*
* MIPS R6 Compact branches and forbidden slots:
* Compact branches do not throw exceptions because they do
* not have delay slots. The forbidden slot instruction ($PC+4)
* is only executed if the branch was not taken. Otherwise the
* forbidden slot is skipped entirely. This means that the
* only possible reason to be here because of a MIPS R6 compact
* branch instruction is that the forbidden slot has thrown one.
* In that case the branch was not taken, so the EPC can be safely
* set to EPC + 8.
*/
int __compute_return_epc_for_insn(struct pt_regs *regs,
union mips_instruction insn)
{
unsigned int bit, fcr31, dspcontrol;
unsigned int bit, fcr31, dspcontrol, reg;
long epc = regs->cp0_epc;
int ret = 0;
......@@ -417,6 +428,8 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
regs->regs[insn.r_format.rd] = epc + 8;
/* Fall through */
case jr_op:
if (NO_R6EMU && insn.r_format.func == jr_op)
goto sigill_r6;
regs->cp0_epc = regs->regs[insn.r_format.rs];
break;
}
......@@ -429,8 +442,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
*/
case bcond_op:
switch (insn.i_format.rt) {
case bltz_op:
case bltzl_op:
if (NO_R6EMU)
goto sigill_r6;
case bltz_op:
if ((long)regs->regs[insn.i_format.rs] < 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == bltzl_op)
......@@ -440,8 +455,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
regs->cp0_epc = epc;
break;
case bgez_op:
case bgezl_op:
if (NO_R6EMU)
goto sigill_r6;
case bgez_op:
if ((long)regs->regs[insn.i_format.rs] >= 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == bgezl_op)
......@@ -453,7 +470,29 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
case bltzal_op:
case bltzall_op:
if (NO_R6EMU && (insn.i_format.rs ||
insn.i_format.rt == bltzall_op)) {
ret = -SIGILL;
break;
}
regs->regs[31] = epc + 8;
/*
* OK we are here either because we hit a NAL
* instruction or because we are emulating an
* old bltzal{,l} one. Lets figure out what the
* case really is.
*/
if (!insn.i_format.rs) {
/*
* NAL or BLTZAL with rs == 0
* Doesn't matter if we are R6 or not. The
* result is the same
*/
regs->cp0_epc += 4 +
(insn.i_format.simmediate << 2);
break;
}
/* Now do the real thing for non-R6 BLTZAL{,L} */
if ((long)regs->regs[insn.i_format.rs] < 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == bltzall_op)
......@@ -465,7 +504,29 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
case bgezal_op:
case bgezall_op:
if (NO_R6EMU && (insn.i_format.rs ||
insn.i_format.rt == bgezall_op)) {
ret = -SIGILL;
break;
}
regs->regs[31] = epc + 8;
/*
* OK we are here either because we hit a BAL
* instruction or because we are emulating an
* old bgezal{,l} one. Lets figure out what the
* case really is.
*/
if (!insn.i_format.rs) {
/*
* BAL or BGEZAL with rs == 0
* Doesn't matter if we are R6 or not. The
* result is the same
*/
regs->cp0_epc += 4 +
(insn.i_format.simmediate << 2);
break;
}
/* Now do the real thing for non-R6 BGEZAL{,L} */
if ((long)regs->regs[insn.i_format.rs] >= 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == bgezall_op)
......@@ -477,7 +538,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
case bposge32_op:
if (!cpu_has_dsp)
goto sigill;
goto sigill_dsp;
dspcontrol = rddsp(0x01);
......@@ -508,8 +569,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
/*
* These are conditional and in i_format.
*/
case beq_op:
case beql_op:
if (NO_R6EMU)
goto sigill_r6;
case beq_op:
if (regs->regs[insn.i_format.rs] ==
regs->regs[insn.i_format.rt]) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
......@@ -520,8 +583,10 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
regs->cp0_epc = epc;
break;
case bne_op:
case bnel_op:
if (NO_R6EMU)
goto sigill_r6;
case bne_op:
if (regs->regs[insn.i_format.rs] !=
regs->regs[insn.i_format.rt]) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
......@@ -532,8 +597,31 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
regs->cp0_epc = epc;
break;
case blez_op: /* not really i_format */
case blezl_op:
case blezl_op: /* not really i_format */
if (NO_R6EMU)
goto sigill_r6;
case blez_op:
/*
* Compact branches for R6 for the
* blez and blezl opcodes.
* BLEZ | rs = 0 | rt != 0 == BLEZALC
* BLEZ | rs = rt != 0 == BGEZALC
* BLEZ | rs != 0 | rt != 0 == BGEUC
* BLEZL | rs = 0 | rt != 0 == BLEZC
* BLEZL | rs = rt != 0 == BGEZC
* BLEZL | rs != 0 | rt != 0 == BGEC
*
* For real BLEZ{,L}, rt is always 0.
*/
if (cpu_has_mips_r6 && insn.i_format.rt) {
if ((insn.i_format.opcode == blez_op) &&
((!insn.i_format.rs && insn.i_format.rt) ||
(insn.i_format.rs == insn.i_format.rt)))
regs->regs[31] = epc + 4;
regs->cp0_epc += 8;
break;
}
/* rt field assumed to be zero */
if ((long)regs->regs[insn.i_format.rs] <= 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
......@@ -544,8 +632,32 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
regs->cp0_epc = epc;
break;
case bgtz_op:
case bgtzl_op:
if (NO_R6EMU)
goto sigill_r6;
case bgtz_op:
/*
* Compact branches for R6 for the
* bgtz and bgtzl opcodes.
* BGTZ | rs = 0 | rt != 0 == BGTZALC
* BGTZ | rs = rt != 0 == BLTZALC
* BGTZ | rs != 0 | rt != 0 == BLTUC
* BGTZL | rs = 0 | rt != 0 == BGTZC
* BGTZL | rs = rt != 0 == BLTZC
* BGTZL | rs != 0 | rt != 0 == BLTC
*
* *ZALC varint for BGTZ &&& rt != 0
* For real GTZ{,L}, rt is always 0.
*/
if (cpu_has_mips_r6 && insn.i_format.rt) {
if ((insn.i_format.opcode == blez_op) &&
((!insn.i_format.rs && insn.i_format.rt) ||
(insn.i_format.rs == insn.i_format.rt)))
regs->regs[31] = epc + 4;
regs->cp0_epc += 8;
break;
}
/* rt field assumed to be zero */
if ((long)regs->regs[insn.i_format.rs] > 0) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
......@@ -560,40 +672,83 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
* And now the FPA/cp1 branch instructions.
*/
case cop1_op:
preempt_disable();
if (is_fpu_owner())
fcr31 = read_32bit_cp1_register(CP1_STATUS);
else
fcr31 = current->thread.fpu.fcr31;
preempt_enable();
bit = (insn.i_format.rt >> 2);
bit += (bit != 0);
bit += 23;
switch (insn.i_format.rt & 3) {
case 0: /* bc1f */
case 2: /* bc1fl */
if (~fcr31 & (1 << bit)) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == 2)
ret = BRANCH_LIKELY_TAKEN;
} else
if (cpu_has_mips_r6 &&
((insn.i_format.rs == bc1eqz_op) ||
(insn.i_format.rs == bc1nez_op))) {
if (!used_math()) { /* First time FPU user */
ret = init_fpu();
if (ret && NO_R6EMU) {
ret = -ret;
break;
}
ret = 0;
set_used_math();
}
lose_fpu(1); /* Save FPU state for the emulator. */
reg = insn.i_format.rt;
bit = 0;
switch (insn.i_format.rs) {
case bc1eqz_op:
/* Test bit 0 */
if (get_fpr32(&current->thread.fpu.fpr[reg], 0)
& 0x1)
bit = 1;
break;
case bc1nez_op:
/* Test bit 0 */
if (!(get_fpr32(&current->thread.fpu.fpr[reg], 0)
& 0x1))
bit = 1;
break;
}
own_fpu(1);
if (bit)
epc = epc + 4 +
(insn.i_format.simmediate << 2);
else
epc += 8;
regs->cp0_epc = epc;
break;
} else {
case 1: /* bc1t */
case 3: /* bc1tl */
if (fcr31 & (1 << bit)) {
epc = epc + 4 + (insn.i_format.simmediate << 2);
if (insn.i_format.rt == 3)
ret = BRANCH_LIKELY_TAKEN;
} else
epc += 8;
regs->cp0_epc = epc;
preempt_disable();
if (is_fpu_owner())
fcr31 = read_32bit_cp1_register(CP1_STATUS);
else
fcr31 = current->thread.fpu.fcr31;
preempt_enable();
bit = (insn.i_format.rt >> 2);
bit += (bit != 0);
bit += 23;
switch (insn.i_format.rt & 3) {
case 0: /* bc1f */
case 2: /* bc1fl */
if (~fcr31 & (1 << bit)) {
epc = epc + 4 +
(insn.i_format.simmediate << 2);
if (insn.i_format.rt == 2)
ret = BRANCH_LIKELY_TAKEN;
} else
epc += 8;
regs->cp0_epc = epc;
break;
case 1: /* bc1t */
case 3: /* bc1tl */
if (fcr31 & (1 << bit)) {
epc = epc + 4 +
(insn.i_format.simmediate << 2);
if (insn.i_format.rt == 3)
ret = BRANCH_LIKELY_TAKEN;
} else
epc += 8;
regs->cp0_epc = epc;
break;
}
break;
}
break;
#ifdef CONFIG_CPU_CAVIUM_OCTEON
case lwc2_op: /* This is bbit0 on Octeon */
if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
......@@ -626,15 +781,72 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
epc += 8;
regs->cp0_epc = epc;
break;
#else
case bc6_op:
/* Only valid for MIPS R6 */
if (!cpu_has_mips_r6) {
ret = -SIGILL;
break;
}
regs->cp0_epc += 8;
break;
case balc6_op:
if (!cpu_has_mips_r6) {
ret = -SIGILL;
break;
}
/* Compact branch: BALC */
regs->regs[31] = epc + 4;
epc += 4 + (insn.i_format.simmediate << 2);
regs->cp0_epc = epc;
break;
case beqzcjic_op:
if (!cpu_has_mips_r6) {
ret = -SIGILL;
break;
}
/* Compact branch: BEQZC || JIC */
regs->cp0_epc += 8;
break;
case bnezcjialc_op:
if (!cpu_has_mips_r6) {
ret = -SIGILL;
break;
}
/* Compact branch: BNEZC || JIALC */
if (insn.i_format.rs)
regs->regs[31] = epc + 4;
regs->cp0_epc += 8;
break;
#endif
case cbcond0_op:
case cbcond1_op:
/* Only valid for MIPS R6 */
if (!cpu_has_mips_r6) {
ret = -SIGILL;
break;
}
/*
* Compact branches:
* bovc, beqc, beqzalc, bnvc, bnec, bnezlac
*/
if (insn.i_format.rt && !insn.i_format.rs)
regs->regs[31] = epc + 4;
regs->cp0_epc += 8;
break;
}
return ret;
sigill:
sigill_dsp:
printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
force_sig(SIGBUS, current);
return -EFAULT;
sigill_r6:
pr_info("%s: R2 branch but r2-to-r6 emulator is not preset - sending SIGILL.\n",
current->comm);
force_sig(SIGILL, current);
return -EFAULT;
}
EXPORT_SYMBOL_GPL(__compute_return_epc_for_insn);
......
......@@ -39,7 +39,7 @@ int cp0_timer_irq_installed;
irqreturn_t c0_compare_interrupt(int irq, void *dev_id)
{
const int r2 = cpu_has_mips_r2;
const int r2 = cpu_has_mips_r2_r6;
struct clock_event_device *cd;
int cpu = smp_processor_id();
......
......@@ -99,11 +99,11 @@ not_nmi:
xori t2, t1, 0x7
beqz t2, 1f
li t3, 32
addi t1, t1, 1
addiu t1, t1, 1
sllv t1, t3, t1
1: /* At this point t1 == I-cache sets per way */
_EXT t2, v0, MIPS_CONF1_IA_SHF, MIPS_CONF1_IA_SZ
addi t2, t2, 1
addiu t2, t2, 1
mul t1, t1, t0
mul t1, t1, t2
......@@ -126,11 +126,11 @@ icache_done:
xori t2, t1, 0x7
beqz t2, 1f
li t3, 32
addi t1, t1, 1
addiu t1, t1, 1
sllv t1, t3, t1
1: /* At this point t1 == D-cache sets per way */
_EXT t2, v0, MIPS_CONF1_DA_SHF, MIPS_CONF1_DA_SZ
addi t2, t2, 1
addiu t2, t2, 1
mul t1, t1, t0
mul t1, t1, t2
......@@ -250,7 +250,7 @@ LEAF(mips_cps_core_init)
mfc0 t0, CP0_MVPCONF0
srl t0, t0, MVPCONF0_PVPE_SHIFT
andi t0, t0, (MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT)
addi t7, t0, 1
addiu t7, t0, 1
/* If there's only 1, we're done */
beqz t0, 2f
......@@ -280,7 +280,7 @@ LEAF(mips_cps_core_init)
mttc0 t0, CP0_TCHALT
/* Next VPE */
addi t5, t5, 1
addiu t5, t5, 1
slt t0, t5, t7
bnez t0, 1b
nop
......@@ -317,7 +317,7 @@ LEAF(mips_cps_boot_vpes)
mfc0 t1, CP0_MVPCONF0
srl t1, t1, MVPCONF0_PVPE_SHIFT
andi t1, t1, MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT
addi t1, t1, 1
addiu t1, t1, 1
/* Calculate a mask for the VPE ID from EBase.CPUNum */
clz t1, t1
......@@ -424,7 +424,7 @@ LEAF(mips_cps_boot_vpes)
/* Next VPE */
2: srl t6, t6, 1
addi t5, t5, 1
addiu t5, t5, 1
bnez t6, 1b
nop
......
......@@ -244,7 +244,7 @@ static inline void check_daddi(void)
panic(bug64hit, !DADDI_WAR ? daddiwar : nowar);
}
int daddiu_bug = -1;
int daddiu_bug = config_enabled(CONFIG_CPU_MIPSR6) ? 0 : -1;
static inline void check_daddiu(void)
{
......@@ -314,11 +314,14 @@ static inline void check_daddiu(void)
void __init check_bugs64_early(void)
{
check_mult_sh();
check_daddiu();
if (!config_enabled(CONFIG_CPU_MIPSR6)) {
check_mult_sh();
check_daddiu();
}
}
void __init check_bugs64(void)
{
check_daddi();
if (!config_enabled(CONFIG_CPU_MIPSR6))
check_daddi();
}
......@@ -237,6 +237,13 @@ static void set_isa(struct cpuinfo_mips *c, unsigned int isa)
c->isa_level |= MIPS_CPU_ISA_II | MIPS_CPU_ISA_III;
break;
/* R6 incompatible with everything else */
case MIPS_CPU_ISA_M64R6:
c->isa_level |= MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6;
case MIPS_CPU_ISA_M32R6:
c->isa_level |= MIPS_CPU_ISA_M32R6;
/* Break here so we don't add incompatible ISAs */
break;
case MIPS_CPU_ISA_M32R2:
c->isa_level |= MIPS_CPU_ISA_M32R2;
case MIPS_CPU_ISA_M32R1:
......@@ -326,6 +333,9 @@ static inline unsigned int decode_config0(struct cpuinfo_mips *c)
case 1:
set_isa(c, MIPS_CPU_ISA_M32R2);
break;
case 2:
set_isa(c, MIPS_CPU_ISA_M32R6);
break;
default:
goto unknown;
}
......@@ -338,6 +348,9 @@ static inline unsigned int decode_config0(struct cpuinfo_mips *c)
case 1:
set_isa(c, MIPS_CPU_ISA_M64R2);
break;
case 2:
set_isa(c, MIPS_CPU_ISA_M64R6);
break;
default:
goto unknown;
}
......@@ -501,6 +514,8 @@ static inline unsigned int decode_config5(struct cpuinfo_mips *c)
c->options |= MIPS_CPU_EVA;
if (config5 & MIPS_CONF5_MRP)
c->options |= MIPS_CPU_MAAR;
if (config5 & MIPS_CONF5_LLB)
c->options |= MIPS_CPU_RW_LLB;
return config5 & MIPS_CONF_M;
}
......@@ -543,7 +558,7 @@ static void decode_configs(struct cpuinfo_mips *c)
}
#ifndef CONFIG_MIPS_CPS
if (cpu_has_mips_r2) {
if (cpu_has_mips_r2_r6) {
c->core = get_ebase_cpunum();
if (cpu_has_mipsmt)
c->core >>= fls(core_nvpes()) - 1;
......@@ -898,6 +913,11 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
{
c->writecombine = _CACHE_UNCACHED_ACCELERATED;
switch (c->processor_id & PRID_IMP_MASK) {
case PRID_IMP_QEMU_GENERIC:
c->writecombine = _CACHE_UNCACHED;
c->cputype = CPU_QEMU_GENERIC;
__cpu_name[cpu] = "MIPS GENERIC QEMU";
break;
case PRID_IMP_4KC:
c->cputype = CPU_4KC;
c->writecombine = _CACHE_UNCACHED;
......@@ -1347,8 +1367,7 @@ void cpu_probe(void)
if (c->options & MIPS_CPU_FPU) {
c->fpu_id = cpu_get_fpu_id();
if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 |
MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)) {
if (c->isa_level & cpu_has_mips_r) {
if (c->fpu_id & MIPS_FPIR_3D)
c->ases |= MIPS_ASE_MIPS3D;
if (c->fpu_id & MIPS_FPIR_FREP)
......@@ -1356,7 +1375,7 @@ void cpu_probe(void)
}
}
if (cpu_has_mips_r2) {
if (cpu_has_mips_r2_r6) {
c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
/* R2 has Performance Counter Interrupt indicator */
c->options |= MIPS_CPU_PCI;
......
......@@ -11,29 +11,112 @@
#include <linux/elf.h>
#include <linux/sched.h>
/* FPU modes */
enum {
FP_ERROR = -1,
FP_DOUBLE_64A = -2,
FP_FRE,
FP_FR0,
FP_FR1,
};
/**
* struct mode_req - ABI FPU mode requirements
* @single: The program being loaded needs an FPU but it will only issue
* single precision instructions meaning that it can execute in
* either FR0 or FR1.
* @soft: The soft(-float) requirement means that the program being
* loaded needs has no FPU dependency at all (i.e. it has no
* FPU instructions).
* @fr1: The program being loaded depends on FPU being in FR=1 mode.
* @frdefault: The program being loaded depends on the default FPU mode.
* That is FR0 for O32 and FR1 for N32/N64.
* @fre: The program being loaded depends on FPU with FRE=1. This mode is
* a bridge which uses FR=1 whilst still being able to maintain
* full compatibility with pre-existing code using the O32 FP32
* ABI.
*
* More information about the FP ABIs can be found here:
*
* https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking#10.4.1._Basic_mode_set-up
*
*/
struct mode_req {
bool single;
bool soft;
bool fr1;
bool frdefault;
bool fre;
};
static const struct mode_req fpu_reqs[] = {
[MIPS_ABI_FP_ANY] = { true, true, true, true, true },
[MIPS_ABI_FP_DOUBLE] = { false, false, false, true, true },
[MIPS_ABI_FP_SINGLE] = { true, false, false, false, false },
[MIPS_ABI_FP_SOFT] = { false, true, false, false, false },
[MIPS_ABI_FP_OLD_64] = { false, false, false, false, false },
[MIPS_ABI_FP_XX] = { false, false, true, true, true },
[MIPS_ABI_FP_64] = { false, false, true, false, false },
[MIPS_ABI_FP_64A] = { false, false, true, false, true }
};
/*
* Mode requirements when .MIPS.abiflags is not present in the ELF.
* Not present means that everything is acceptable except FR1.
*/
static struct mode_req none_req = { true, true, false, true, true };
int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
bool is_interp, struct arch_elf_state *state)
{
struct elfhdr *ehdr = _ehdr;
struct elf_phdr *phdr = _phdr;
struct elf32_hdr *ehdr32 = _ehdr;
struct elf32_phdr *phdr32 = _phdr;
struct elf64_phdr *phdr64 = _phdr;
struct mips_elf_abiflags_v0 abiflags;
int ret;
if (config_enabled(CONFIG_64BIT) &&
(ehdr->e_ident[EI_CLASS] != ELFCLASS32))
return 0;
if (phdr->p_type != PT_MIPS_ABIFLAGS)
return 0;
if (phdr->p_filesz < sizeof(abiflags))
return -EINVAL;
/* Lets see if this is an O32 ELF */
if (ehdr32->e_ident[EI_CLASS] == ELFCLASS32) {
/* FR = 1 for N32 */
if (ehdr32->e_flags & EF_MIPS_ABI2)
state->overall_fp_mode = FP_FR1;
else
/* Set a good default FPU mode for O32 */
state->overall_fp_mode = cpu_has_mips_r6 ?
FP_FRE : FP_FR0;
if (ehdr32->e_flags & EF_MIPS_FP64) {
/*
* Set MIPS_ABI_FP_OLD_64 for EF_MIPS_FP64. We will override it
* later if needed
*/
if (is_interp)
state->interp_fp_abi = MIPS_ABI_FP_OLD_64;
else
state->fp_abi = MIPS_ABI_FP_OLD_64;
}
if (phdr32->p_type != PT_MIPS_ABIFLAGS)
return 0;
if (phdr32->p_filesz < sizeof(abiflags))
return -EINVAL;
ret = kernel_read(elf, phdr32->p_offset,
(char *)&abiflags,
sizeof(abiflags));
} else {
/* FR=1 is really the only option for 64-bit */
state->overall_fp_mode = FP_FR1;
if (phdr64->p_type != PT_MIPS_ABIFLAGS)
return 0;
if (phdr64->p_filesz < sizeof(abiflags))
return -EINVAL;
ret = kernel_read(elf, phdr64->p_offset,
(char *)&abiflags,
sizeof(abiflags));
}
ret = kernel_read(elf, phdr->p_offset, (char *)&abiflags,
sizeof(abiflags));
if (ret < 0)
return ret;
if (ret != sizeof(abiflags))
......@@ -48,35 +131,30 @@ int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
return 0;
}
static inline unsigned get_fp_abi(struct elfhdr *ehdr, int in_abi)
static inline unsigned get_fp_abi(int in_abi)
{
/* If the ABI requirement is provided, simply return that */
if (in_abi != -1)
if (in_abi != MIPS_ABI_FP_UNKNOWN)
return in_abi;
/* If the EF_MIPS_FP64 flag was set, return MIPS_ABI_FP_64 */
if (ehdr->e_flags & EF_MIPS_FP64)
return MIPS_ABI_FP_64;
/* Default to MIPS_ABI_FP_DOUBLE */
return MIPS_ABI_FP_DOUBLE;
/* Unknown ABI */
return MIPS_ABI_FP_UNKNOWN;
}
int arch_check_elf(void *_ehdr, bool has_interpreter,
struct arch_elf_state *state)
{
struct elfhdr *ehdr = _ehdr;
unsigned fp_abi, interp_fp_abi, abi0, abi1;
struct elf32_hdr *ehdr = _ehdr;
struct mode_req prog_req, interp_req;
int fp_abi, interp_fp_abi, abi0, abi1, max_abi;
/* Ignore non-O32 binaries */
if (config_enabled(CONFIG_64BIT) &&
(ehdr->e_ident[EI_CLASS] != ELFCLASS32))
if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
return 0;
fp_abi = get_fp_abi(ehdr, state->fp_abi);
fp_abi = get_fp_abi(state->fp_abi);
if (has_interpreter) {
interp_fp_abi = get_fp_abi(ehdr, state->interp_fp_abi);
interp_fp_abi = get_fp_abi(state->interp_fp_abi);
abi0 = min(fp_abi, interp_fp_abi);
abi1 = max(fp_abi, interp_fp_abi);
......@@ -84,108 +162,103 @@ int arch_check_elf(void *_ehdr, bool has_interpreter,
abi0 = abi1 = fp_abi;
}
state->overall_abi = FP_ERROR;
if (abi0 == abi1) {
state->overall_abi = abi0;
} else if (abi0 == MIPS_ABI_FP_ANY) {
state->overall_abi = abi1;
} else if (abi0 == MIPS_ABI_FP_DOUBLE) {
switch (abi1) {
case MIPS_ABI_FP_XX:
state->overall_abi = MIPS_ABI_FP_DOUBLE;
break;
case MIPS_ABI_FP_64A:
state->overall_abi = FP_DOUBLE_64A;
break;
}
} else if (abi0 == MIPS_ABI_FP_SINGLE ||
abi0 == MIPS_ABI_FP_SOFT) {
/* Cannot link with other ABIs */
} else if (abi0 == MIPS_ABI_FP_OLD_64) {
switch (abi1) {
case MIPS_ABI_FP_XX:
case MIPS_ABI_FP_64:
case MIPS_ABI_FP_64A:
state->overall_abi = MIPS_ABI_FP_64;
break;
}
} else if (abi0 == MIPS_ABI_FP_XX ||
abi0 == MIPS_ABI_FP_64 ||
abi0 == MIPS_ABI_FP_64A) {
state->overall_abi = MIPS_ABI_FP_64;
}
/* ABI limits. O32 = FP_64A, N32/N64 = FP_SOFT */
max_abi = ((ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
(!(ehdr->e_flags & EF_MIPS_ABI2))) ?
MIPS_ABI_FP_64A : MIPS_ABI_FP_SOFT;
switch (state->overall_abi) {
case MIPS_ABI_FP_64:
case MIPS_ABI_FP_64A:
case FP_DOUBLE_64A:
if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
return -ELIBBAD;
break;
if ((abi0 > max_abi && abi0 != MIPS_ABI_FP_UNKNOWN) ||
(abi1 > max_abi && abi1 != MIPS_ABI_FP_UNKNOWN))
return -ELIBBAD;
/* It's time to determine the FPU mode requirements */
prog_req = (abi0 == MIPS_ABI_FP_UNKNOWN) ? none_req : fpu_reqs[abi0];
interp_req = (abi1 == MIPS_ABI_FP_UNKNOWN) ? none_req : fpu_reqs[abi1];
case FP_ERROR:
/*
* Check whether the program's and interp's ABIs have a matching FPU
* mode requirement.
*/
prog_req.single = interp_req.single && prog_req.single;
prog_req.soft = interp_req.soft && prog_req.soft;
prog_req.fr1 = interp_req.fr1 && prog_req.fr1;
prog_req.frdefault = interp_req.frdefault && prog_req.frdefault;
prog_req.fre = interp_req.fre && prog_req.fre;
/*
* Determine the desired FPU mode
*
* Decision making:
*
* - We want FR_FRE if FRE=1 and both FR=1 and FR=0 are false. This
* means that we have a combination of program and interpreter
* that inherently require the hybrid FP mode.
* - If FR1 and FRDEFAULT is true, that means we hit the any-abi or
* fpxx case. This is because, in any-ABI (or no-ABI) we have no FPU
* instructions so we don't care about the mode. We will simply use
* the one preferred by the hardware. In fpxx case, that ABI can
* handle both FR=1 and FR=0, so, again, we simply choose the one
* preferred by the hardware. Next, if we only use single-precision
* FPU instructions, and the default ABI FPU mode is not good
* (ie single + any ABI combination), we set again the FPU mode to the
* one is preferred by the hardware. Next, if we know that the code
* will only use single-precision instructions, shown by single being
* true but frdefault being false, then we again set the FPU mode to
* the one that is preferred by the hardware.
* - We want FP_FR1 if that's the only matching mode and the default one
* is not good.
* - Return with -ELIBADD if we can't find a matching FPU mode.
*/
if (prog_req.fre && !prog_req.frdefault && !prog_req.fr1)
state->overall_fp_mode = FP_FRE;
else if ((prog_req.fr1 && prog_req.frdefault) ||
(prog_req.single && !prog_req.frdefault))
/* Make sure 64-bit MIPS III/IV/64R1 will not pick FR1 */
state->overall_fp_mode = ((current_cpu_data.fpu_id & MIPS_FPIR_F64) &&
cpu_has_mips_r2_r6) ?
FP_FR1 : FP_FR0;
else if (prog_req.fr1)
state->overall_fp_mode = FP_FR1;
else if (!prog_req.fre && !prog_req.frdefault &&
!prog_req.fr1 && !prog_req.single && !prog_req.soft)
return -ELIBBAD;
}
return 0;
}
void mips_set_personality_fp(struct arch_elf_state *state)
static inline void set_thread_fp_mode(int hybrid, int regs32)
{
if (config_enabled(CONFIG_FP32XX_HYBRID_FPRS)) {
/*
* Use hybrid FPRs for all code which can correctly execute
* with that mode.
*/
switch (state->overall_abi) {
case MIPS_ABI_FP_DOUBLE:
case MIPS_ABI_FP_SINGLE:
case MIPS_ABI_FP_SOFT:
case MIPS_ABI_FP_XX:
case MIPS_ABI_FP_ANY:
/* FR=1, FRE=1 */
clear_thread_flag(TIF_32BIT_FPREGS);
set_thread_flag(TIF_HYBRID_FPREGS);
return;
}
}
switch (state->overall_abi) {
case MIPS_ABI_FP_DOUBLE:
case MIPS_ABI_FP_SINGLE:
case MIPS_ABI_FP_SOFT:
/* FR=0 */
set_thread_flag(TIF_32BIT_FPREGS);
if (hybrid)
set_thread_flag(TIF_HYBRID_FPREGS);
else
clear_thread_flag(TIF_HYBRID_FPREGS);
break;
case FP_DOUBLE_64A:
/* FR=1, FRE=1 */
if (regs32)
set_thread_flag(TIF_32BIT_FPREGS);
else
clear_thread_flag(TIF_32BIT_FPREGS);
set_thread_flag(TIF_HYBRID_FPREGS);
break;
}
case MIPS_ABI_FP_64:
case MIPS_ABI_FP_64A:
/* FR=1, FRE=0 */
clear_thread_flag(TIF_32BIT_FPREGS);
clear_thread_flag(TIF_HYBRID_FPREGS);
break;
void mips_set_personality_fp(struct arch_elf_state *state)
{
/*
* This function is only ever called for O32 ELFs so we should
* not be worried about N32/N64 binaries.
*/
case MIPS_ABI_FP_XX:
case MIPS_ABI_FP_ANY:
if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
set_thread_flag(TIF_32BIT_FPREGS);
else
clear_thread_flag(TIF_32BIT_FPREGS);
if (!config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT))
return;
clear_thread_flag(TIF_HYBRID_FPREGS);
switch (state->overall_fp_mode) {
case FP_FRE:
set_thread_fp_mode(1, 0);
break;
case FP_FR0:
set_thread_fp_mode(0, 1);
break;
case FP_FR1:
set_thread_fp_mode(0, 0);
break;
default:
case FP_ERROR:
BUG();
}
}
......@@ -46,6 +46,11 @@ resume_userspace:
local_irq_disable # make sure we dont miss an
# interrupt setting need_resched
# between sampling and return
#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR
lw k0, TI_R2_EMUL_RET($28)
bnez k0, restore_all_from_r2_emul
#endif
LONG_L a2, TI_FLAGS($28) # current->work
andi t0, a2, _TIF_WORK_MASK # (ignoring syscall_trace)
bnez t0, work_pending
......@@ -114,6 +119,19 @@ restore_partial: # restore partial frame
RESTORE_SP_AND_RET
.set at
#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR
restore_all_from_r2_emul: # restore full frame
.set noat
sw zero, TI_R2_EMUL_RET($28) # reset it
RESTORE_TEMP
RESTORE_AT
RESTORE_STATIC
RESTORE_SOME
LONG_L sp, PT_R29(sp)
eretnc
.set at
#endif
work_pending:
andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
beqz t0, work_notifysig
......@@ -158,7 +176,8 @@ syscall_exit_work:
jal syscall_trace_leave
b resume_userspace
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT)
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) || \
defined(CONFIG_MIPS_MT)
/*
* MIPS32R2 Instruction Hazard Barrier - must be called
......@@ -171,4 +190,4 @@ LEAF(mips_ihb)
nop
END(mips_ihb)
#endif /* CONFIG_CPU_MIPSR2 or CONFIG_MIPS_MT */
#endif /* CONFIG_CPU_MIPSR2 or CONFIG_CPU_MIPSR6 or CONFIG_MIPS_MT */
......@@ -125,7 +125,7 @@ LEAF(__r4k_wait)
nop
nop
#endif
.set arch=r4000
.set MIPS_ISA_ARCH_LEVEL_RAW
wait
/* end of rollback region (the region size must be power of two) */
1:
......
......@@ -186,6 +186,7 @@ void __init check_wait(void)
case CPU_PROAPTIV:
case CPU_P5600:
case CPU_M5150:
case CPU_QEMU_GENERIC:
cpu_wait = r4k_wait;
if (read_c0_config7() & MIPS_CONF7_WII)
cpu_wait = r4k_wait_irqoff;
......
此差异已折叠。
......@@ -77,11 +77,13 @@ EXPORT_SYMBOL(__strnlen_kernel_asm);
EXPORT_SYMBOL(__strnlen_user_nocheck_asm);
EXPORT_SYMBOL(__strnlen_user_asm);
#ifndef CONFIG_CPU_MIPSR6
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_nocheck);
EXPORT_SYMBOL(__csum_partial_copy_kernel);
EXPORT_SYMBOL(__csum_partial_copy_to_user);
EXPORT_SYMBOL(__csum_partial_copy_from_user);
#endif
EXPORT_SYMBOL(invalid_pte_table);
#ifdef CONFIG_FUNCTION_TRACER
......
......@@ -82,7 +82,9 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "]\n");
}
seq_printf(m, "isa\t\t\t: mips1");
seq_printf(m, "isa\t\t\t:");
if (cpu_has_mips_r1)
seq_printf(m, " mips1");
if (cpu_has_mips_2)
seq_printf(m, "%s", " mips2");
if (cpu_has_mips_3)
......@@ -95,10 +97,14 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "%s", " mips32r1");
if (cpu_has_mips32r2)
seq_printf(m, "%s", " mips32r2");
if (cpu_has_mips32r6)
seq_printf(m, "%s", " mips32r6");
if (cpu_has_mips64r1)
seq_printf(m, "%s", " mips64r1");
if (cpu_has_mips64r2)
seq_printf(m, "%s", " mips64r2");
if (cpu_has_mips64r6)
seq_printf(m, "%s", " mips64r6");
seq_printf(m, "\n");
seq_printf(m, "ASEs implemented\t:");
......
......@@ -581,6 +581,10 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
if ((value & PR_FP_MODE_FRE) && cpu_has_fpu && !cpu_has_fre)
return -EOPNOTSUPP;
/* FR = 0 not supported in MIPS R6 */
if (!(value & PR_FP_MODE_FR) && cpu_has_fpu && cpu_has_mips_r6)
return -EOPNOTSUPP;
/* Save FP & vector context, then disable FPU & MSA */
if (task->signal == current->signal)
lose_fpu(1);
......
......@@ -34,7 +34,7 @@
.endm
.set noreorder
.set arch=r4000
.set MIPS_ISA_ARCH_LEVEL_RAW
LEAF(_save_fp_context)
.set push
......@@ -42,7 +42,8 @@ LEAF(_save_fp_context)
cfc1 t1, fcr31
.set pop
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \
defined(CONFIG_CPU_MIPS32_R6)
.set push
SET_HARDFLOAT
#ifdef CONFIG_CPU_MIPS32_R2
......@@ -105,10 +106,12 @@ LEAF(_save_fp_context32)
SET_HARDFLOAT
cfc1 t1, fcr31
#ifndef CONFIG_CPU_MIPS64_R6
mfc0 t0, CP0_STATUS
sll t0, t0, 5
bgez t0, 1f # skip storing odd if FR=0
nop
#endif
/* Store the 16 odd double precision registers */
EX sdc1 $f1, SC32_FPREGS+8(a0)
......@@ -163,7 +166,8 @@ LEAF(_save_fp_context32)
LEAF(_restore_fp_context)
EX lw t1, SC_FPC_CSR(a0)
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \
defined(CONFIG_CPU_MIPS32_R6)
.set push
SET_HARDFLOAT
#ifdef CONFIG_CPU_MIPS32_R2
......@@ -223,10 +227,12 @@ LEAF(_restore_fp_context32)
SET_HARDFLOAT
EX lw t1, SC32_FPC_CSR(a0)
#ifndef CONFIG_CPU_MIPS64_R6
mfc0 t0, CP0_STATUS
sll t0, t0, 5
bgez t0, 1f # skip loading odd if FR=0
nop
#endif
EX ldc1 $f1, SC32_FPREGS+8(a0)
EX ldc1 $f3, SC32_FPREGS+24(a0)
......
......@@ -115,7 +115,8 @@
* Save a thread's fp context.
*/
LEAF(_save_fp)
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \
defined(CONFIG_CPU_MIPS32_R6)
mfc0 t0, CP0_STATUS
#endif
fpu_save_double a0 t0 t1 # clobbers t1
......@@ -126,7 +127,8 @@ LEAF(_save_fp)
* Restore a thread's fp context.
*/
LEAF(_restore_fp)
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \
defined(CONFIG_CPU_MIPS32_R6)
mfc0 t0, CP0_STATUS
#endif
fpu_restore_double a0 t0 t1 # clobbers t1
......@@ -240,9 +242,9 @@ LEAF(_init_fpu)
mtc1 t1, $f30
mtc1 t1, $f31
#ifdef CONFIG_CPU_MIPS32_R2
#if defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_CPU_MIPS32_R6)
.set push
.set mips32r2
.set MIPS_ISA_LEVEL_RAW
.set fp=64
sll t0, t0, 5 # is Status.FR set?
bgez t0, 1f # no: skip setting upper 32b
......@@ -280,9 +282,9 @@ LEAF(_init_fpu)
mthc1 t1, $f30
mthc1 t1, $f31
1: .set pop
#endif /* CONFIG_CPU_MIPS32_R2 */
#endif /* CONFIG_CPU_MIPS32_R2 || CONFIG_CPU_MIPS32_R6 */
#else
.set arch=r4000
.set MIPS_ISA_ARCH_LEVEL_RAW
dmtc1 t1, $f0
dmtc1 t1, $f2
dmtc1 t1, $f4
......
......@@ -208,6 +208,7 @@ void spram_config(void)
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
case CPU_P5600:
case CPU_QEMU_GENERIC:
config0 = read_c0_config();
/* FIXME: addresses are Malta specific */
if (config0 & (1<<24)) {
......
......@@ -136,7 +136,7 @@ static inline int mips_atomic_set(unsigned long addr, unsigned long new)
: "memory");
} else if (cpu_has_llsc) {
__asm__ __volatile__ (
" .set arch=r4000 \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
" li %[err], 0 \n"
"1: ll %[old], (%[addr]) \n"
" move %[tmp], %[new] \n"
......
......@@ -46,6 +46,7 @@
#include <asm/fpu.h>
#include <asm/fpu_emulator.h>
#include <asm/idle.h>
#include <asm/mips-r2-to-r6-emul.h>
#include <asm/mipsregs.h>
#include <asm/mipsmtregs.h>
#include <asm/module.h>
......@@ -837,7 +838,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
exception_exit(prev_state);
}
static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
const char *str)
{
siginfo_t info;
......@@ -1027,7 +1028,34 @@ asmlinkage void do_ri(struct pt_regs *regs)
unsigned int opcode = 0;
int status = -1;
/*
* Avoid any kernel code. Just emulate the R2 instruction
* as quickly as possible.
*/
if (mipsr2_emulation && cpu_has_mips_r6 &&
likely(user_mode(regs))) {
if (likely(get_user(opcode, epc) >= 0)) {
status = mipsr2_decoder(regs, opcode);
switch (status) {
case 0:
case SIGEMT:
task_thread_info(current)->r2_emul_return = 1;
return;
case SIGILL:
goto no_r2_instr;
default:
process_fpemu_return(status,
&current->thread.cp0_baduaddr);
task_thread_info(current)->r2_emul_return = 1;
return;
}
}
}
no_r2_instr:
prev_state = exception_enter();
if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs),
SIGILL) == NOTIFY_STOP)
goto out;
......@@ -1559,6 +1587,7 @@ static inline void parity_protection_init(void)
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
case CPU_P5600:
case CPU_QEMU_GENERIC:
{
#define ERRCTL_PE 0x80000000
#define ERRCTL_L2P 0x00800000
......@@ -1648,7 +1677,7 @@ asmlinkage void cache_parity_error(void)
printk("Decoded c0_cacheerr: %s cache fault in %s reference.\n",
reg_val & (1<<30) ? "secondary" : "primary",
reg_val & (1<<31) ? "data" : "insn");
if (cpu_has_mips_r2 &&
if ((cpu_has_mips_r2_r6) &&
((current_cpu_data.processor_id & 0xff0000) == PRID_COMP_MIPS)) {
pr_err("Error bits: %s%s%s%s%s%s%s%s\n",
reg_val & (1<<29) ? "ED " : "",
......@@ -1688,7 +1717,7 @@ asmlinkage void do_ftlb(void)
unsigned int reg_val;
/* For the moment, report the problem and hang. */
if (cpu_has_mips_r2 &&
if ((cpu_has_mips_r2_r6) &&
((current_cpu_data.processor_id & 0xff0000) == PRID_COMP_MIPS)) {
pr_err("FTLB error exception, cp0_ecc=0x%08x:\n",
read_c0_ecc());
......@@ -1977,7 +2006,7 @@ static void configure_hwrena(void)
{
unsigned int hwrena = cpu_hwrena_impl_bits;
if (cpu_has_mips_r2)
if (cpu_has_mips_r2_r6)
hwrena |= 0x0000000f;
if (!noulri && cpu_has_userlocal)
......@@ -2021,7 +2050,7 @@ void per_cpu_trap_init(bool is_boot_cpu)
* o read IntCtl.IPTI to determine the timer interrupt
* o read IntCtl.IPPCI to determine the performance counter interrupt
*/
if (cpu_has_mips_r2) {
if (cpu_has_mips_r2_r6) {
cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP;
cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7;
cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7;
......@@ -2112,7 +2141,7 @@ void __init trap_init(void)
#else
ebase = CKSEG0;
#endif
if (cpu_has_mips_r2)
if (cpu_has_mips_r2_r6)
ebase += (read_c0_ebase() & 0x3ffff000);
}
......
......@@ -129,6 +129,7 @@ extern void show_registers(struct pt_regs *regs);
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#ifndef CONFIG_CPU_MIPSR6
#define LoadW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\t"user_lwl("%0", "(%2)")"\n" \
......@@ -146,6 +147,39 @@ extern void show_registers(struct pt_regs *regs);
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#else
/* MIPSR6 has no lwl instruction */
#define LoadW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tpush\n" \
".set\tnoat\n\t" \
"1:"user_lb("%0", "0(%2)")"\n\t" \
"2:"user_lbu("$1", "1(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"3:"user_lbu("$1", "2(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"4:"user_lbu("$1", "3(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
".set\tpop\n" \
"10:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"11:\tli\t%1, %3\n\t" \
"j\t10b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 11b\n\t" \
STR(PTR)"\t2b, 11b\n\t" \
STR(PTR)"\t3b, 11b\n\t" \
STR(PTR)"\t4b, 11b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#endif /* CONFIG_CPU_MIPSR6 */
#define LoadHWU(addr, value, res) \
__asm__ __volatile__ ( \
......@@ -169,6 +203,7 @@ extern void show_registers(struct pt_regs *regs);
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#ifndef CONFIG_CPU_MIPSR6
#define LoadWU(addr, value, res) \
__asm__ __volatile__ ( \
"1:\t"user_lwl("%0", "(%2)")"\n" \
......@@ -206,6 +241,87 @@ extern void show_registers(struct pt_regs *regs);
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#else
/* MIPSR6 has not lwl and ldl instructions */
#define LoadWU(addr, value, res) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
"1:"user_lbu("%0", "0(%2)")"\n\t" \
"2:"user_lbu("$1", "1(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"3:"user_lbu("$1", "2(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"4:"user_lbu("$1", "3(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
".set\tpop\n" \
"10:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"11:\tli\t%1, %3\n\t" \
"j\t10b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 11b\n\t" \
STR(PTR)"\t2b, 11b\n\t" \
STR(PTR)"\t3b, 11b\n\t" \
STR(PTR)"\t4b, 11b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadDW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
"1:lb\t%0, 0(%2)\n\t" \
"2:lbu\t $1, 1(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"3:lbu\t$1, 2(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"4:lbu\t$1, 3(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"5:lbu\t$1, 4(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"6:lbu\t$1, 5(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"7:lbu\t$1, 6(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"8:lbu\t$1, 7(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
".set\tpop\n\t" \
"10:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"11:\tli\t%1, %3\n\t" \
"j\t10b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 11b\n\t" \
STR(PTR)"\t2b, 11b\n\t" \
STR(PTR)"\t3b, 11b\n\t" \
STR(PTR)"\t4b, 11b\n\t" \
STR(PTR)"\t5b, 11b\n\t" \
STR(PTR)"\t6b, 11b\n\t" \
STR(PTR)"\t7b, 11b\n\t" \
STR(PTR)"\t8b, 11b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#endif /* CONFIG_CPU_MIPSR6 */
#define StoreHW(addr, value, res) \
__asm__ __volatile__ ( \
......@@ -228,6 +344,7 @@ extern void show_registers(struct pt_regs *regs);
: "=r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT));
#ifndef CONFIG_CPU_MIPSR6
#define StoreW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\t"user_swl("%1", "(%2)")"\n" \
......@@ -263,9 +380,82 @@ extern void show_registers(struct pt_regs *regs);
".previous" \
: "=r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT));
#endif
#else
/* MIPSR6 has no swl and sdl instructions */
#define StoreW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
"1:"user_sb("%1", "3(%2)")"\n\t" \
"srl\t$1, %1, 0x8\n\t" \
"2:"user_sb("$1", "2(%2)")"\n\t" \
"srl\t$1, $1, 0x8\n\t" \
"3:"user_sb("$1", "1(%2)")"\n\t" \
"srl\t$1, $1, 0x8\n\t" \
"4:"user_sb("$1", "0(%2)")"\n\t" \
".set\tpop\n\t" \
"li\t%0, 0\n" \
"10:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"11:\tli\t%0, %3\n\t" \
"j\t10b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 11b\n\t" \
STR(PTR)"\t2b, 11b\n\t" \
STR(PTR)"\t3b, 11b\n\t" \
STR(PTR)"\t4b, 11b\n\t" \
".previous" \
: "=&r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT) \
: "memory");
#define StoreDW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
"1:sb\t%1, 7(%2)\n\t" \
"dsrl\t$1, %1, 0x8\n\t" \
"2:sb\t$1, 6(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
"3:sb\t$1, 5(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
"4:sb\t$1, 4(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
"5:sb\t$1, 3(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
"6:sb\t$1, 2(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
"7:sb\t$1, 1(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
"8:sb\t$1, 0(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
".set\tpop\n\t" \
"li\t%0, 0\n" \
"10:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"11:\tli\t%0, %3\n\t" \
"j\t10b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 11b\n\t" \
STR(PTR)"\t2b, 11b\n\t" \
STR(PTR)"\t3b, 11b\n\t" \
STR(PTR)"\t4b, 11b\n\t" \
STR(PTR)"\t5b, 11b\n\t" \
STR(PTR)"\t6b, 11b\n\t" \
STR(PTR)"\t7b, 11b\n\t" \
STR(PTR)"\t8b, 11b\n\t" \
".previous" \
: "=&r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT) \
: "memory");
#endif /* CONFIG_CPU_MIPSR6 */
#else /* __BIG_ENDIAN */
#ifdef __LITTLE_ENDIAN
#define LoadHW(addr, value, res) \
__asm__ __volatile__ (".set\tnoat\n" \
"1:\t"user_lb("%0", "1(%2)")"\n" \
......@@ -286,6 +476,7 @@ extern void show_registers(struct pt_regs *regs);
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#ifndef CONFIG_CPU_MIPSR6
#define LoadW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\t"user_lwl("%0", "3(%2)")"\n" \
......@@ -303,6 +494,40 @@ extern void show_registers(struct pt_regs *regs);
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#else
/* MIPSR6 has no lwl instruction */
#define LoadW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tpush\n" \
".set\tnoat\n\t" \
"1:"user_lb("%0", "3(%2)")"\n\t" \
"2:"user_lbu("$1", "2(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"3:"user_lbu("$1", "1(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"4:"user_lbu("$1", "0(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
".set\tpop\n" \
"10:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"11:\tli\t%1, %3\n\t" \
"j\t10b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 11b\n\t" \
STR(PTR)"\t2b, 11b\n\t" \
STR(PTR)"\t3b, 11b\n\t" \
STR(PTR)"\t4b, 11b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#endif /* CONFIG_CPU_MIPSR6 */
#define LoadHWU(addr, value, res) \
__asm__ __volatile__ ( \
......@@ -326,6 +551,7 @@ extern void show_registers(struct pt_regs *regs);
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#ifndef CONFIG_CPU_MIPSR6
#define LoadWU(addr, value, res) \
__asm__ __volatile__ ( \
"1:\t"user_lwl("%0", "3(%2)")"\n" \
......@@ -363,6 +589,86 @@ extern void show_registers(struct pt_regs *regs);
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#else
/* MIPSR6 has not lwl and ldl instructions */
#define LoadWU(addr, value, res) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
"1:"user_lbu("%0", "3(%2)")"\n\t" \
"2:"user_lbu("$1", "2(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"3:"user_lbu("$1", "1(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"4:"user_lbu("$1", "0(%2)")"\n\t" \
"sll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
".set\tpop\n" \
"10:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"11:\tli\t%1, %3\n\t" \
"j\t10b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 11b\n\t" \
STR(PTR)"\t2b, 11b\n\t" \
STR(PTR)"\t3b, 11b\n\t" \
STR(PTR)"\t4b, 11b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#define LoadDW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
"1:lb\t%0, 7(%2)\n\t" \
"2:lbu\t$1, 6(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"3:lbu\t$1, 5(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"4:lbu\t$1, 4(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"5:lbu\t$1, 3(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"6:lbu\t$1, 2(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"7:lbu\t$1, 1(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"8:lbu\t$1, 0(%2)\n\t" \
"dsll\t%0, 0x8\n\t" \
"or\t%0, $1\n\t" \
"li\t%1, 0\n" \
".set\tpop\n\t" \
"10:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"11:\tli\t%1, %3\n\t" \
"j\t10b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 11b\n\t" \
STR(PTR)"\t2b, 11b\n\t" \
STR(PTR)"\t3b, 11b\n\t" \
STR(PTR)"\t4b, 11b\n\t" \
STR(PTR)"\t5b, 11b\n\t" \
STR(PTR)"\t6b, 11b\n\t" \
STR(PTR)"\t7b, 11b\n\t" \
STR(PTR)"\t8b, 11b\n\t" \
".previous" \
: "=&r" (value), "=r" (res) \
: "r" (addr), "i" (-EFAULT));
#endif /* CONFIG_CPU_MIPSR6 */
#define StoreHW(addr, value, res) \
__asm__ __volatile__ ( \
......@@ -384,7 +690,7 @@ extern void show_registers(struct pt_regs *regs);
".previous" \
: "=r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT));
#ifndef CONFIG_CPU_MIPSR6
#define StoreW(addr, value, res) \
__asm__ __volatile__ ( \
"1:\t"user_swl("%1", "3(%2)")"\n" \
......@@ -420,6 +726,79 @@ extern void show_registers(struct pt_regs *regs);
".previous" \
: "=r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT));
#else
/* MIPSR6 has no swl and sdl instructions */
#define StoreW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
"1:"user_sb("%1", "0(%2)")"\n\t" \
"srl\t$1, %1, 0x8\n\t" \
"2:"user_sb("$1", "1(%2)")"\n\t" \
"srl\t$1, $1, 0x8\n\t" \
"3:"user_sb("$1", "2(%2)")"\n\t" \
"srl\t$1, $1, 0x8\n\t" \
"4:"user_sb("$1", "3(%2)")"\n\t" \
".set\tpop\n\t" \
"li\t%0, 0\n" \
"10:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"11:\tli\t%0, %3\n\t" \
"j\t10b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 11b\n\t" \
STR(PTR)"\t2b, 11b\n\t" \
STR(PTR)"\t3b, 11b\n\t" \
STR(PTR)"\t4b, 11b\n\t" \
".previous" \
: "=&r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT) \
: "memory");
#define StoreDW(addr, value, res) \
__asm__ __volatile__ ( \
".set\tpush\n\t" \
".set\tnoat\n\t" \
"1:sb\t%1, 0(%2)\n\t" \
"dsrl\t$1, %1, 0x8\n\t" \
"2:sb\t$1, 1(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
"3:sb\t$1, 2(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
"4:sb\t$1, 3(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
"5:sb\t$1, 4(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
"6:sb\t$1, 5(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
"7:sb\t$1, 6(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
"8:sb\t$1, 7(%2)\n\t" \
"dsrl\t$1, $1, 0x8\n\t" \
".set\tpop\n\t" \
"li\t%0, 0\n" \
"10:\n\t" \
".insn\n\t" \
".section\t.fixup,\"ax\"\n\t" \
"11:\tli\t%0, %3\n\t" \
"j\t10b\n\t" \
".previous\n\t" \
".section\t__ex_table,\"a\"\n\t" \
STR(PTR)"\t1b, 11b\n\t" \
STR(PTR)"\t2b, 11b\n\t" \
STR(PTR)"\t3b, 11b\n\t" \
STR(PTR)"\t4b, 11b\n\t" \
STR(PTR)"\t5b, 11b\n\t" \
STR(PTR)"\t6b, 11b\n\t" \
STR(PTR)"\t7b, 11b\n\t" \
STR(PTR)"\t8b, 11b\n\t" \
".previous" \
: "=&r" (res) \
: "r" (value), "r" (addr), "i" (-EFAULT) \
: "memory");
#endif /* CONFIG_CPU_MIPSR6 */
#endif
static void emulate_load_store_insn(struct pt_regs *regs,
......@@ -703,10 +1082,13 @@ static void emulate_load_store_insn(struct pt_regs *regs,
break;
return;
#ifndef CONFIG_CPU_MIPSR6
/*
* COP2 is available to implementor for application specific use.
* It's up to applications to register a notifier chain and do
* whatever they have to do, including possible sending of signals.
*
* This instruction has been reallocated in Release 6
*/
case lwc2_op:
cu2_notifier_call_chain(CU2_LWC2_OP, regs);
......@@ -723,7 +1105,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
case sdc2_op:
cu2_notifier_call_chain(CU2_SDC2_OP, regs);
break;
#endif
default:
/*
* Pheeee... We encountered an yet unknown instruction or
......
......@@ -8,6 +8,7 @@ lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \
obj-y += iomap.o
obj-$(CONFIG_PCI) += iomap-pci.o
lib-$(CONFIG_GENERIC_CSUM) := $(filter-out csum_partial.o, $(lib-y))
obj-$(CONFIG_CPU_GENERIC_DUMP_TLB) += dump_tlb.o
obj-$(CONFIG_CPU_R3000) += r3k_dump_tlb.o
......
......@@ -293,9 +293,14 @@
and t0, src, ADDRMASK
PREFS( 0, 2*32(src) )
PREFD( 1, 2*32(dst) )
#ifndef CONFIG_CPU_MIPSR6
bnez t1, .Ldst_unaligned\@
nop
bnez t0, .Lsrc_unaligned_dst_aligned\@
#else
or t0, t0, t1
bnez t0, .Lcopy_unaligned_bytes\@
#endif
/*
* use delay slot for fall-through
* src and dst are aligned; need to compute rem
......@@ -376,6 +381,7 @@
bne rem, len, 1b
.set noreorder
#ifndef CONFIG_CPU_MIPSR6
/*
* src and dst are aligned, need to copy rem bytes (rem < NBYTES)
* A loop would do only a byte at a time with possible branch
......@@ -477,6 +483,7 @@
bne len, rem, 1b
.set noreorder
#endif /* !CONFIG_CPU_MIPSR6 */
.Lcopy_bytes_checklen\@:
beqz len, .Ldone\@
nop
......@@ -504,6 +511,22 @@
.Ldone\@:
jr ra
nop
#ifdef CONFIG_CPU_MIPSR6
.Lcopy_unaligned_bytes\@:
1:
COPY_BYTE(0)
COPY_BYTE(1)
COPY_BYTE(2)
COPY_BYTE(3)
COPY_BYTE(4)
COPY_BYTE(5)
COPY_BYTE(6)
COPY_BYTE(7)
ADD src, src, 8
b 1b
ADD dst, dst, 8
#endif /* CONFIG_CPU_MIPSR6 */
.if __memcpy == 1
END(memcpy)
.set __memcpy, 0
......
......@@ -111,6 +111,7 @@
.set at
#endif
#ifndef CONFIG_CPU_MIPSR6
R10KCBARRIER(0(ra))
#ifdef __MIPSEB__
EX(LONG_S_L, a1, (a0), .Lfirst_fixup\@) /* make word/dword aligned */
......@@ -120,6 +121,30 @@
PTR_SUBU a0, t0 /* long align ptr */
PTR_ADDU a2, t0 /* correct size */
#else /* CONFIG_CPU_MIPSR6 */
#define STORE_BYTE(N) \
EX(sb, a1, N(a0), .Lbyte_fixup\@); \
beqz t0, 0f; \
PTR_ADDU t0, 1;
PTR_ADDU a2, t0 /* correct size */
PTR_ADDU t0, 1
STORE_BYTE(0)
STORE_BYTE(1)
#if LONGSIZE == 4
EX(sb, a1, 2(a0), .Lbyte_fixup\@)
#else
STORE_BYTE(2)
STORE_BYTE(3)
STORE_BYTE(4)
STORE_BYTE(5)
EX(sb, a1, 6(a0), .Lbyte_fixup\@)
#endif
0:
ori a0, STORMASK
xori a0, STORMASK
PTR_ADDIU a0, STORSIZE
#endif /* CONFIG_CPU_MIPSR6 */
1: ori t1, a2, 0x3f /* # of full blocks */
xori t1, 0x3f
beqz t1, .Lmemset_partial\@ /* no block to fill */
......@@ -159,6 +184,7 @@
andi a2, STORMASK /* At most one long to go */
beqz a2, 1f
#ifndef CONFIG_CPU_MIPSR6
PTR_ADDU a0, a2 /* What's left */
R10KCBARRIER(0(ra))
#ifdef __MIPSEB__
......@@ -166,6 +192,22 @@
#else
EX(LONG_S_L, a1, -1(a0), .Llast_fixup\@)
#endif
#else
PTR_SUBU t0, $0, a2
PTR_ADDIU t0, 1
STORE_BYTE(0)
STORE_BYTE(1)
#if LONGSIZE == 4
EX(sb, a1, 2(a0), .Lbyte_fixup\@)
#else
STORE_BYTE(2)
STORE_BYTE(3)
STORE_BYTE(4)
STORE_BYTE(5)
EX(sb, a1, 6(a0), .Lbyte_fixup\@)
#endif
0:
#endif
1: jr ra
move a2, zero
......@@ -186,6 +228,11 @@
.hidden __memset
.endif
.Lbyte_fixup\@:
PTR_SUBU a2, $0, t0
jr ra
PTR_ADDIU a2, 1
.Lfirst_fixup\@:
jr ra
nop
......
......@@ -15,7 +15,7 @@
#include <linux/export.h>
#include <linux/stringify.h>
#ifndef CONFIG_CPU_MIPSR2
#if !defined(CONFIG_CPU_MIPSR2) && !defined(CONFIG_CPU_MIPSR6)
/*
* For cli() we have to insert nops to make sure that the new value
......
......@@ -48,6 +48,7 @@
#include <asm/processor.h>
#include <asm/fpu_emulator.h>
#include <asm/fpu.h>
#include <asm/mips-r2-to-r6-emul.h>
#include "ieee754.h"
......@@ -68,7 +69,7 @@ static int fpux_emu(struct pt_regs *,
#define modeindex(v) ((v) & FPU_CSR_RM)
/* convert condition code register number to csr bit */
static const unsigned int fpucondbit[8] = {
const unsigned int fpucondbit[8] = {
FPU_CSR_COND0,
FPU_CSR_COND1,
FPU_CSR_COND2,
......@@ -448,6 +449,9 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
dec_insn.next_pc_inc;
/* Fall through */
case jr_op:
/* For R6, JR already emulated in jalr_op */
if (NO_R6EMU && insn.r_format.opcode == jr_op)
break;
*contpc = regs->regs[insn.r_format.rs];
return 1;
}
......@@ -456,12 +460,18 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
switch (insn.i_format.rt) {
case bltzal_op:
case bltzall_op:
if (NO_R6EMU && (insn.i_format.rs ||
insn.i_format.rt == bltzall_op))
break;
regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
/* Fall through */
case bltz_op:
case bltzl_op:
if (NO_R6EMU)
break;
case bltz_op:
if ((long)regs->regs[insn.i_format.rs] < 0)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
......@@ -473,12 +483,18 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
return 1;
case bgezal_op:
case bgezall_op:
if (NO_R6EMU && (insn.i_format.rs ||
insn.i_format.rt == bgezall_op))
break;
regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
/* Fall through */
case bgez_op:
case bgezl_op:
if (NO_R6EMU)
break;
case bgez_op:
if ((long)regs->regs[insn.i_format.rs] >= 0)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
......@@ -505,8 +521,10 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
/* Set microMIPS mode bit: XOR for jalx. */
*contpc ^= bit;
return 1;
case beq_op:
case beql_op:
if (NO_R6EMU)
break;
case beq_op:
if (regs->regs[insn.i_format.rs] ==
regs->regs[insn.i_format.rt])
*contpc = regs->cp0_epc +
......@@ -517,8 +535,10 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
case bne_op:
case bnel_op:
if (NO_R6EMU)
break;
case bne_op:
if (regs->regs[insn.i_format.rs] !=
regs->regs[insn.i_format.rt])
*contpc = regs->cp0_epc +
......@@ -529,8 +549,34 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
case blez_op:
case blezl_op:
if (NO_R6EMU)
break;
case blez_op:
/*
* Compact branches for R6 for the
* blez and blezl opcodes.
* BLEZ | rs = 0 | rt != 0 == BLEZALC
* BLEZ | rs = rt != 0 == BGEZALC
* BLEZ | rs != 0 | rt != 0 == BGEUC
* BLEZL | rs = 0 | rt != 0 == BLEZC
* BLEZL | rs = rt != 0 == BGEZC
* BLEZL | rs != 0 | rt != 0 == BGEC
*
* For real BLEZ{,L}, rt is always 0.
*/
if (cpu_has_mips_r6 && insn.i_format.rt) {
if ((insn.i_format.opcode == blez_op) &&
((!insn.i_format.rs && insn.i_format.rt) ||
(insn.i_format.rs == insn.i_format.rt)))
regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc;
*contpc = regs->cp0_epc + dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
}
if ((long)regs->regs[insn.i_format.rs] <= 0)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
......@@ -540,8 +586,35 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
case bgtz_op:
case bgtzl_op:
if (NO_R6EMU)
break;
case bgtz_op:
/*
* Compact branches for R6 for the
* bgtz and bgtzl opcodes.
* BGTZ | rs = 0 | rt != 0 == BGTZALC
* BGTZ | rs = rt != 0 == BLTZALC
* BGTZ | rs != 0 | rt != 0 == BLTUC
* BGTZL | rs = 0 | rt != 0 == BGTZC
* BGTZL | rs = rt != 0 == BLTZC
* BGTZL | rs != 0 | rt != 0 == BLTC
*
* *ZALC varint for BGTZ &&& rt != 0
* For real GTZ{,L}, rt is always 0.
*/
if (cpu_has_mips_r6 && insn.i_format.rt) {
if ((insn.i_format.opcode == blez_op) &&
((!insn.i_format.rs && insn.i_format.rt) ||
(insn.i_format.rs == insn.i_format.rt)))
regs->regs[31] = regs->cp0_epc +
dec_insn.pc_inc;
*contpc = regs->cp0_epc + dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
}
if ((long)regs->regs[insn.i_format.rs] > 0)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
......@@ -551,6 +624,16 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
case cbcond0_op:
case cbcond1_op:
if (!cpu_has_mips_r6)
break;
if (insn.i_format.rt && !insn.i_format.rs)
regs->regs[31] = regs->cp0_epc + 4;
*contpc = regs->cp0_epc + dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
#ifdef CONFIG_CPU_CAVIUM_OCTEON
case lwc2_op: /* This is bbit0 on Octeon */
if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) == 0)
......@@ -576,9 +659,73 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
else
*contpc = regs->cp0_epc + 8;
return 1;
#else
case bc6_op:
/*
* Only valid for MIPS R6 but we can still end up
* here from a broken userland so just tell emulator
* this is not a branch and let it break later on.
*/
if (!cpu_has_mips_r6)
break;
*contpc = regs->cp0_epc + dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
case balc6_op:
if (!cpu_has_mips_r6)
break;
regs->regs[31] = regs->cp0_epc + 4;
*contpc = regs->cp0_epc + dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
case beqzcjic_op:
if (!cpu_has_mips_r6)
break;
*contpc = regs->cp0_epc + dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
case bnezcjialc_op:
if (!cpu_has_mips_r6)
break;
if (!insn.i_format.rs)
regs->regs[31] = regs->cp0_epc + 4;
*contpc = regs->cp0_epc + dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
#endif
case cop0_op:
case cop1_op:
/* Need to check for R6 bc1nez and bc1eqz branches */
if (cpu_has_mips_r6 &&
((insn.i_format.rs == bc1eqz_op) ||
(insn.i_format.rs == bc1nez_op))) {
bit = 0;
switch (insn.i_format.rs) {
case bc1eqz_op:
if (get_fpr32(&current->thread.fpu.fpr[insn.i_format.rt], 0) & 0x1)
bit = 1;
break;
case bc1nez_op:
if (!(get_fpr32(&current->thread.fpu.fpr[insn.i_format.rt], 0) & 0x1))
bit = 1;
break;
}
if (bit)
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
(insn.i_format.simmediate << 2);
else
*contpc = regs->cp0_epc +
dec_insn.pc_inc +
dec_insn.next_pc_inc;
return 1;
}
/* R2/R6 compatible cop1 instruction. Fall through */
case cop2_op:
case cop1x_op:
if (insn.i_format.rs == bc_op) {
......@@ -1414,14 +1561,14 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
* achieve full IEEE-754 accuracy - however this emulator does.
*/
case frsqrt_op:
if (!cpu_has_mips_4_5_r2)
if (!cpu_has_mips_4_5_r2_r6)
return SIGILL;
handler.u = fpemu_sp_rsqrt;
goto scopuop;
case frecip_op:
if (!cpu_has_mips_4_5_r2)
if (!cpu_has_mips_4_5_r2_r6)
return SIGILL;
handler.u = fpemu_sp_recip;
......@@ -1616,13 +1763,13 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
* achieve full IEEE-754 accuracy - however this emulator does.
*/
case frsqrt_op:
if (!cpu_has_mips_4_5_r2)
if (!cpu_has_mips_4_5_r2_r6)
return SIGILL;
handler.u = fpemu_dp_rsqrt;
goto dcopuop;
case frecip_op:
if (!cpu_has_mips_4_5_r2)
if (!cpu_has_mips_4_5_r2_r6)
return SIGILL;
handler.u = fpemu_dp_recip;
......
......@@ -794,7 +794,7 @@ static void local_r4k_flush_cache_sigtramp(void * arg)
__asm__ __volatile__ (
".set push\n\t"
".set noat\n\t"
".set mips3\n\t"
".set "MIPS_ISA_LEVEL"\n\t"
#ifdef CONFIG_32BIT
"la $at,1f\n\t"
#endif
......@@ -1255,6 +1255,7 @@ static void probe_pcache(void)
case CPU_P5600:
case CPU_PROAPTIV:
case CPU_M5150:
case CPU_QEMU_GENERIC:
if (!(read_c0_config7() & MIPS_CONF7_IAR) &&
(c->icache.waysize > PAGE_SIZE))
c->icache.flags |= MIPS_CACHE_ALIASES;
......@@ -1472,7 +1473,8 @@ static void setup_scache(void)
default:
if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 |
MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)) {
MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 |
MIPS_CPU_ISA_M64R2 | MIPS_CPU_ISA_M64R6)) {
#ifdef CONFIG_MIPS_CPU_SCACHE
if (mips_sc_init ()) {
scache_size = c->scache.ways * c->scache.sets * c->scache.linesz;
......
......@@ -72,6 +72,20 @@ static struct uasm_reloc relocs[5];
#define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x00002010)
#define cpu_is_r4600_v2_x() ((read_c0_prid() & 0xfffffff0) == 0x00002020)
/*
* R6 has a limited offset of the pref instruction.
* Skip it if the offset is more than 9 bits.
*/
#define _uasm_i_pref(a, b, c, d) \
do { \
if (cpu_has_mips_r6) { \
if (c <= 0xff && c >= -0x100) \
uasm_i_pref(a, b, c, d);\
} else { \
uasm_i_pref(a, b, c, d); \
} \
} while(0)
static int pref_bias_clear_store;
static int pref_bias_copy_load;
static int pref_bias_copy_store;
......@@ -178,7 +192,15 @@ static void set_prefetch_parameters(void)
pref_bias_copy_load = 256;
pref_bias_copy_store = 128;
pref_src_mode = Pref_LoadStreamed;
pref_dst_mode = Pref_PrepareForStore;
if (cpu_has_mips_r6)
/*
* Bit 30 (Pref_PrepareForStore) has been
* removed from MIPS R6. Use bit 5
* (Pref_StoreStreamed).
*/
pref_dst_mode = Pref_StoreStreamed;
else
pref_dst_mode = Pref_PrepareForStore;
break;
}
} else {
......@@ -214,7 +236,7 @@ static inline void build_clear_pref(u32 **buf, int off)
return;
if (pref_bias_clear_store) {
uasm_i_pref(buf, pref_dst_mode, pref_bias_clear_store + off,
_uasm_i_pref(buf, pref_dst_mode, pref_bias_clear_store + off,
A0);
} else if (cache_line_size == (half_clear_loop_size << 1)) {
if (cpu_has_cache_cdex_s) {
......@@ -357,7 +379,7 @@ static inline void build_copy_load_pref(u32 **buf, int off)
return;
if (pref_bias_copy_load)
uasm_i_pref(buf, pref_src_mode, pref_bias_copy_load + off, A1);
_uasm_i_pref(buf, pref_src_mode, pref_bias_copy_load + off, A1);
}
static inline void build_copy_store_pref(u32 **buf, int off)
......@@ -366,7 +388,7 @@ static inline void build_copy_store_pref(u32 **buf, int off)
return;
if (pref_bias_copy_store) {
uasm_i_pref(buf, pref_dst_mode, pref_bias_copy_store + off,
_uasm_i_pref(buf, pref_dst_mode, pref_bias_copy_store + off,
A0);
} else if (cache_line_size == (half_copy_loop_size << 1)) {
if (cpu_has_cache_cdex_s) {
......
......@@ -81,6 +81,7 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c)
case CPU_PROAPTIV:
case CPU_P5600:
case CPU_BMIPS5000:
case CPU_QEMU_GENERIC:
if (config2 & (1 << 12))
return 0;
}
......@@ -104,7 +105,8 @@ static inline int __init mips_sc_probe(void)
/* Ignore anything but MIPSxx processors */
if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 |
MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)))
MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 |
MIPS_CPU_ISA_M64R2 | MIPS_CPU_ISA_M64R6)))
return 0;
/* Does this MIPS32/MIPS64 CPU have a config2 register? */
......
......@@ -501,7 +501,7 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l,
case tlb_indexed: tlbw = uasm_i_tlbwi; break;
}
if (cpu_has_mips_r2) {
if (cpu_has_mips_r2_exec_hazard) {
/*
* The architecture spec says an ehb is required here,
* but a number of cores do not have the hazard and
......@@ -514,6 +514,7 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l,
case CPU_PROAPTIV:
case CPU_P5600:
case CPU_M5150:
case CPU_QEMU_GENERIC:
break;
default:
......@@ -1952,7 +1953,7 @@ static void build_r4000_tlb_load_handler(void)
switch (current_cpu_type()) {
default:
if (cpu_has_mips_r2) {
if (cpu_has_mips_r2_exec_hazard) {
uasm_i_ehb(&p);
case CPU_CAVIUM_OCTEON:
......@@ -2019,7 +2020,7 @@ static void build_r4000_tlb_load_handler(void)
switch (current_cpu_type()) {
default:
if (cpu_has_mips_r2) {
if (cpu_has_mips_r2_exec_hazard) {
uasm_i_ehb(&p);
case CPU_CAVIUM_OCTEON:
......
......@@ -38,6 +38,14 @@
| (e) << RE_SH \
| (f) << FUNC_SH)
/* This macro sets the non-variable bits of an R6 instruction. */
#define M6(a, b, c, d, e) \
((a) << OP_SH \
| (b) << RS_SH \
| (c) << RT_SH \
| (d) << SIMM9_SH \
| (e) << FUNC_SH)
/* Define these when we are not the ISA the kernel is being compiled with. */
#ifdef CONFIG_CPU_MICROMIPS
#define CL_uasm_i_b(buf, off) ISAOPC(_beq)(buf, 0, 0, off)
......@@ -62,7 +70,11 @@ static struct insn insn_table[] = {
{ insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
{ insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
{ insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
#ifndef CONFIG_CPU_MIPSR6
{ insn_cache, M(cache_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
#else
{ insn_cache, M6(cache_op, 0, 0, 0, cache6_op), RS | RT | SIMM9 },
#endif
{ insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
{ insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE },
......@@ -85,13 +97,22 @@ static struct insn insn_table[] = {
{ insn_jal, M(jal_op, 0, 0, 0, 0, 0), JIMM },
{ insn_jalr, M(spec_op, 0, 0, 0, 0, jalr_op), RS | RD },
{ insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
#ifndef CONFIG_CPU_MIPSR6
{ insn_jr, M(spec_op, 0, 0, 0, 0, jr_op), RS },
#else
{ insn_jr, M(spec_op, 0, 0, 0, 0, jalr_op), RS },
#endif
{ insn_lb, M(lb_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_ld, M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD },
{ insn_lh, M(lh_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
#ifndef CONFIG_CPU_MIPSR6
{ insn_lld, M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
#else
{ insn_lld, M6(spec3_op, 0, 0, 0, lld6_op), RS | RT | SIMM9 },
{ insn_ll, M6(spec3_op, 0, 0, 0, ll6_op), RS | RT | SIMM9 },
#endif
{ insn_lui, M(lui_op, 0, 0, 0, 0, 0), RT | SIMM },
{ insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD },
......@@ -104,11 +125,20 @@ static struct insn insn_table[] = {
{ insn_mul, M(spec2_op, 0, 0, 0, 0, mul_op), RS | RT | RD},
{ insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
{ insn_or, M(spec_op, 0, 0, 0, 0, or_op), RS | RT | RD },
#ifndef CONFIG_CPU_MIPSR6
{ insn_pref, M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
#else
{ insn_pref, M6(spec3_op, 0, 0, 0, pref6_op), RS | RT | SIMM9 },
#endif
{ insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 },
{ insn_rotr, M(spec_op, 1, 0, 0, 0, srl_op), RT | RD | RE },
#ifndef CONFIG_CPU_MIPSR6
{ insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
#else
{ insn_scd, M6(spec3_op, 0, 0, 0, scd6_op), RS | RT | SIMM9 },
{ insn_sc, M6(spec3_op, 0, 0, 0, sc6_op), RS | RT | SIMM9 },
#endif
{ insn_sd, M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
{ insn_sll, M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE },
{ insn_sllv, M(spec_op, 0, 0, 0, 0, sllv_op), RS | RT | RD },
......@@ -198,6 +228,8 @@ static void build_insn(u32 **buf, enum opcode opc, ...)
op |= build_set(va_arg(ap, u32));
if (ip->fields & SCIMM)
op |= build_scimm(va_arg(ap, u32));
if (ip->fields & SIMM9)
op |= build_scimm9(va_arg(ap, u32));
va_end(ap);
**buf = op;
......
......@@ -24,7 +24,8 @@ enum fields {
JIMM = 0x080,
FUNC = 0x100,
SET = 0x200,
SCIMM = 0x400
SCIMM = 0x400,
SIMM9 = 0x800,
};
#define OP_MASK 0x3f
......@@ -41,6 +42,8 @@ enum fields {
#define FUNC_SH 0
#define SET_MASK 0x7
#define SET_SH 0
#define SIMM9_SH 7
#define SIMM9_MASK 0x1ff
enum opcode {
insn_invalid,
......@@ -116,6 +119,14 @@ static inline u32 build_scimm(u32 arg)
return (arg & SCIMM_MASK) << SCIMM_SH;
}
static inline u32 build_scimm9(s32 arg)
{
WARN((arg > 0xff || arg < -0x100),
KERN_WARNING "Micro-assembler field overflow\n");
return (arg & SIMM9_MASK) << SIMM9_SH;
}
static inline u32 build_func(u32 arg)
{
WARN(arg & ~FUNC_MASK, KERN_WARNING "Micro-assembler field overflow\n");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册