diff options
Diffstat (limited to 'arch/sparc/kernel/process_64.c')
| -rw-r--r-- | arch/sparc/kernel/process_64.c | 120 |
1 files changed, 100 insertions, 20 deletions
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index fcaa59421126..d778248ef3f8 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/tick.h> | 27 | #include <linux/tick.h> |
| 28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
| 29 | #include <linux/cpu.h> | 29 | #include <linux/cpu.h> |
| 30 | #include <linux/perf_event.h> | ||
| 30 | #include <linux/elfcore.h> | 31 | #include <linux/elfcore.h> |
| 31 | #include <linux/sysrq.h> | 32 | #include <linux/sysrq.h> |
| 32 | #include <linux/nmi.h> | 33 | #include <linux/nmi.h> |
| @@ -47,6 +48,7 @@ | |||
| 47 | #include <asm/syscalls.h> | 48 | #include <asm/syscalls.h> |
| 48 | #include <asm/irq_regs.h> | 49 | #include <asm/irq_regs.h> |
| 49 | #include <asm/smp.h> | 50 | #include <asm/smp.h> |
| 51 | #include <asm/pcr.h> | ||
| 50 | 52 | ||
| 51 | #include "kstack.h" | 53 | #include "kstack.h" |
| 52 | 54 | ||
| @@ -204,18 +206,22 @@ void show_regs(struct pt_regs *regs) | |||
| 204 | show_stack(current, (unsigned long *) regs->u_regs[UREG_FP]); | 206 | show_stack(current, (unsigned long *) regs->u_regs[UREG_FP]); |
| 205 | } | 207 | } |
| 206 | 208 | ||
| 207 | struct global_reg_snapshot global_reg_snapshot[NR_CPUS]; | 209 | union global_cpu_snapshot global_cpu_snapshot[NR_CPUS]; |
| 208 | static DEFINE_SPINLOCK(global_reg_snapshot_lock); | 210 | static DEFINE_SPINLOCK(global_cpu_snapshot_lock); |
| 209 | 211 | ||
| 210 | static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs, | 212 | static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs, |
| 211 | int this_cpu) | 213 | int this_cpu) |
| 212 | { | 214 | { |
| 215 | struct global_reg_snapshot *rp; | ||
| 216 | |||
| 213 | flushw_all(); | 217 | flushw_all(); |
| 214 | 218 | ||
| 215 | global_reg_snapshot[this_cpu].tstate = regs->tstate; | 219 | rp = &global_cpu_snapshot[this_cpu].reg; |
| 216 | global_reg_snapshot[this_cpu].tpc = regs->tpc; | 220 | |
| 217 | global_reg_snapshot[this_cpu].tnpc = regs->tnpc; | 221 | rp->tstate = regs->tstate; |
| 218 | global_reg_snapshot[this_cpu].o7 = regs->u_regs[UREG_I7]; | 222 | rp->tpc = regs->tpc; |
| 223 | rp->tnpc = regs->tnpc; | ||
| 224 | rp->o7 = regs->u_regs[UREG_I7]; | ||
| 219 | 225 | ||
| 220 | if (regs->tstate & TSTATE_PRIV) { | 226 | if (regs->tstate & TSTATE_PRIV) { |
| 221 | struct reg_window *rw; | 227 | struct reg_window *rw; |
| @@ -223,17 +229,17 @@ static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs, | |||
| 223 | rw = (struct reg_window *) | 229 | rw = (struct reg_window *) |
| 224 | (regs->u_regs[UREG_FP] + STACK_BIAS); | 230 | (regs->u_regs[UREG_FP] + STACK_BIAS); |
| 225 | if (kstack_valid(tp, (unsigned long) rw)) { | 231 | if (kstack_valid(tp, (unsigned long) rw)) { |
| 226 | global_reg_snapshot[this_cpu].i7 = rw->ins[7]; | 232 | rp->i7 = rw->ins[7]; |
| 227 | rw = (struct reg_window *) | 233 | rw = (struct reg_window *) |
| 228 | (rw->ins[6] + STACK_BIAS); | 234 | (rw->ins[6] + STACK_BIAS); |
| 229 | if (kstack_valid(tp, (unsigned long) rw)) | 235 | if (kstack_valid(tp, (unsigned long) rw)) |
| 230 | global_reg_snapshot[this_cpu].rpc = rw->ins[7]; | 236 | rp->rpc = rw->ins[7]; |
| 231 | } | 237 | } |
| 232 | } else { | 238 | } else { |
| 233 | global_reg_snapshot[this_cpu].i7 = 0; | 239 | rp->i7 = 0; |
| 234 | global_reg_snapshot[this_cpu].rpc = 0; | 240 | rp->rpc = 0; |
| 235 | } | 241 | } |
| 236 | global_reg_snapshot[this_cpu].thread = tp; | 242 | rp->thread = tp; |
| 237 | } | 243 | } |
| 238 | 244 | ||
| 239 | /* In order to avoid hangs we do not try to synchronize with the | 245 | /* In order to avoid hangs we do not try to synchronize with the |
| @@ -261,9 +267,9 @@ void arch_trigger_all_cpu_backtrace(void) | |||
| 261 | if (!regs) | 267 | if (!regs) |
| 262 | regs = tp->kregs; | 268 | regs = tp->kregs; |
| 263 | 269 | ||
| 264 | spin_lock_irqsave(&global_reg_snapshot_lock, flags); | 270 | spin_lock_irqsave(&global_cpu_snapshot_lock, flags); |
| 265 | 271 | ||
| 266 | memset(global_reg_snapshot, 0, sizeof(global_reg_snapshot)); | 272 | memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); |
| 267 | 273 | ||
| 268 | this_cpu = raw_smp_processor_id(); | 274 | this_cpu = raw_smp_processor_id(); |
| 269 | 275 | ||
| @@ -272,7 +278,7 @@ void arch_trigger_all_cpu_backtrace(void) | |||
| 272 | smp_fetch_global_regs(); | 278 | smp_fetch_global_regs(); |
| 273 | 279 | ||
| 274 | for_each_online_cpu(cpu) { | 280 | for_each_online_cpu(cpu) { |
| 275 | struct global_reg_snapshot *gp = &global_reg_snapshot[cpu]; | 281 | struct global_reg_snapshot *gp = &global_cpu_snapshot[cpu].reg; |
| 276 | 282 | ||
| 277 | __global_reg_poll(gp); | 283 | __global_reg_poll(gp); |
| 278 | 284 | ||
| @@ -295,9 +301,9 @@ void arch_trigger_all_cpu_backtrace(void) | |||
| 295 | } | 301 | } |
| 296 | } | 302 | } |
| 297 | 303 | ||
| 298 | memset(global_reg_snapshot, 0, sizeof(global_reg_snapshot)); | 304 | memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); |
| 299 | 305 | ||
| 300 | spin_unlock_irqrestore(&global_reg_snapshot_lock, flags); | 306 | spin_unlock_irqrestore(&global_cpu_snapshot_lock, flags); |
| 301 | } | 307 | } |
| 302 | 308 | ||
| 303 | #ifdef CONFIG_MAGIC_SYSRQ | 309 | #ifdef CONFIG_MAGIC_SYSRQ |
| @@ -309,16 +315,90 @@ static void sysrq_handle_globreg(int key) | |||
| 309 | 315 | ||
| 310 | static struct sysrq_key_op sparc_globalreg_op = { | 316 | static struct sysrq_key_op sparc_globalreg_op = { |
| 311 | .handler = sysrq_handle_globreg, | 317 | .handler = sysrq_handle_globreg, |
| 312 | .help_msg = "Globalregs", | 318 | .help_msg = "global-regs(Y)", |
| 313 | .action_msg = "Show Global CPU Regs", | 319 | .action_msg = "Show Global CPU Regs", |
| 314 | }; | 320 | }; |
| 315 | 321 | ||
| 316 | static int __init sparc_globreg_init(void) | 322 | static void __global_pmu_self(int this_cpu) |
| 323 | { | ||
| 324 | struct global_pmu_snapshot *pp; | ||
| 325 | int i, num; | ||
| 326 | |||
| 327 | pp = &global_cpu_snapshot[this_cpu].pmu; | ||
| 328 | |||
| 329 | num = 1; | ||
| 330 | if (tlb_type == hypervisor && | ||
| 331 | sun4v_chip_type >= SUN4V_CHIP_NIAGARA4) | ||
| 332 | num = 4; | ||
| 333 | |||
| 334 | for (i = 0; i < num; i++) { | ||
| 335 | pp->pcr[i] = pcr_ops->read_pcr(i); | ||
| 336 | pp->pic[i] = pcr_ops->read_pic(i); | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | static void __global_pmu_poll(struct global_pmu_snapshot *pp) | ||
| 341 | { | ||
| 342 | int limit = 0; | ||
| 343 | |||
| 344 | while (!pp->pcr[0] && ++limit < 100) { | ||
| 345 | barrier(); | ||
| 346 | udelay(1); | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | static void pmu_snapshot_all_cpus(void) | ||
| 317 | { | 351 | { |
| 318 | return register_sysrq_key('y', &sparc_globalreg_op); | 352 | unsigned long flags; |
| 353 | int this_cpu, cpu; | ||
| 354 | |||
| 355 | spin_lock_irqsave(&global_cpu_snapshot_lock, flags); | ||
| 356 | |||
| 357 | memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); | ||
| 358 | |||
| 359 | this_cpu = raw_smp_processor_id(); | ||
| 360 | |||
| 361 | __global_pmu_self(this_cpu); | ||
| 362 | |||
| 363 | smp_fetch_global_pmu(); | ||
| 364 | |||
| 365 | for_each_online_cpu(cpu) { | ||
| 366 | struct global_pmu_snapshot *pp = &global_cpu_snapshot[cpu].pmu; | ||
| 367 | |||
| 368 | __global_pmu_poll(pp); | ||
| 369 | |||
| 370 | printk("%c CPU[%3d]: PCR[%08lx:%08lx:%08lx:%08lx] PIC[%08lx:%08lx:%08lx:%08lx]\n", | ||
| 371 | (cpu == this_cpu ? '*' : ' '), cpu, | ||
| 372 | pp->pcr[0], pp->pcr[1], pp->pcr[2], pp->pcr[3], | ||
| 373 | pp->pic[0], pp->pic[1], pp->pic[2], pp->pic[3]); | ||
| 374 | } | ||
| 375 | |||
| 376 | memset(global_cpu_snapshot, 0, sizeof(global_cpu_snapshot)); | ||
| 377 | |||
| 378 | spin_unlock_irqrestore(&global_cpu_snapshot_lock, flags); | ||
| 379 | } | ||
| 380 | |||
| 381 | static void sysrq_handle_globpmu(int key) | ||
| 382 | { | ||
| 383 | pmu_snapshot_all_cpus(); | ||
| 384 | } | ||
| 385 | |||
| 386 | static struct sysrq_key_op sparc_globalpmu_op = { | ||
| 387 | .handler = sysrq_handle_globpmu, | ||
| 388 | .help_msg = "global-pmu(X)", | ||
| 389 | .action_msg = "Show Global PMU Regs", | ||
| 390 | }; | ||
| 391 | |||
| 392 | static int __init sparc_sysrq_init(void) | ||
| 393 | { | ||
| 394 | int ret = register_sysrq_key('y', &sparc_globalreg_op); | ||
| 395 | |||
| 396 | if (!ret) | ||
| 397 | ret = register_sysrq_key('x', &sparc_globalpmu_op); | ||
| 398 | return ret; | ||
| 319 | } | 399 | } |
| 320 | 400 | ||
| 321 | core_initcall(sparc_globreg_init); | 401 | core_initcall(sparc_sysrq_init); |
| 322 | 402 | ||
| 323 | #endif | 403 | #endif |
| 324 | 404 | ||
