summaryrefslogtreecommitdiffstats
path: root/arch/mips/math-emu/cp1emu.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-09-15 20:43:33 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-09-15 20:43:33 -0700
commit7318413077a5141a50a753b1fab687b7907eef16 (patch)
tree21a59cf856f4bb762f6d3d0635c898ca6b24cff6 /arch/mips/math-emu/cp1emu.c
parent8d93c7a4315711ea0f7a95ca353a89c4ed0763fb (diff)
parent35eed7cb2cf1c58a225a0140729ba787fbb06c88 (diff)
downloadblackbird-op-linux-7318413077a5141a50a753b1fab687b7907eef16.tar.gz
blackbird-op-linux-7318413077a5141a50a753b1fab687b7907eef16.zip
Merge branch '4.14-features' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle: "This is the main pull request for 4.14 for MIPS; below a summary of the non-merge commits: CM: - Rename mips_cm_base to mips_gcr_base - Specify register size when generating accessors - Use BIT/GENMASK for register fields, order & drop shifts - Add cluster & block args to mips_cm_lock_other() CPC: - Use common CPS accessor generation macros - Use BIT/GENMASK for register fields, order & drop shifts - Introduce register modify (set/clear/change) accessors - Use change_*, set_* & clear_* where appropriate - Add CM/CPC 3.5 register definitions - Use GlobalNumber macros rather than magic numbers - Have asm/mips-cps.h include CM & CPC headers - Cluster support for topology functions - Detect CPUs in secondary clusters CPS: - Read GIC_VL_IDENT directly, not via irqchip driver DMA: - Consolidate coherent and non-coherent dma_alloc code - Don't use dma_cache_sync to implement fd_cacheflush FPU emulation / FP assist code: - Another series of 14 commits fixing corner cases such as NaN propgagation and other special input values. - Zero bits 32-63 of the result for a CLASS.D instruction. - Enhanced statics via debugfs - Do not use bools for arithmetic. GCC 7.1 moans about this. - Correct user fault_addr type Generic MIPS: - Enhancement of stack backtraces - Cleanup from non-existing options - Handle non word sized instructions when examining frame - Fix detection and decoding of ADDIUSP instruction - Fix decoding of SWSP16 instruction - Refactor handling of stack pointer in get_frame_info - Remove unreachable code from force_fcr31_sig() - Convert to using %pOF instead of full_name - Remove the R6000 support. - Move FP code from *_switch.S to *_fpu.S - Remove unused ST_OFF from r2300_switch.S - Allow platform to specify multiple its.S files - Add #includes to various files to ensure code builds reliable and without warning.. - Remove __invalidate_kernel_vmap_range - Remove plat_timer_setup - Declare various variables & functions static - Abstract CPU core & VP(E) ID access through accessor functions - Store core & VP IDs in GlobalNumber-style variable - Unify checks for sibling CPUs - Add CPU cluster number accessors - Prevent direct use of generic_defconfig - Make CONFIG_MIPS_MT_SMP default y - Add __ioread64_copy - Remove unnecessary inclusions of linux/irqchip/mips-gic.h GIC: - Introduce asm/mips-gic.h with accessor functions - Use new GIC accessor functions in mips-gic-timer - Remove counter access functions from irq-mips-gic.c - Remove gic_read_local_vp_id() from irq-mips-gic.c - Simplify shared interrupt pending/mask reads in irq-mips-gic.c - Simplify gic_local_irq_domain_map() in irq-mips-gic.c - Drop gic_(re)set_mask() functions in irq-mips-gic.c - Remove gic_set_polarity(), gic_set_trigger(), gic_set_dual_edge(), gic_map_to_pin() and gic_map_to_vpe() from irq-mips-gic.c. - Convert remaining shared reg access, local int mask access and remaining local reg access to new accessors - Move GIC_LOCAL_INT_* to asm/mips-gic.h - Remove GIC_CPU_INT* macros from irq-mips-gic.c - Move various definitions to the driver - Remove gic_get_usm_range() - Remove __gic_irq_dispatch() forward declaration - Remove gic_init() - Use mips_gic_present() in place of gic_present and remove gic_present - Move gic_get_c0_*_int() to asm/mips-gic.h - Remove linux/irqchip/mips-gic.h - Inline __gic_init() - Inline gic_basic_init() - Make pcpu_masks a per-cpu variable - Use pcpu_masks to avoid reading GIC_SH_MASK* - Clean up mti, reserved-cpu-vectors handling - Use cpumask_first_and() in gic_set_affinity() - Let the core set struct irq_common_data affinity microMIPS: - Fix microMIPS stack unwinding on big endian systems MIPS-GIC: - SYNC after enabling GIC region NUMA: - Remove the unused parent_node() macro R6: - Constify r2_decoder_tables - Add accessor & bit definitions for GlobalNumber SMP: - Constify smp ops - Allow boot_secondary SMP op to return errors VDSO: - Drop gic_get_usm_range() usage - Avoid use of linux/irqchip/mips-gic.h Platform changes: Alchemy: - Add devboard machine type to cpuinfo - update cpu feature overrides - Threaded carddetect irqs for devboards AR7: - allow NULL clock for clk_get_rate BCM63xx: - Fix ENETDMA_6345_MAXBURST_REG offset - Allow NULL clock for clk_get_rate CI20: - Enable GPIO and RTC drivers in defconfig - Add ethernet and fixed-regulator nodes to DTS Generic platform: - Move Boston and NI 169445 FIT image source to their own files - Include asm/bootinfo.h for plat_fdt_relocated() - Include asm/time.h for get_c0_*_int() - Include asm/bootinfo.h for plat_fdt_relocated() - Include asm/time.h for get_c0_*_int() - Allow filtering enabled boards by requirements - Don't explicitly disable CONFIG_USB_SUPPORT - Bump default NR_CPUS to 16 JZ4700: - Probe the jz4740-rtc driver from devicetree Lantiq: - Drop check of boot select from the spi-falcon driver. - Drop check of boot select from the lantiq-flash MTD driver. - Access boot cause register in the watchdog driver through regmap - Add device tree binding documentation for the watchdog driver - Add docs for the RCU DT bindings. - Convert the fpi bus driver to a platform_driver - Remove ltq_reset_cause() and ltq_boot_select( - Switch to a proper reset driver - Switch to a new drivers/soc GPHY driver - Add an USB PHY driver for the Lantiq SoCs using the RCU module - Use of_platform_default_populate instead of __dt_register_buses - Enable MFD_SYSCON to be able to use it for the RCU MFD - Replace ltq_boot_select() with dummy implementation. Loongson 2F: - Allow NULL clock for clk_get_rate Malta: - Use new GIC accessor functions NI 169445: - Add support for NI 169445 board. - Only include in 32r2el kernels Octeon: - Add support for watchdog of 78XX SOCs. - Add support for watchdog of CN68XX SOCs. - Expose support for mips32r1, mips32r2 and mips64r1 - Enable more drivers in config file - Add support for accessing the boot vector. - Remove old boot vector code from watchdog driver - Define watchdog registers for 70xx, 73xx, 78xx, F75xx. - Make CSR functions node aware. - Allow access to CIU3 IRQ domains. - Misc cleanups in the watchdog driver Omega2+: - New board, add support and defconfig Pistachio: - Enable Root FS on NFS in defconfig Ralink: - Add Mediatek MT7628A SoC - Allow NULL clock for clk_get_rate - Explicitly request exclusive reset control in the pci-mt7620 PCI driver. SEAD3: - Only include in 32 bit kernels by default VoCore: - Add VoCore as a vendor t0 dt-bindings - Add defconfig file" * '4.14-features' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (167 commits) MIPS: Refactor handling of stack pointer in get_frame_info MIPS: Stacktrace: Fix microMIPS stack unwinding on big endian systems MIPS: microMIPS: Fix decoding of swsp16 instruction MIPS: microMIPS: Fix decoding of addiusp instruction MIPS: microMIPS: Fix detection of addiusp instruction MIPS: Handle non word sized instructions when examining frame MIPS: ralink: allow NULL clock for clk_get_rate MIPS: Loongson 2F: allow NULL clock for clk_get_rate MIPS: BCM63XX: allow NULL clock for clk_get_rate MIPS: AR7: allow NULL clock for clk_get_rate MIPS: BCM63XX: fix ENETDMA_6345_MAXBURST_REG offset mips: Save all registers when saving the frame MIPS: Add DWARF unwinding to assembly MIPS: Make SAVE_SOME more standard MIPS: Fix issues in backtraces MIPS: jz4780: DTS: Probe the jz4740-rtc driver from devicetree MIPS: Ci20: Enable RTC driver watchdog: octeon-wdt: Add support for 78XX SOCs. watchdog: octeon-wdt: Add support for cn68XX SOCs. watchdog: octeon-wdt: File cleaning. ...
Diffstat (limited to 'arch/mips/math-emu/cp1emu.c')
-rw-r--r--arch/mips/math-emu/cp1emu.c284
1 files changed, 272 insertions, 12 deletions
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index f08a7b4facb9..192542dbd972 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -58,7 +58,7 @@ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *,
mips_instruction);
static int fpux_emu(struct pt_regs *,
- struct mips_fpu_struct *, mips_instruction, void *__user *);
+ struct mips_fpu_struct *, mips_instruction, void __user **);
/* Control registers */
@@ -830,12 +830,12 @@ do { \
} while (0)
#define DIFROMREG(di, x) \
- ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0))
+ ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) ^ 1)], 0))
#define DITOREG(di, x) \
do { \
unsigned fpr, i; \
- fpr = (x) & ~(cop1_64bit(xcp) == 0); \
+ fpr = (x) & ~(cop1_64bit(xcp) ^ 1); \
set_fpr64(&ctx->fpr[fpr], 0, di); \
for (i = 1; i < ARRAY_SIZE(ctx->fpr[x].val64); i++) \
set_fpr64(&ctx->fpr[fpr], i, 0); \
@@ -973,7 +973,7 @@ static inline void cop1_ctc(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
*/
static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- struct mm_decoded_insn dec_insn, void *__user *fault_addr)
+ struct mm_decoded_insn dec_insn, void __user **fault_addr)
{
unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc;
unsigned int cond, cbit, bit0;
@@ -1195,9 +1195,11 @@ emul:
bit0 = get_fpr32(fpr, 0) & 0x1;
switch (MIPSInst_RS(ir)) {
case bc1eqz_op:
+ MIPS_FPU_EMU_INC_STATS(bc1eqz);
cond = bit0 == 0;
break;
case bc1nez_op:
+ MIPS_FPU_EMU_INC_STATS(bc1nez);
cond = bit0 != 0;
break;
}
@@ -1230,6 +1232,7 @@ emul:
break;
}
branch_common:
+ MIPS_FPU_EMU_INC_STATS(branches);
set_delay_slot(xcp);
if (cond) {
/*
@@ -1460,7 +1463,7 @@ DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg);
DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- mips_instruction ir, void *__user *fault_addr)
+ mips_instruction ir, void __user **fault_addr)
{
unsigned rcsr = 0; /* resulting csr */
@@ -1682,15 +1685,19 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
switch (MIPSInst_FUNC(ir)) {
/* binary ops */
case fadd_op:
+ MIPS_FPU_EMU_INC_STATS(add_s);
handler.b = ieee754sp_add;
goto scopbop;
case fsub_op:
+ MIPS_FPU_EMU_INC_STATS(sub_s);
handler.b = ieee754sp_sub;
goto scopbop;
case fmul_op:
+ MIPS_FPU_EMU_INC_STATS(mul_s);
handler.b = ieee754sp_mul;
goto scopbop;
case fdiv_op:
+ MIPS_FPU_EMU_INC_STATS(div_s);
handler.b = ieee754sp_div;
goto scopbop;
@@ -1699,6 +1706,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (!cpu_has_mips_2_3_4_5_r)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(sqrt_s);
handler.u = ieee754sp_sqrt;
goto scopuop;
@@ -1711,6 +1719,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (!cpu_has_mips_4_5_64_r2_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(rsqrt_s);
handler.u = fpemu_sp_rsqrt;
goto scopuop;
@@ -1718,6 +1727,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (!cpu_has_mips_4_5_64_r2_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(recip_s);
handler.u = fpemu_sp_recip;
goto scopuop;
@@ -1754,6 +1764,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(seleqz_s);
SPFROMREG(rv.s, MIPSInst_FT(ir));
if (rv.w & 0x1)
rv.w = 0;
@@ -1765,6 +1776,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(selnez_s);
SPFROMREG(rv.s, MIPSInst_FT(ir));
if (rv.w & 0x1)
SPFROMREG(rv.s, MIPSInst_FS(ir));
@@ -1778,6 +1790,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(maddf_s);
SPFROMREG(ft, MIPSInst_FT(ir));
SPFROMREG(fs, MIPSInst_FS(ir));
SPFROMREG(fd, MIPSInst_FD(ir));
@@ -1791,6 +1804,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(msubf_s);
SPFROMREG(ft, MIPSInst_FT(ir));
SPFROMREG(fs, MIPSInst_FS(ir));
SPFROMREG(fd, MIPSInst_FD(ir));
@@ -1804,9 +1818,9 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(rint_s);
SPFROMREG(fs, MIPSInst_FS(ir));
- rv.l = ieee754sp_tlong(fs);
- rv.s = ieee754sp_flong(rv.l);
+ rv.s = ieee754sp_rint(fs);
goto copcsr;
}
@@ -1816,6 +1830,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(class_s);
SPFROMREG(fs, MIPSInst_FS(ir));
rv.w = ieee754sp_2008class(fs);
rfmt = w_fmt;
@@ -1828,6 +1843,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(min_s);
SPFROMREG(ft, MIPSInst_FT(ir));
SPFROMREG(fs, MIPSInst_FS(ir));
rv.s = ieee754sp_fmin(fs, ft);
@@ -1840,6 +1856,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(mina_s);
SPFROMREG(ft, MIPSInst_FT(ir));
SPFROMREG(fs, MIPSInst_FS(ir));
rv.s = ieee754sp_fmina(fs, ft);
@@ -1852,6 +1869,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(max_s);
SPFROMREG(ft, MIPSInst_FT(ir));
SPFROMREG(fs, MIPSInst_FS(ir));
rv.s = ieee754sp_fmax(fs, ft);
@@ -1864,6 +1882,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(maxa_s);
SPFROMREG(ft, MIPSInst_FT(ir));
SPFROMREG(fs, MIPSInst_FS(ir));
rv.s = ieee754sp_fmaxa(fs, ft);
@@ -1871,15 +1890,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
}
case fabs_op:
+ MIPS_FPU_EMU_INC_STATS(abs_s);
handler.u = ieee754sp_abs;
goto scopuop;
case fneg_op:
+ MIPS_FPU_EMU_INC_STATS(neg_s);
handler.u = ieee754sp_neg;
goto scopuop;
case fmov_op:
/* an easy one */
+ MIPS_FPU_EMU_INC_STATS(mov_s);
SPFROMREG(rv.s, MIPSInst_FS(ir));
goto copcsr;
@@ -1922,12 +1944,14 @@ copcsr:
return SIGILL; /* not defined */
case fcvtd_op:
+ MIPS_FPU_EMU_INC_STATS(cvt_d_s);
SPFROMREG(fs, MIPSInst_FS(ir));
rv.d = ieee754dp_fsp(fs);
rfmt = d_fmt;
goto copcsr;
case fcvtw_op:
+ MIPS_FPU_EMU_INC_STATS(cvt_w_s);
SPFROMREG(fs, MIPSInst_FS(ir));
rv.w = ieee754sp_tint(fs);
rfmt = w_fmt;
@@ -1940,6 +1964,15 @@ copcsr:
if (!cpu_has_mips_2_3_4_5_r)
return SIGILL;
+ if (MIPSInst_FUNC(ir) == fceil_op)
+ MIPS_FPU_EMU_INC_STATS(ceil_w_s);
+ if (MIPSInst_FUNC(ir) == ffloor_op)
+ MIPS_FPU_EMU_INC_STATS(floor_w_s);
+ if (MIPSInst_FUNC(ir) == fround_op)
+ MIPS_FPU_EMU_INC_STATS(round_w_s);
+ if (MIPSInst_FUNC(ir) == ftrunc_op)
+ MIPS_FPU_EMU_INC_STATS(trunc_w_s);
+
oldrm = ieee754_csr.rm;
SPFROMREG(fs, MIPSInst_FS(ir));
ieee754_csr.rm = MIPSInst_FUNC(ir);
@@ -1952,6 +1985,7 @@ copcsr:
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(sel_s);
SPFROMREG(fd, MIPSInst_FD(ir));
if (fd.bits & 0x1)
SPFROMREG(rv.s, MIPSInst_FT(ir));
@@ -1963,6 +1997,7 @@ copcsr:
if (!cpu_has_mips_3_4_5_64_r2_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(cvt_l_s);
SPFROMREG(fs, MIPSInst_FS(ir));
rv.l = ieee754sp_tlong(fs);
rfmt = l_fmt;
@@ -1975,6 +2010,15 @@ copcsr:
if (!cpu_has_mips_3_4_5_64_r2_r6)
return SIGILL;
+ if (MIPSInst_FUNC(ir) == fceill_op)
+ MIPS_FPU_EMU_INC_STATS(ceil_l_s);
+ if (MIPSInst_FUNC(ir) == ffloorl_op)
+ MIPS_FPU_EMU_INC_STATS(floor_l_s);
+ if (MIPSInst_FUNC(ir) == froundl_op)
+ MIPS_FPU_EMU_INC_STATS(round_l_s);
+ if (MIPSInst_FUNC(ir) == ftruncl_op)
+ MIPS_FPU_EMU_INC_STATS(trunc_l_s);
+
oldrm = ieee754_csr.rm;
SPFROMREG(fs, MIPSInst_FS(ir));
ieee754_csr.rm = MIPSInst_FUNC(ir);
@@ -2016,15 +2060,19 @@ copcsr:
switch (MIPSInst_FUNC(ir)) {
/* binary ops */
case fadd_op:
+ MIPS_FPU_EMU_INC_STATS(add_d);
handler.b = ieee754dp_add;
goto dcopbop;
case fsub_op:
+ MIPS_FPU_EMU_INC_STATS(sub_d);
handler.b = ieee754dp_sub;
goto dcopbop;
case fmul_op:
+ MIPS_FPU_EMU_INC_STATS(mul_d);
handler.b = ieee754dp_mul;
goto dcopbop;
case fdiv_op:
+ MIPS_FPU_EMU_INC_STATS(div_d);
handler.b = ieee754dp_div;
goto dcopbop;
@@ -2033,6 +2081,7 @@ copcsr:
if (!cpu_has_mips_2_3_4_5_r)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(sqrt_d);
handler.u = ieee754dp_sqrt;
goto dcopuop;
/*
@@ -2044,12 +2093,14 @@ copcsr:
if (!cpu_has_mips_4_5_64_r2_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(rsqrt_d);
handler.u = fpemu_dp_rsqrt;
goto dcopuop;
case frecip_op:
if (!cpu_has_mips_4_5_64_r2_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(recip_d);
handler.u = fpemu_dp_recip;
goto dcopuop;
case fmovc_op:
@@ -2083,6 +2134,7 @@ copcsr:
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(seleqz_d);
DPFROMREG(rv.d, MIPSInst_FT(ir));
if (rv.l & 0x1)
rv.l = 0;
@@ -2094,6 +2146,7 @@ copcsr:
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(selnez_d);
DPFROMREG(rv.d, MIPSInst_FT(ir));
if (rv.l & 0x1)
DPFROMREG(rv.d, MIPSInst_FS(ir));
@@ -2107,6 +2160,7 @@ copcsr:
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(maddf_d);
DPFROMREG(ft, MIPSInst_FT(ir));
DPFROMREG(fs, MIPSInst_FS(ir));
DPFROMREG(fd, MIPSInst_FD(ir));
@@ -2120,6 +2174,7 @@ copcsr:
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(msubf_d);
DPFROMREG(ft, MIPSInst_FT(ir));
DPFROMREG(fs, MIPSInst_FS(ir));
DPFROMREG(fd, MIPSInst_FD(ir));
@@ -2133,9 +2188,9 @@ copcsr:
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(rint_d);
DPFROMREG(fs, MIPSInst_FS(ir));
- rv.l = ieee754dp_tlong(fs);
- rv.d = ieee754dp_flong(rv.l);
+ rv.d = ieee754dp_rint(fs);
goto copcsr;
}
@@ -2145,9 +2200,10 @@ copcsr:
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(class_d);
DPFROMREG(fs, MIPSInst_FS(ir));
- rv.w = ieee754dp_2008class(fs);
- rfmt = w_fmt;
+ rv.l = ieee754dp_2008class(fs);
+ rfmt = l_fmt;
break;
}
@@ -2157,6 +2213,7 @@ copcsr:
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(min_d);
DPFROMREG(ft, MIPSInst_FT(ir));
DPFROMREG(fs, MIPSInst_FS(ir));
rv.d = ieee754dp_fmin(fs, ft);
@@ -2169,6 +2226,7 @@ copcsr:
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(mina_d);
DPFROMREG(ft, MIPSInst_FT(ir));
DPFROMREG(fs, MIPSInst_FS(ir));
rv.d = ieee754dp_fmina(fs, ft);
@@ -2181,6 +2239,7 @@ copcsr:
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(max_d);
DPFROMREG(ft, MIPSInst_FT(ir));
DPFROMREG(fs, MIPSInst_FS(ir));
rv.d = ieee754dp_fmax(fs, ft);
@@ -2193,6 +2252,7 @@ copcsr:
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(maxa_d);
DPFROMREG(ft, MIPSInst_FT(ir));
DPFROMREG(fs, MIPSInst_FS(ir));
rv.d = ieee754dp_fmaxa(fs, ft);
@@ -2200,15 +2260,18 @@ copcsr:
}
case fabs_op:
+ MIPS_FPU_EMU_INC_STATS(abs_d);
handler.u = ieee754dp_abs;
goto dcopuop;
case fneg_op:
+ MIPS_FPU_EMU_INC_STATS(neg_d);
handler.u = ieee754dp_neg;
goto dcopuop;
case fmov_op:
/* an easy one */
+ MIPS_FPU_EMU_INC_STATS(mov_d);
DPFROMREG(rv.d, MIPSInst_FS(ir));
goto copcsr;
@@ -2228,6 +2291,7 @@ dcopuop:
* unary conv ops
*/
case fcvts_op:
+ MIPS_FPU_EMU_INC_STATS(cvt_s_d);
DPFROMREG(fs, MIPSInst_FS(ir));
rv.s = ieee754sp_fdp(fs);
rfmt = s_fmt;
@@ -2237,6 +2301,7 @@ dcopuop:
return SIGILL; /* not defined */
case fcvtw_op:
+ MIPS_FPU_EMU_INC_STATS(cvt_w_d);
DPFROMREG(fs, MIPSInst_FS(ir));
rv.w = ieee754dp_tint(fs); /* wrong */
rfmt = w_fmt;
@@ -2249,6 +2314,15 @@ dcopuop:
if (!cpu_has_mips_2_3_4_5_r)
return SIGILL;
+ if (MIPSInst_FUNC(ir) == fceil_op)
+ MIPS_FPU_EMU_INC_STATS(ceil_w_d);
+ if (MIPSInst_FUNC(ir) == ffloor_op)
+ MIPS_FPU_EMU_INC_STATS(floor_w_d);
+ if (MIPSInst_FUNC(ir) == fround_op)
+ MIPS_FPU_EMU_INC_STATS(round_w_d);
+ if (MIPSInst_FUNC(ir) == ftrunc_op)
+ MIPS_FPU_EMU_INC_STATS(trunc_w_d);
+
oldrm = ieee754_csr.rm;
DPFROMREG(fs, MIPSInst_FS(ir));
ieee754_csr.rm = MIPSInst_FUNC(ir);
@@ -2261,6 +2335,7 @@ dcopuop:
if (!cpu_has_mips_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(sel_d);
DPFROMREG(fd, MIPSInst_FD(ir));
if (fd.bits & 0x1)
DPFROMREG(rv.d, MIPSInst_FT(ir));
@@ -2272,6 +2347,7 @@ dcopuop:
if (!cpu_has_mips_3_4_5_64_r2_r6)
return SIGILL;
+ MIPS_FPU_EMU_INC_STATS(cvt_l_d);
DPFROMREG(fs, MIPSInst_FS(ir));
rv.l = ieee754dp_tlong(fs);
rfmt = l_fmt;
@@ -2284,6 +2360,15 @@ dcopuop:
if (!cpu_has_mips_3_4_5_64_r2_r6)
return SIGILL;
+ if (MIPSInst_FUNC(ir) == fceill_op)
+ MIPS_FPU_EMU_INC_STATS(ceil_l_d);
+ if (MIPSInst_FUNC(ir) == ffloorl_op)
+ MIPS_FPU_EMU_INC_STATS(floor_l_d);
+ if (MIPSInst_FUNC(ir) == froundl_op)
+ MIPS_FPU_EMU_INC_STATS(round_l_d);
+ if (MIPSInst_FUNC(ir) == ftruncl_op)
+ MIPS_FPU_EMU_INC_STATS(trunc_l_d);
+
oldrm = ieee754_csr.rm;
DPFROMREG(fs, MIPSInst_FS(ir));
ieee754_csr.rm = MIPSInst_FUNC(ir);
@@ -2325,12 +2410,14 @@ dcopuop:
switch (MIPSInst_FUNC(ir)) {
case fcvts_op:
/* convert word to single precision real */
+ MIPS_FPU_EMU_INC_STATS(cvt_s_w);
SPFROMREG(fs, MIPSInst_FS(ir));
rv.s = ieee754sp_fint(fs.bits);
rfmt = s_fmt;
goto copcsr;
case fcvtd_op:
/* convert word to double precision real */
+ MIPS_FPU_EMU_INC_STATS(cvt_d_w);
SPFROMREG(fs, MIPSInst_FS(ir));
rv.d = ieee754dp_fint(fs.bits);
rfmt = d_fmt;
@@ -2350,6 +2437,90 @@ dcopuop:
(MIPSInst_FUNC(ir) & 0x20))
return SIGILL;
+ if (!sig) {
+ if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
+ switch (cmpop) {
+ case 0:
+ MIPS_FPU_EMU_INC_STATS(cmp_af_s);
+ break;
+ case 1:
+ MIPS_FPU_EMU_INC_STATS(cmp_un_s);
+ break;
+ case 2:
+ MIPS_FPU_EMU_INC_STATS(cmp_eq_s);
+ break;
+ case 3:
+ MIPS_FPU_EMU_INC_STATS(cmp_ueq_s);
+ break;
+ case 4:
+ MIPS_FPU_EMU_INC_STATS(cmp_lt_s);
+ break;
+ case 5:
+ MIPS_FPU_EMU_INC_STATS(cmp_ult_s);
+ break;
+ case 6:
+ MIPS_FPU_EMU_INC_STATS(cmp_le_s);
+ break;
+ case 7:
+ MIPS_FPU_EMU_INC_STATS(cmp_ule_s);
+ break;
+ }
+ } else {
+ switch (cmpop) {
+ case 1:
+ MIPS_FPU_EMU_INC_STATS(cmp_or_s);
+ break;
+ case 2:
+ MIPS_FPU_EMU_INC_STATS(cmp_une_s);
+ break;
+ case 3:
+ MIPS_FPU_EMU_INC_STATS(cmp_ne_s);
+ break;
+ }
+ }
+ } else {
+ if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
+ switch (cmpop) {
+ case 0:
+ MIPS_FPU_EMU_INC_STATS(cmp_saf_s);
+ break;
+ case 1:
+ MIPS_FPU_EMU_INC_STATS(cmp_sun_s);
+ break;
+ case 2:
+ MIPS_FPU_EMU_INC_STATS(cmp_seq_s);
+ break;
+ case 3:
+ MIPS_FPU_EMU_INC_STATS(cmp_sueq_s);
+ break;
+ case 4:
+ MIPS_FPU_EMU_INC_STATS(cmp_slt_s);
+ break;
+ case 5:
+ MIPS_FPU_EMU_INC_STATS(cmp_sult_s);
+ break;
+ case 6:
+ MIPS_FPU_EMU_INC_STATS(cmp_sle_s);
+ break;
+ case 7:
+ MIPS_FPU_EMU_INC_STATS(cmp_sule_s);
+ break;
+ }
+ } else {
+ switch (cmpop) {
+ case 1:
+ MIPS_FPU_EMU_INC_STATS(cmp_sor_s);
+ break;
+ case 2:
+ MIPS_FPU_EMU_INC_STATS(cmp_sune_s);
+ break;
+ case 3:
+ MIPS_FPU_EMU_INC_STATS(cmp_sne_s);
+ break;
+ }
+ }
+ }
+
/* fmt is w_fmt for single precision so fix it */
rfmt = s_fmt;
/* default to false */
@@ -2394,6 +2565,7 @@ dcopuop:
break;
}
}
+ break;
}
case l_fmt:
@@ -2406,11 +2578,13 @@ dcopuop:
switch (MIPSInst_FUNC(ir)) {
case fcvts_op:
/* convert long to single precision real */
+ MIPS_FPU_EMU_INC_STATS(cvt_s_l);
rv.s = ieee754sp_flong(bits);
rfmt = s_fmt;
goto copcsr;
case fcvtd_op:
/* convert long to double precision real */
+ MIPS_FPU_EMU_INC_STATS(cvt_d_l);
rv.d = ieee754dp_flong(bits);
rfmt = d_fmt;
goto copcsr;
@@ -2424,6 +2598,90 @@ dcopuop:
(MIPSInst_FUNC(ir) & 0x20))
return SIGILL;
+ if (!sig) {
+ if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
+ switch (cmpop) {
+ case 0:
+ MIPS_FPU_EMU_INC_STATS(cmp_af_d);
+ break;
+ case 1:
+ MIPS_FPU_EMU_INC_STATS(cmp_un_d);
+ break;
+ case 2:
+ MIPS_FPU_EMU_INC_STATS(cmp_eq_d);
+ break;
+ case 3:
+ MIPS_FPU_EMU_INC_STATS(cmp_ueq_d);
+ break;
+ case 4:
+ MIPS_FPU_EMU_INC_STATS(cmp_lt_d);
+ break;
+ case 5:
+ MIPS_FPU_EMU_INC_STATS(cmp_ult_d);
+ break;
+ case 6:
+ MIPS_FPU_EMU_INC_STATS(cmp_le_d);
+ break;
+ case 7:
+ MIPS_FPU_EMU_INC_STATS(cmp_ule_d);
+ break;
+ }
+ } else {
+ switch (cmpop) {
+ case 1:
+ MIPS_FPU_EMU_INC_STATS(cmp_or_d);
+ break;
+ case 2:
+ MIPS_FPU_EMU_INC_STATS(cmp_une_d);
+ break;
+ case 3:
+ MIPS_FPU_EMU_INC_STATS(cmp_ne_d);
+ break;
+ }
+ }
+ } else {
+ if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
+ switch (cmpop) {
+ case 0:
+ MIPS_FPU_EMU_INC_STATS(cmp_saf_d);
+ break;
+ case 1:
+ MIPS_FPU_EMU_INC_STATS(cmp_sun_d);
+ break;
+ case 2:
+ MIPS_FPU_EMU_INC_STATS(cmp_seq_d);
+ break;
+ case 3:
+ MIPS_FPU_EMU_INC_STATS(cmp_sueq_d);
+ break;
+ case 4:
+ MIPS_FPU_EMU_INC_STATS(cmp_slt_d);
+ break;
+ case 5:
+ MIPS_FPU_EMU_INC_STATS(cmp_sult_d);
+ break;
+ case 6:
+ MIPS_FPU_EMU_INC_STATS(cmp_sle_d);
+ break;
+ case 7:
+ MIPS_FPU_EMU_INC_STATS(cmp_sule_d);
+ break;
+ }
+ } else {
+ switch (cmpop) {
+ case 1:
+ MIPS_FPU_EMU_INC_STATS(cmp_sor_d);
+ break;
+ case 2:
+ MIPS_FPU_EMU_INC_STATS(cmp_sune_d);
+ break;
+ case 3:
+ MIPS_FPU_EMU_INC_STATS(cmp_sne_d);
+ break;
+ }
+ }
+ }
+
/* fmt is l_fmt for double precision so fix it */
rfmt = d_fmt;
/* default to false */
@@ -2468,6 +2726,8 @@ dcopuop:
break;
}
}
+ break;
+
default:
return SIGILL;
}
@@ -2553,7 +2813,7 @@ dcopuop:
* For simplicity we always terminate upon an ISA mode switch.
*/
int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
- int has_fpu, void *__user *fault_addr)
+ int has_fpu, void __user **fault_addr)
{
unsigned long oldepc, prevepc;
struct mm_decoded_insn dec_insn;
OpenPOWER on IntegriCloud