diff options
| author | Takashi Iwai <tiwai@suse.de> | 2010-11-03 10:51:26 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2010-11-03 10:51:26 -0400 |
| commit | 69dbdd819599e2f3b77c172e83af512845bca5ad (patch) | |
| tree | 49939d8b80ec2115a801eae2aebc21f23867c876 /kernel/debug/debug_core.c | |
| parent | 87232dd49aeb6b7d1af291edca8bd129a82ef4b5 (diff) | |
| parent | 75e3f3137cb570661c2ad3035a139dda671fbb63 (diff) | |
Merge branch 'fix/asoc' into for-linus
Diffstat (limited to 'kernel/debug/debug_core.c')
| -rw-r--r-- | kernel/debug/debug_core.c | 153 |
1 files changed, 72 insertions, 81 deletions
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index de407c78178d..cefd4a11f6d9 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c | |||
| @@ -47,6 +47,7 @@ | |||
| 47 | #include <linux/pid.h> | 47 | #include <linux/pid.h> |
| 48 | #include <linux/smp.h> | 48 | #include <linux/smp.h> |
| 49 | #include <linux/mm.h> | 49 | #include <linux/mm.h> |
| 50 | #include <linux/rcupdate.h> | ||
| 50 | 51 | ||
| 51 | #include <asm/cacheflush.h> | 52 | #include <asm/cacheflush.h> |
| 52 | #include <asm/byteorder.h> | 53 | #include <asm/byteorder.h> |
| @@ -109,13 +110,15 @@ static struct kgdb_bkpt kgdb_break[KGDB_MAX_BREAKPOINTS] = { | |||
| 109 | */ | 110 | */ |
| 110 | atomic_t kgdb_active = ATOMIC_INIT(-1); | 111 | atomic_t kgdb_active = ATOMIC_INIT(-1); |
| 111 | EXPORT_SYMBOL_GPL(kgdb_active); | 112 | EXPORT_SYMBOL_GPL(kgdb_active); |
| 113 | static DEFINE_RAW_SPINLOCK(dbg_master_lock); | ||
| 114 | static DEFINE_RAW_SPINLOCK(dbg_slave_lock); | ||
| 112 | 115 | ||
| 113 | /* | 116 | /* |
| 114 | * We use NR_CPUs not PERCPU, in case kgdb is used to debug early | 117 | * We use NR_CPUs not PERCPU, in case kgdb is used to debug early |
| 115 | * bootup code (which might not have percpu set up yet): | 118 | * bootup code (which might not have percpu set up yet): |
| 116 | */ | 119 | */ |
| 117 | static atomic_t passive_cpu_wait[NR_CPUS]; | 120 | static atomic_t masters_in_kgdb; |
| 118 | static atomic_t cpu_in_kgdb[NR_CPUS]; | 121 | static atomic_t slaves_in_kgdb; |
| 119 | static atomic_t kgdb_break_tasklet_var; | 122 | static atomic_t kgdb_break_tasklet_var; |
| 120 | atomic_t kgdb_setting_breakpoint; | 123 | atomic_t kgdb_setting_breakpoint; |
| 121 | 124 | ||
| @@ -206,18 +209,6 @@ int __weak kgdb_skipexception(int exception, struct pt_regs *regs) | |||
| 206 | return 0; | 209 | return 0; |
| 207 | } | 210 | } |
| 208 | 211 | ||
| 209 | /** | ||
| 210 | * kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb. | ||
| 211 | * @regs: Current &struct pt_regs. | ||
| 212 | * | ||
| 213 | * This function will be called if the particular architecture must | ||
| 214 | * disable hardware debugging while it is processing gdb packets or | ||
| 215 | * handling exception. | ||
| 216 | */ | ||
| 217 | void __weak kgdb_disable_hw_debug(struct pt_regs *regs) | ||
| 218 | { | ||
| 219 | } | ||
| 220 | |||
| 221 | /* | 212 | /* |
| 222 | * Some architectures need cache flushes when we set/clear a | 213 | * Some architectures need cache flushes when we set/clear a |
| 223 | * breakpoint: | 214 | * breakpoint: |
| @@ -457,26 +448,34 @@ static int kgdb_reenter_check(struct kgdb_state *ks) | |||
| 457 | return 1; | 448 | return 1; |
| 458 | } | 449 | } |
| 459 | 450 | ||
| 460 | static void dbg_cpu_switch(int cpu, int next_cpu) | 451 | static void dbg_touch_watchdogs(void) |
| 461 | { | 452 | { |
| 462 | /* Mark the cpu we are switching away from as a slave when it | 453 | touch_softlockup_watchdog_sync(); |
| 463 | * holds the kgdb_active token. This must be done so that the | 454 | clocksource_touch_watchdog(); |
| 464 | * that all the cpus wait in for the debug core will not enter | 455 | rcu_cpu_stall_reset(); |
| 465 | * again as the master. */ | ||
| 466 | if (cpu == atomic_read(&kgdb_active)) { | ||
| 467 | kgdb_info[cpu].exception_state |= DCPU_IS_SLAVE; | ||
| 468 | kgdb_info[cpu].exception_state &= ~DCPU_WANT_MASTER; | ||
| 469 | } | ||
| 470 | kgdb_info[next_cpu].exception_state |= DCPU_NEXT_MASTER; | ||
| 471 | } | 456 | } |
| 472 | 457 | ||
| 473 | static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs) | 458 | static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs, |
| 459 | int exception_state) | ||
| 474 | { | 460 | { |
| 475 | unsigned long flags; | 461 | unsigned long flags; |
| 476 | int sstep_tries = 100; | 462 | int sstep_tries = 100; |
| 477 | int error; | 463 | int error; |
| 478 | int i, cpu; | 464 | int cpu; |
| 479 | int trace_on = 0; | 465 | int trace_on = 0; |
| 466 | int online_cpus = num_online_cpus(); | ||
| 467 | |||
| 468 | kgdb_info[ks->cpu].enter_kgdb++; | ||
| 469 | kgdb_info[ks->cpu].exception_state |= exception_state; | ||
| 470 | |||
| 471 | if (exception_state == DCPU_WANT_MASTER) | ||
| 472 | atomic_inc(&masters_in_kgdb); | ||
| 473 | else | ||
| 474 | atomic_inc(&slaves_in_kgdb); | ||
| 475 | |||
| 476 | if (arch_kgdb_ops.disable_hw_break) | ||
| 477 | arch_kgdb_ops.disable_hw_break(regs); | ||
| 478 | |||
| 480 | acquirelock: | 479 | acquirelock: |
| 481 | /* | 480 | /* |
| 482 | * Interrupts will be restored by the 'trap return' code, except when | 481 | * Interrupts will be restored by the 'trap return' code, except when |
| @@ -489,14 +488,15 @@ acquirelock: | |||
| 489 | kgdb_info[cpu].task = current; | 488 | kgdb_info[cpu].task = current; |
| 490 | kgdb_info[cpu].ret_state = 0; | 489 | kgdb_info[cpu].ret_state = 0; |
| 491 | kgdb_info[cpu].irq_depth = hardirq_count() >> HARDIRQ_SHIFT; | 490 | kgdb_info[cpu].irq_depth = hardirq_count() >> HARDIRQ_SHIFT; |
| 492 | /* | ||
| 493 | * Make sure the above info reaches the primary CPU before | ||
| 494 | * our cpu_in_kgdb[] flag setting does: | ||
| 495 | */ | ||
| 496 | atomic_inc(&cpu_in_kgdb[cpu]); | ||
| 497 | 491 | ||
| 498 | if (exception_level == 1) | 492 | /* Make sure the above info reaches the primary CPU */ |
| 493 | smp_mb(); | ||
| 494 | |||
| 495 | if (exception_level == 1) { | ||
| 496 | if (raw_spin_trylock(&dbg_master_lock)) | ||
| 497 | atomic_xchg(&kgdb_active, cpu); | ||
| 499 | goto cpu_master_loop; | 498 | goto cpu_master_loop; |
| 499 | } | ||
| 500 | 500 | ||
| 501 | /* | 501 | /* |
| 502 | * CPU will loop if it is a slave or request to become a kgdb | 502 | * CPU will loop if it is a slave or request to become a kgdb |
| @@ -508,10 +508,12 @@ cpu_loop: | |||
| 508 | kgdb_info[cpu].exception_state &= ~DCPU_NEXT_MASTER; | 508 | kgdb_info[cpu].exception_state &= ~DCPU_NEXT_MASTER; |
| 509 | goto cpu_master_loop; | 509 | goto cpu_master_loop; |
| 510 | } else if (kgdb_info[cpu].exception_state & DCPU_WANT_MASTER) { | 510 | } else if (kgdb_info[cpu].exception_state & DCPU_WANT_MASTER) { |
| 511 | if (atomic_cmpxchg(&kgdb_active, -1, cpu) == cpu) | 511 | if (raw_spin_trylock(&dbg_master_lock)) { |
| 512 | atomic_xchg(&kgdb_active, cpu); | ||
| 512 | break; | 513 | break; |
| 514 | } | ||
| 513 | } else if (kgdb_info[cpu].exception_state & DCPU_IS_SLAVE) { | 515 | } else if (kgdb_info[cpu].exception_state & DCPU_IS_SLAVE) { |
| 514 | if (!atomic_read(&passive_cpu_wait[cpu])) | 516 | if (!raw_spin_is_locked(&dbg_slave_lock)) |
| 515 | goto return_normal; | 517 | goto return_normal; |
| 516 | } else { | 518 | } else { |
| 517 | return_normal: | 519 | return_normal: |
| @@ -522,9 +524,12 @@ return_normal: | |||
| 522 | arch_kgdb_ops.correct_hw_break(); | 524 | arch_kgdb_ops.correct_hw_break(); |
| 523 | if (trace_on) | 525 | if (trace_on) |
| 524 | tracing_on(); | 526 | tracing_on(); |
| 525 | atomic_dec(&cpu_in_kgdb[cpu]); | 527 | kgdb_info[cpu].exception_state &= |
| 526 | touch_softlockup_watchdog_sync(); | 528 | ~(DCPU_WANT_MASTER | DCPU_IS_SLAVE); |
| 527 | clocksource_touch_watchdog(); | 529 | kgdb_info[cpu].enter_kgdb--; |
| 530 | smp_mb__before_atomic_dec(); | ||
| 531 | atomic_dec(&slaves_in_kgdb); | ||
| 532 | dbg_touch_watchdogs(); | ||
| 528 | local_irq_restore(flags); | 533 | local_irq_restore(flags); |
| 529 | return 0; | 534 | return 0; |
| 530 | } | 535 | } |
| @@ -541,8 +546,8 @@ return_normal: | |||
| 541 | (kgdb_info[cpu].task && | 546 | (kgdb_info[cpu].task && |
| 542 | kgdb_info[cpu].task->pid != kgdb_sstep_pid) && --sstep_tries) { | 547 | kgdb_info[cpu].task->pid != kgdb_sstep_pid) && --sstep_tries) { |
| 543 | atomic_set(&kgdb_active, -1); | 548 | atomic_set(&kgdb_active, -1); |
| 544 | touch_softlockup_watchdog_sync(); | 549 | raw_spin_unlock(&dbg_master_lock); |
| 545 | clocksource_touch_watchdog(); | 550 | dbg_touch_watchdogs(); |
| 546 | local_irq_restore(flags); | 551 | local_irq_restore(flags); |
| 547 | 552 | ||
| 548 | goto acquirelock; | 553 | goto acquirelock; |
| @@ -563,16 +568,12 @@ return_normal: | |||
| 563 | if (dbg_io_ops->pre_exception) | 568 | if (dbg_io_ops->pre_exception) |
| 564 | dbg_io_ops->pre_exception(); | 569 | dbg_io_ops->pre_exception(); |
| 565 | 570 | ||
| 566 | kgdb_disable_hw_debug(ks->linux_regs); | ||
| 567 | |||
| 568 | /* | 571 | /* |
| 569 | * Get the passive CPU lock which will hold all the non-primary | 572 | * Get the passive CPU lock which will hold all the non-primary |
| 570 | * CPU in a spin state while the debugger is active | 573 | * CPU in a spin state while the debugger is active |
| 571 | */ | 574 | */ |
| 572 | if (!kgdb_single_step) { | 575 | if (!kgdb_single_step) |
| 573 | for (i = 0; i < NR_CPUS; i++) | 576 | raw_spin_lock(&dbg_slave_lock); |
| 574 | atomic_inc(&passive_cpu_wait[i]); | ||
| 575 | } | ||
| 576 | 577 | ||
| 577 | #ifdef CONFIG_SMP | 578 | #ifdef CONFIG_SMP |
| 578 | /* Signal the other CPUs to enter kgdb_wait() */ | 579 | /* Signal the other CPUs to enter kgdb_wait() */ |
| @@ -583,10 +584,9 @@ return_normal: | |||
| 583 | /* | 584 | /* |
| 584 | * Wait for the other CPUs to be notified and be waiting for us: | 585 | * Wait for the other CPUs to be notified and be waiting for us: |
| 585 | */ | 586 | */ |
| 586 | for_each_online_cpu(i) { | 587 | while (kgdb_do_roundup && (atomic_read(&masters_in_kgdb) + |
| 587 | while (kgdb_do_roundup && !atomic_read(&cpu_in_kgdb[i])) | 588 | atomic_read(&slaves_in_kgdb)) != online_cpus) |
| 588 | cpu_relax(); | 589 | cpu_relax(); |
| 589 | } | ||
| 590 | 590 | ||
| 591 | /* | 591 | /* |
| 592 | * At this point the primary processor is completely | 592 | * At this point the primary processor is completely |
| @@ -615,7 +615,8 @@ cpu_master_loop: | |||
| 615 | if (error == DBG_PASS_EVENT) { | 615 | if (error == DBG_PASS_EVENT) { |
| 616 | dbg_kdb_mode = !dbg_kdb_mode; | 616 | dbg_kdb_mode = !dbg_kdb_mode; |
| 617 | } else if (error == DBG_SWITCH_CPU_EVENT) { | 617 | } else if (error == DBG_SWITCH_CPU_EVENT) { |
| 618 | dbg_cpu_switch(cpu, dbg_switch_cpu); | 618 | kgdb_info[dbg_switch_cpu].exception_state |= |
| 619 | DCPU_NEXT_MASTER; | ||
| 619 | goto cpu_loop; | 620 | goto cpu_loop; |
| 620 | } else { | 621 | } else { |
| 621 | kgdb_info[cpu].ret_state = error; | 622 | kgdb_info[cpu].ret_state = error; |
| @@ -627,24 +628,11 @@ cpu_master_loop: | |||
| 627 | if (dbg_io_ops->post_exception) | 628 | if (dbg_io_ops->post_exception) |
| 628 | dbg_io_ops->post_exception(); | 629 | dbg_io_ops->post_exception(); |
| 629 | 630 | ||
| 630 | atomic_dec(&cpu_in_kgdb[ks->cpu]); | ||
| 631 | |||
| 632 | if (!kgdb_single_step) { | 631 | if (!kgdb_single_step) { |
| 633 | for (i = NR_CPUS-1; i >= 0; i--) | 632 | raw_spin_unlock(&dbg_slave_lock); |
| 634 | atomic_dec(&passive_cpu_wait[i]); | 633 | /* Wait till all the CPUs have quit from the debugger. */ |
| 635 | /* | 634 | while (kgdb_do_roundup && atomic_read(&slaves_in_kgdb)) |
| 636 | * Wait till all the CPUs have quit from the debugger, | 635 | cpu_relax(); |
| 637 | * but allow a CPU that hit an exception and is | ||
| 638 | * waiting to become the master to remain in the debug | ||
| 639 | * core. | ||
| 640 | */ | ||
| 641 | for_each_online_cpu(i) { | ||
| 642 | while (kgdb_do_roundup && | ||
| 643 | atomic_read(&cpu_in_kgdb[i]) && | ||
| 644 | !(kgdb_info[i].exception_state & | ||
| 645 | DCPU_WANT_MASTER)) | ||
| 646 | cpu_relax(); | ||
| 647 | } | ||
| 648 | } | 636 | } |
| 649 | 637 | ||
| 650 | kgdb_restore: | 638 | kgdb_restore: |
| @@ -655,12 +643,20 @@ kgdb_restore: | |||
| 655 | else | 643 | else |
| 656 | kgdb_sstep_pid = 0; | 644 | kgdb_sstep_pid = 0; |
| 657 | } | 645 | } |
| 646 | if (arch_kgdb_ops.correct_hw_break) | ||
| 647 | arch_kgdb_ops.correct_hw_break(); | ||
| 658 | if (trace_on) | 648 | if (trace_on) |
| 659 | tracing_on(); | 649 | tracing_on(); |
| 650 | |||
| 651 | kgdb_info[cpu].exception_state &= | ||
| 652 | ~(DCPU_WANT_MASTER | DCPU_IS_SLAVE); | ||
| 653 | kgdb_info[cpu].enter_kgdb--; | ||
| 654 | smp_mb__before_atomic_dec(); | ||
| 655 | atomic_dec(&masters_in_kgdb); | ||
| 660 | /* Free kgdb_active */ | 656 | /* Free kgdb_active */ |
| 661 | atomic_set(&kgdb_active, -1); | 657 | atomic_set(&kgdb_active, -1); |
| 662 | touch_softlockup_watchdog_sync(); | 658 | raw_spin_unlock(&dbg_master_lock); |
| 663 | clocksource_touch_watchdog(); | 659 | dbg_touch_watchdogs(); |
| 664 | local_irq_restore(flags); | 660 | local_irq_restore(flags); |
| 665 | 661 | ||
| 666 | return kgdb_info[cpu].ret_state; | 662 | return kgdb_info[cpu].ret_state; |
| @@ -678,7 +674,6 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | |||
| 678 | { | 674 | { |
| 679 | struct kgdb_state kgdb_var; | 675 | struct kgdb_state kgdb_var; |
| 680 | struct kgdb_state *ks = &kgdb_var; | 676 | struct kgdb_state *ks = &kgdb_var; |
| 681 | int ret; | ||
| 682 | 677 | ||
| 683 | ks->cpu = raw_smp_processor_id(); | 678 | ks->cpu = raw_smp_processor_id(); |
| 684 | ks->ex_vector = evector; | 679 | ks->ex_vector = evector; |
| @@ -689,11 +684,10 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | |||
| 689 | 684 | ||
| 690 | if (kgdb_reenter_check(ks)) | 685 | if (kgdb_reenter_check(ks)) |
| 691 | return 0; /* Ouch, double exception ! */ | 686 | return 0; /* Ouch, double exception ! */ |
| 692 | kgdb_info[ks->cpu].exception_state |= DCPU_WANT_MASTER; | 687 | if (kgdb_info[ks->cpu].enter_kgdb != 0) |
| 693 | ret = kgdb_cpu_enter(ks, regs); | 688 | return 0; |
| 694 | kgdb_info[ks->cpu].exception_state &= ~(DCPU_WANT_MASTER | | 689 | |
| 695 | DCPU_IS_SLAVE); | 690 | return kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER); |
| 696 | return ret; | ||
| 697 | } | 691 | } |
| 698 | 692 | ||
| 699 | int kgdb_nmicallback(int cpu, void *regs) | 693 | int kgdb_nmicallback(int cpu, void *regs) |
| @@ -706,12 +700,9 @@ int kgdb_nmicallback(int cpu, void *regs) | |||
| 706 | ks->cpu = cpu; | 700 | ks->cpu = cpu; |
| 707 | ks->linux_regs = regs; | 701 | ks->linux_regs = regs; |
| 708 | 702 | ||
| 709 | if (!atomic_read(&cpu_in_kgdb[cpu]) && | 703 | if (kgdb_info[ks->cpu].enter_kgdb == 0 && |
| 710 | atomic_read(&kgdb_active) != -1 && | 704 | raw_spin_is_locked(&dbg_master_lock)) { |
| 711 | atomic_read(&kgdb_active) != cpu) { | 705 | kgdb_cpu_enter(ks, regs, DCPU_IS_SLAVE); |
| 712 | kgdb_info[cpu].exception_state |= DCPU_IS_SLAVE; | ||
| 713 | kgdb_cpu_enter(ks, regs); | ||
| 714 | kgdb_info[cpu].exception_state &= ~DCPU_IS_SLAVE; | ||
| 715 | return 0; | 706 | return 0; |
| 716 | } | 707 | } |
| 717 | #endif | 708 | #endif |
