[PATCH] [POWERPC] Emulate isel (Integer Select) instruction
Geert Uytterhoeven
Geert.Uytterhoeven at sonycom.com
Wed Nov 28 01:56:53 EST 2007
On Wed, 21 Nov 2007, Geert Uytterhoeven wrote:
> On Tue, 20 Nov 2007, Kumar Gala wrote:
> > On Nov 20, 2007, at 11:54 AM, Scott Wood wrote:
> > > On Mon, Nov 19, 2007 at 09:36:57PM -0600, Kumar Gala wrote:
> > >> isel (Integer Select) is a new user space instruction in the
> > >> PowerISA 2.04 spec. Not all processors implement it so lets emulate
> > >> to ensure code built with isel will run everywhere.
> > >
> > > Given that the instruction is meant to be a performance enhancement,
> > > we should probably warn the first few times it's emulated, so the user
> > > knows they should change their toolchain setup if possible.
> >
> > The same is true of mcrxr, popcntb, and possibly string ld/st.
> >
> > Feel free to submit a patch that warns about their usage.
>
> Something like this?
New version below.
Do we want it in sysfs? Or should we use debugfs instead?
Subject: powerpc: Keep track of emulated instructions
From: Geert Uytterhoeven <Geert.Uytterhoeven at sonycom.com>
powerpc: Keep track of emulated instructions
Counters for the various classes of emulated instructions are available under
/sys/devices/system/cpu/cpu*/emulated/.
Optionally, rate-limited warnings can be printed to the console when
instructions are emulated.
Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven at sonycom.com>
---
arch/powerpc/Kconfig.debug | 10 ++++++
arch/powerpc/kernel/align.c | 17 ++++++++--
arch/powerpc/kernel/sysfs.c | 64 ++++++++++++++++++++++++++++++++++++++++-
arch/powerpc/kernel/traps.c | 17 +++++++++-
include/asm-powerpc/emulator.h | 60 ++++++++++++++++++++++++++++++++++++++
5 files changed, 161 insertions(+), 7 deletions(-)
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -284,4 +284,14 @@ config PPC_EARLY_DEBUG_CPM_ADDR
platform probing is done, all platforms selected must
share the same address.
+config DEBUG_WARN_EMULATED
+ bool "Warn if emulated instructions are used"
+ depends on DEBUG_KERNEL && SYSFS
+ help
+ This option will cause messages to be printed if an instruction is
+ emulated.
+ Counters for emulated instruction usages are always available under
+ /sys/devices/system/cpu/cpu*/emulated/, irrespective of the state
+ of this option.
+
endmenu
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -24,6 +24,7 @@
#include <asm/system.h>
#include <asm/cache.h>
#include <asm/cputable.h>
+#include <asm/emulator.h>
struct aligninfo {
unsigned char len;
@@ -696,8 +697,10 @@ int fix_alignment(struct pt_regs *regs)
areg = dsisr & 0x1f; /* register to update */
#ifdef CONFIG_SPE
- if ((instr >> 26) == 0x4)
+ if ((instr >> 26) == 0x4) {
+ WARN_EMULATE(spe);
return emulate_spe(regs, reg, instr);
+ }
#endif
instr = (dsisr >> 10) & 0x7f;
@@ -731,17 +734,21 @@ int fix_alignment(struct pt_regs *regs)
/* A size of 0 indicates an instruction we don't support, with
* the exception of DCBZ which is handled as a special case here
*/
- if (instr == DCBZ)
+ if (instr == DCBZ) {
+ WARN_EMULATE(dcbz);
return emulate_dcbz(regs, addr);
+ }
if (unlikely(nb == 0))
return 0;
/* Load/Store Multiple instructions are handled in their own
* function
*/
- if (flags & M)
+ if (flags & M) {
+ WARN_EMULATE(multiple);
return emulate_multiple(regs, addr, reg, nb,
flags, instr, swiz);
+ }
/* Verify the address of the operand */
if (unlikely(user_mode(regs) &&
@@ -758,8 +765,10 @@ int fix_alignment(struct pt_regs *regs)
}
/* Special case for 16-byte FP loads and stores */
- if (nb == 16)
+ if (nb == 16) {
+ WARN_EMULATE(fp_pair);
return emulate_fp_pair(regs, addr, reg, flags);
+ }
/* If we are loading, get the data from user space, else
* get it from register values
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -19,6 +19,7 @@
#include <asm/lppaca.h>
#include <asm/machdep.h>
#include <asm/smp.h>
+#include <asm/emulator.h>
static DEFINE_PER_CPU(struct cpu, cpu_devices);
@@ -291,12 +292,68 @@ static struct sysdev_attribute pa6t_attr
};
+#define SYSFS_EMULATED_SETUP(type) \
+DEFINE_PER_CPU(atomic_long_t, emulated_ ## type); \
+static ssize_t show_emulated_ ## type (struct sys_device *dev, \
+ char *buf) \
+{ \
+ struct cpu *cpu = container_of(dev, struct cpu, sysdev); \
+ \
+ return sprintf(buf, "%lu\n", \
+ atomic_long_read(&per_cpu(emulated_ ## type, \
+ cpu->sysdev.id))); \
+} \
+ \
+static struct sysdev_attribute emulated_ ## type ## _attr = { \
+ .attr = { .name = #type, .mode = 0400 }, \
+ .show = show_emulated_ ## type, \
+};
+
+SYSFS_EMULATED_SETUP(dcba);
+SYSFS_EMULATED_SETUP(dcbz);
+SYSFS_EMULATED_SETUP(fp_pair);
+SYSFS_EMULATED_SETUP(mcrxr);
+SYSFS_EMULATED_SETUP(mfpvr);
+SYSFS_EMULATED_SETUP(multiple);
+SYSFS_EMULATED_SETUP(popcntb);
+SYSFS_EMULATED_SETUP(spe);
+SYSFS_EMULATED_SETUP(string);
+#ifdef CONFIG_MATH_EMULATION
+SYSFS_EMULATED_SETUP(math);
+#elif defined(CONFIG_8XX_MINIMAL_FPEMU)
+SYSFS_EMULATED_SETUP(8xx);
+#endif
+
+static struct attribute *emulated_attrs[] = {
+ &emulated_dcba_attr.attr,
+ &emulated_dcbz_attr.attr,
+ &emulated_fp_pair_attr.attr,
+ &emulated_mcrxr_attr.attr,
+ &emulated_mfpvr_attr.attr,
+ &emulated_multiple_attr.attr,
+ &emulated_popcntb_attr.attr,
+ &emulated_spe_attr.attr,
+ &emulated_string_attr.attr,
+#ifdef CONFIG_MATH_EMULATION
+ &emulated_math_attr.attr,
+#elif defined(CONFIG_8XX_MINIMAL_FPEMU)
+ &emulated_8xx_attr.attr,
+#endif
+ NULL
+};
+
+static struct attribute_group emulated_attr_group = {
+ .attrs = emulated_attrs,
+ .name = "emulated"
+};
+
+
static void register_cpu_online(unsigned int cpu)
{
struct cpu *c = &per_cpu(cpu_devices, cpu);
struct sys_device *s = &c->sysdev;
struct sysdev_attribute *attrs, *pmc_attrs;
- int i, nattrs;
+ int i, nattrs, res;
if (!firmware_has_feature(FW_FEATURE_ISERIES) &&
cpu_has_feature(CPU_FTR_SMT))
@@ -339,6 +396,11 @@ static void register_cpu_online(unsigned
if (cpu_has_feature(CPU_FTR_DSCR))
sysdev_create_file(s, &attr_dscr);
+
+ res = sysfs_create_group(&s->kobj, &emulated_attr_group);
+ if (res)
+ pr_warning("Cannot create emulated sysfs group for cpu %u\n",
+ cpu);
}
#ifdef CONFIG_HOTPLUG_CPU
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -53,6 +53,7 @@
#include <asm/processor.h>
#endif
#include <asm/kexec.h>
+#include <asm/emulator.h>
#ifdef CONFIG_DEBUGGER
int (*__debugger)(struct pt_regs *regs);
@@ -721,31 +722,38 @@ static int emulate_instruction(struct pt
/* Emulate the mfspr rD, PVR. */
if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) {
+ WARN_EMULATE(mfpvr);
rd = (instword >> 21) & 0x1f;
regs->gpr[rd] = mfspr(SPRN_PVR);
return 0;
}
/* Emulating the dcba insn is just a no-op. */
- if ((instword & INST_DCBA_MASK) == INST_DCBA)
+ if ((instword & INST_DCBA_MASK) == INST_DCBA) {
+ WARN_EMULATE(dcba);
return 0;
+ }
/* Emulate the mcrxr insn. */
if ((instword & INST_MCRXR_MASK) == INST_MCRXR) {
int shift = (instword >> 21) & 0x1c;
unsigned long msk = 0xf0000000UL >> shift;
+ WARN_EMULATE(mcrxr);
regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk);
regs->xer &= ~0xf0000000UL;
return 0;
}
/* Emulate load/store string insn. */
- if ((instword & INST_STRING_GEN_MASK) == INST_STRING)
+ if ((instword & INST_STRING_GEN_MASK) == INST_STRING) {
+ WARN_EMULATE(string);
return emulate_string_inst(regs, instword);
+ }
/* Emulate the popcntb (Population Count Bytes) instruction. */
if ((instword & INST_POPCNTB_MASK) == INST_POPCNTB) {
+ WARN_EMULATE(popcntb);
return emulate_popcntb_inst(regs, instword);
}
@@ -929,6 +937,8 @@ void SoftwareEmulation(struct pt_regs *r
#ifdef CONFIG_MATH_EMULATION
errcode = do_mathemu(regs);
+ if (errcode >= 0)
+ WARN_EMULATE(math);
switch (errcode) {
case 0:
@@ -950,6 +960,9 @@ void SoftwareEmulation(struct pt_regs *r
#elif defined(CONFIG_8XX_MINIMAL_FPEMU)
errcode = Soft_emulate_8xx(regs);
+ if (errcode >= 0)
+ WARN_EMULATE(8xx);
+
switch (errcode) {
case 0:
emulate_single_step(regs);
--- /dev/null
+++ b/include/asm-powerpc/emulator.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2007 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ASM_POWERPC_EMULATOR_H
+#define _ASM_POWERPC_EMULATOR_H
+
+#include <linux/kernel.h>
+#include <linux/percpu.h>
+
+#include <asm/atomic.h>
+
+DECLARE_PER_CPU(atomic_long_t, emulated_dcba);
+DECLARE_PER_CPU(atomic_long_t, emulated_dcbz);
+DECLARE_PER_CPU(atomic_long_t, emulated_fp_pair);
+DECLARE_PER_CPU(atomic_long_t, emulated_mcrxr);
+DECLARE_PER_CPU(atomic_long_t, emulated_mfpvr);
+DECLARE_PER_CPU(atomic_long_t, emulated_multiple);
+DECLARE_PER_CPU(atomic_long_t, emulated_popcntb);
+DECLARE_PER_CPU(atomic_long_t, emulated_spe);
+DECLARE_PER_CPU(atomic_long_t, emulated_string);
+#ifdef CONFIG_MATH_EMULATION
+DECLARE_PER_CPU(atomic_long_t, emulated_math);
+#elif defined(CONFIG_8XX_MINIMAL_FPEMU)
+DECLARE_PER_CPU(atomic_long_t, emulated_8xx);
+#endif
+
+#ifdef CONFIG_DEBUG_WARN_EMULATED
+static inline void do_warn_emulate(const char *type)
+{
+ if (printk_ratelimit())
+ pr_warning("%s used emulated %s instruction\n", current->comm,
+ type);
+}
+#else
+static inline void do_warn_emulate(const char *type) {}
+#endif
+
+#define WARN_EMULATE(type) \
+ do { \
+ atomic_long_inc(&per_cpu(emulated_ ## type, \
+ raw_smp_processor_id())); \
+ do_warn_emulate(#type); \
+ } while (0)
+
+
+#endif /* _ASM_POWERPC_EMULATOR_H */
With kind regards,
Geert Uytterhoeven
Software Architect
Sony Network and Software Technology Center Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium
Phone: +32 (0)2 700 8453
Fax: +32 (0)2 700 8622
E-mail: Geert.Uytterhoeven at sonycom.com
Internet: http://www.sony-europe.com/
Sony Network and Software Technology Center Europe
A division of Sony Service Centre (Europe) N.V.
Registered office: Technologielaan 7 · B-1840 Londerzeel · Belgium
VAT BE 0413.825.160 · RPR Brussels
Fortis Bank Zaventem · Swift GEBABEBB08A · IBAN BE39001382358619
More information about the Linuxppc-dev
mailing list