185c51c51SRalf Baechle #include <linux/cpumask.h> 285c51c51SRalf Baechle #include <linux/debugfs.h> 385c51c51SRalf Baechle #include <linux/fs.h> 485c51c51SRalf Baechle #include <linux/init.h> 585c51c51SRalf Baechle #include <linux/percpu.h> 685c51c51SRalf Baechle #include <linux/types.h> 775dcfc1dSPaul Burton #include <asm/debug.h> 885c51c51SRalf Baechle #include <asm/fpu_emulator.h> 985c51c51SRalf Baechle #include <asm/local.h> 1085c51c51SRalf Baechle 1185c51c51SRalf Baechle DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); 1285c51c51SRalf Baechle 1385c51c51SRalf Baechle static int fpuemu_stat_get(void *data, u64 *val) 1485c51c51SRalf Baechle { 1585c51c51SRalf Baechle int cpu; 1685c51c51SRalf Baechle unsigned long sum = 0; 1785c51c51SRalf Baechle 1885c51c51SRalf Baechle for_each_online_cpu(cpu) { 1985c51c51SRalf Baechle struct mips_fpu_emulator_stats *ps; 2085c51c51SRalf Baechle local_t *pv; 2185c51c51SRalf Baechle 2285c51c51SRalf Baechle ps = &per_cpu(fpuemustats, cpu); 2385c51c51SRalf Baechle pv = (void *)ps + (unsigned long)data; 2485c51c51SRalf Baechle sum += local_read(pv); 2585c51c51SRalf Baechle } 2685c51c51SRalf Baechle *val = sum; 2785c51c51SRalf Baechle return 0; 2885c51c51SRalf Baechle } 2985c51c51SRalf Baechle DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n"); 3085c51c51SRalf Baechle 31*25ad8db6SAleksandar Markovic static int fpuemustats_clear_show(struct seq_file *s, void *unused) 32*25ad8db6SAleksandar Markovic { 33*25ad8db6SAleksandar Markovic __this_cpu_write((fpuemustats).emulated, 0); 34*25ad8db6SAleksandar Markovic __this_cpu_write((fpuemustats).loads, 0); 35*25ad8db6SAleksandar Markovic __this_cpu_write((fpuemustats).stores, 0); 36*25ad8db6SAleksandar Markovic __this_cpu_write((fpuemustats).branches, 0); 37*25ad8db6SAleksandar Markovic __this_cpu_write((fpuemustats).cp1ops, 0); 38*25ad8db6SAleksandar Markovic __this_cpu_write((fpuemustats).cp1xops, 0); 39*25ad8db6SAleksandar Markovic __this_cpu_write((fpuemustats).errors, 0); 40*25ad8db6SAleksandar Markovic __this_cpu_write((fpuemustats).ieee754_inexact, 0); 41*25ad8db6SAleksandar Markovic __this_cpu_write((fpuemustats).ieee754_underflow, 0); 42*25ad8db6SAleksandar Markovic __this_cpu_write((fpuemustats).ieee754_overflow, 0); 43*25ad8db6SAleksandar Markovic __this_cpu_write((fpuemustats).ieee754_zerodiv, 0); 44*25ad8db6SAleksandar Markovic __this_cpu_write((fpuemustats).ieee754_invalidop, 0); 45*25ad8db6SAleksandar Markovic __this_cpu_write((fpuemustats).ds_emul, 0); 46*25ad8db6SAleksandar Markovic 47*25ad8db6SAleksandar Markovic return 0; 48*25ad8db6SAleksandar Markovic } 49*25ad8db6SAleksandar Markovic 50*25ad8db6SAleksandar Markovic static int fpuemustats_clear_open(struct inode *inode, struct file *file) 51*25ad8db6SAleksandar Markovic { 52*25ad8db6SAleksandar Markovic return single_open(file, fpuemustats_clear_show, inode->i_private); 53*25ad8db6SAleksandar Markovic } 54*25ad8db6SAleksandar Markovic 55*25ad8db6SAleksandar Markovic static const struct file_operations fpuemustats_clear_fops = { 56*25ad8db6SAleksandar Markovic .open = fpuemustats_clear_open, 57*25ad8db6SAleksandar Markovic .read = seq_read, 58*25ad8db6SAleksandar Markovic .llseek = seq_lseek, 59*25ad8db6SAleksandar Markovic .release = single_release, 60*25ad8db6SAleksandar Markovic }; 61*25ad8db6SAleksandar Markovic 6285c51c51SRalf Baechle static int __init debugfs_fpuemu(void) 6385c51c51SRalf Baechle { 64*25ad8db6SAleksandar Markovic struct dentry *d, *dir, *reset_file; 6585c51c51SRalf Baechle 6685c51c51SRalf Baechle if (!mips_debugfs_dir) 6785c51c51SRalf Baechle return -ENODEV; 6885c51c51SRalf Baechle dir = debugfs_create_dir("fpuemustats", mips_debugfs_dir); 6985c51c51SRalf Baechle if (!dir) 7085c51c51SRalf Baechle return -ENOMEM; 71*25ad8db6SAleksandar Markovic reset_file = debugfs_create_file("fpuemustats_clear", 0444, 72*25ad8db6SAleksandar Markovic mips_debugfs_dir, NULL, 73*25ad8db6SAleksandar Markovic &fpuemustats_clear_fops); 74*25ad8db6SAleksandar Markovic if (!reset_file) 75*25ad8db6SAleksandar Markovic return -ENOMEM; 7685c51c51SRalf Baechle 7747fa0c02SRalf Baechle #define FPU_EMU_STAT_OFFSET(m) \ 7847fa0c02SRalf Baechle offsetof(struct mips_fpu_emulator_stats, m) 7947fa0c02SRalf Baechle 8047fa0c02SRalf Baechle #define FPU_STAT_CREATE(m) \ 8185c51c51SRalf Baechle do { \ 8247fa0c02SRalf Baechle d = debugfs_create_file(#m , S_IRUGO, dir, \ 8347fa0c02SRalf Baechle (void *)FPU_EMU_STAT_OFFSET(m), \ 8485c51c51SRalf Baechle &fops_fpuemu_stat); \ 8585c51c51SRalf Baechle if (!d) \ 8685c51c51SRalf Baechle return -ENOMEM; \ 8785c51c51SRalf Baechle } while (0) 8885c51c51SRalf Baechle 8985c51c51SRalf Baechle FPU_STAT_CREATE(emulated); 9085c51c51SRalf Baechle FPU_STAT_CREATE(loads); 9185c51c51SRalf Baechle FPU_STAT_CREATE(stores); 92ae5f3f5bSAleksandar Markovic FPU_STAT_CREATE(branches); 9385c51c51SRalf Baechle FPU_STAT_CREATE(cp1ops); 9485c51c51SRalf Baechle FPU_STAT_CREATE(cp1xops); 9585c51c51SRalf Baechle FPU_STAT_CREATE(errors); 96c4103526SDeng-Cheng Zhu FPU_STAT_CREATE(ieee754_inexact); 97c4103526SDeng-Cheng Zhu FPU_STAT_CREATE(ieee754_underflow); 98c4103526SDeng-Cheng Zhu FPU_STAT_CREATE(ieee754_overflow); 99c4103526SDeng-Cheng Zhu FPU_STAT_CREATE(ieee754_zerodiv); 100c4103526SDeng-Cheng Zhu FPU_STAT_CREATE(ieee754_invalidop); 1012707cd29SDavid Daney FPU_STAT_CREATE(ds_emul); 10285c51c51SRalf Baechle 10385c51c51SRalf Baechle return 0; 10485c51c51SRalf Baechle } 1051249ed35SRalf Baechle arch_initcall(debugfs_fpuemu); 106