diff options
Diffstat (limited to 'kernel/debug')
-rw-r--r-- | kernel/debug/debug_core.c | 105 | ||||
-rw-r--r-- | kernel/debug/debug_core.h | 1 |
2 files changed, 56 insertions, 50 deletions
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index bb9497724808..26dbdc37d219 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c | |||
@@ -110,13 +110,15 @@ static struct kgdb_bkpt kgdb_break[KGDB_MAX_BREAKPOINTS] = { | |||
110 | */ | 110 | */ |
111 | atomic_t kgdb_active = ATOMIC_INIT(-1); | 111 | atomic_t kgdb_active = ATOMIC_INIT(-1); |
112 | 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); | ||
113 | 115 | ||
114 | /* | 116 | /* |
115 | * 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 |
116 | * bootup code (which might not have percpu set up yet): | 118 | * bootup code (which might not have percpu set up yet): |
117 | */ | 119 | */ |
118 | static atomic_t passive_cpu_wait[NR_CPUS]; | 120 | static atomic_t masters_in_kgdb; |
119 | static atomic_t cpu_in_kgdb[NR_CPUS]; | 121 | static atomic_t slaves_in_kgdb; |
120 | static atomic_t kgdb_break_tasklet_var; | 122 | static atomic_t kgdb_break_tasklet_var; |
121 | atomic_t kgdb_setting_breakpoint; | 123 | atomic_t kgdb_setting_breakpoint; |
122 | 124 | ||
@@ -478,14 +480,23 @@ static void dbg_touch_watchdogs(void) | |||
478 | rcu_cpu_stall_reset(); | 480 | rcu_cpu_stall_reset(); |
479 | } | 481 | } |
480 | 482 | ||
481 | static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs) | 483 | static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs, |
484 | int exception_state) | ||
482 | { | 485 | { |
483 | unsigned long flags; | 486 | unsigned long flags; |
484 | int sstep_tries = 100; | 487 | int sstep_tries = 100; |
485 | int error; | 488 | int error; |
486 | int i, cpu; | 489 | int cpu; |
487 | int trace_on = 0; | 490 | int trace_on = 0; |
491 | int online_cpus = num_online_cpus(); | ||
488 | 492 | ||
493 | kgdb_info[ks->cpu].enter_kgdb++; | ||
494 | kgdb_info[ks->cpu].exception_state |= exception_state; | ||
495 | |||
496 | if (exception_state == DCPU_WANT_MASTER) | ||
497 | atomic_inc(&masters_in_kgdb); | ||
498 | else | ||
499 | atomic_inc(&slaves_in_kgdb); | ||
489 | kgdb_disable_hw_debug(ks->linux_regs); | 500 | kgdb_disable_hw_debug(ks->linux_regs); |
490 | 501 | ||
491 | acquirelock: | 502 | acquirelock: |
@@ -500,14 +511,15 @@ acquirelock: | |||
500 | kgdb_info[cpu].task = current; | 511 | kgdb_info[cpu].task = current; |
501 | kgdb_info[cpu].ret_state = 0; | 512 | kgdb_info[cpu].ret_state = 0; |
502 | kgdb_info[cpu].irq_depth = hardirq_count() >> HARDIRQ_SHIFT; | 513 | kgdb_info[cpu].irq_depth = hardirq_count() >> HARDIRQ_SHIFT; |
503 | /* | ||
504 | * Make sure the above info reaches the primary CPU before | ||
505 | * our cpu_in_kgdb[] flag setting does: | ||
506 | */ | ||
507 | atomic_inc(&cpu_in_kgdb[cpu]); | ||
508 | 514 | ||
509 | if (exception_level == 1) | 515 | /* Make sure the above info reaches the primary CPU */ |
516 | smp_mb(); | ||
517 | |||
518 | if (exception_level == 1) { | ||
519 | if (raw_spin_trylock(&dbg_master_lock)) | ||
520 | atomic_xchg(&kgdb_active, cpu); | ||
510 | goto cpu_master_loop; | 521 | goto cpu_master_loop; |
522 | } | ||
511 | 523 | ||
512 | /* | 524 | /* |
513 | * CPU will loop if it is a slave or request to become a kgdb | 525 | * CPU will loop if it is a slave or request to become a kgdb |
@@ -519,10 +531,12 @@ cpu_loop: | |||
519 | kgdb_info[cpu].exception_state &= ~DCPU_NEXT_MASTER; | 531 | kgdb_info[cpu].exception_state &= ~DCPU_NEXT_MASTER; |
520 | goto cpu_master_loop; | 532 | goto cpu_master_loop; |
521 | } else if (kgdb_info[cpu].exception_state & DCPU_WANT_MASTER) { | 533 | } else if (kgdb_info[cpu].exception_state & DCPU_WANT_MASTER) { |
522 | if (atomic_cmpxchg(&kgdb_active, -1, cpu) == cpu) | 534 | if (raw_spin_trylock(&dbg_master_lock)) { |
535 | atomic_xchg(&kgdb_active, cpu); | ||
523 | break; | 536 | break; |
537 | } | ||
524 | } else if (kgdb_info[cpu].exception_state & DCPU_IS_SLAVE) { | 538 | } else if (kgdb_info[cpu].exception_state & DCPU_IS_SLAVE) { |
525 | if (!atomic_read(&passive_cpu_wait[cpu])) | 539 | if (!raw_spin_is_locked(&dbg_slave_lock)) |
526 | goto return_normal; | 540 | goto return_normal; |
527 | } else { | 541 | } else { |
528 | return_normal: | 542 | return_normal: |
@@ -533,7 +547,11 @@ return_normal: | |||
533 | arch_kgdb_ops.correct_hw_break(); | 547 | arch_kgdb_ops.correct_hw_break(); |
534 | if (trace_on) | 548 | if (trace_on) |
535 | tracing_on(); | 549 | tracing_on(); |
536 | atomic_dec(&cpu_in_kgdb[cpu]); | 550 | kgdb_info[cpu].exception_state &= |
551 | ~(DCPU_WANT_MASTER | DCPU_IS_SLAVE); | ||
552 | kgdb_info[cpu].enter_kgdb--; | ||
553 | smp_mb__before_atomic_dec(); | ||
554 | atomic_dec(&slaves_in_kgdb); | ||
537 | dbg_touch_watchdogs(); | 555 | dbg_touch_watchdogs(); |
538 | local_irq_restore(flags); | 556 | local_irq_restore(flags); |
539 | return 0; | 557 | return 0; |
@@ -551,6 +569,7 @@ return_normal: | |||
551 | (kgdb_info[cpu].task && | 569 | (kgdb_info[cpu].task && |
552 | kgdb_info[cpu].task->pid != kgdb_sstep_pid) && --sstep_tries) { | 570 | kgdb_info[cpu].task->pid != kgdb_sstep_pid) && --sstep_tries) { |
553 | atomic_set(&kgdb_active, -1); | 571 | atomic_set(&kgdb_active, -1); |
572 | raw_spin_unlock(&dbg_master_lock); | ||
554 | dbg_touch_watchdogs(); | 573 | dbg_touch_watchdogs(); |
555 | local_irq_restore(flags); | 574 | local_irq_restore(flags); |
556 | 575 | ||
@@ -576,10 +595,8 @@ return_normal: | |||
576 | * Get the passive CPU lock which will hold all the non-primary | 595 | * Get the passive CPU lock which will hold all the non-primary |
577 | * CPU in a spin state while the debugger is active | 596 | * CPU in a spin state while the debugger is active |
578 | */ | 597 | */ |
579 | if (!kgdb_single_step) { | 598 | if (!kgdb_single_step) |
580 | for (i = 0; i < NR_CPUS; i++) | 599 | raw_spin_lock(&dbg_slave_lock); |
581 | atomic_inc(&passive_cpu_wait[i]); | ||
582 | } | ||
583 | 600 | ||
584 | #ifdef CONFIG_SMP | 601 | #ifdef CONFIG_SMP |
585 | /* Signal the other CPUs to enter kgdb_wait() */ | 602 | /* Signal the other CPUs to enter kgdb_wait() */ |
@@ -590,10 +607,9 @@ return_normal: | |||
590 | /* | 607 | /* |
591 | * Wait for the other CPUs to be notified and be waiting for us: | 608 | * Wait for the other CPUs to be notified and be waiting for us: |
592 | */ | 609 | */ |
593 | for_each_online_cpu(i) { | 610 | while (kgdb_do_roundup && (atomic_read(&masters_in_kgdb) + |
594 | while (kgdb_do_roundup && !atomic_read(&cpu_in_kgdb[i])) | 611 | atomic_read(&slaves_in_kgdb)) != online_cpus) |
595 | cpu_relax(); | 612 | cpu_relax(); |
596 | } | ||
597 | 613 | ||
598 | /* | 614 | /* |
599 | * At this point the primary processor is completely | 615 | * At this point the primary processor is completely |
@@ -634,24 +650,11 @@ cpu_master_loop: | |||
634 | if (dbg_io_ops->post_exception) | 650 | if (dbg_io_ops->post_exception) |
635 | dbg_io_ops->post_exception(); | 651 | dbg_io_ops->post_exception(); |
636 | 652 | ||
637 | atomic_dec(&cpu_in_kgdb[ks->cpu]); | ||
638 | |||
639 | if (!kgdb_single_step) { | 653 | if (!kgdb_single_step) { |
640 | for (i = NR_CPUS-1; i >= 0; i--) | 654 | raw_spin_unlock(&dbg_slave_lock); |
641 | atomic_dec(&passive_cpu_wait[i]); | 655 | /* Wait till all the CPUs have quit from the debugger. */ |
642 | /* | 656 | while (kgdb_do_roundup && atomic_read(&slaves_in_kgdb)) |
643 | * Wait till all the CPUs have quit from the debugger, | 657 | cpu_relax(); |
644 | * but allow a CPU that hit an exception and is | ||
645 | * waiting to become the master to remain in the debug | ||
646 | * core. | ||
647 | */ | ||
648 | for_each_online_cpu(i) { | ||
649 | while (kgdb_do_roundup && | ||
650 | atomic_read(&cpu_in_kgdb[i]) && | ||
651 | !(kgdb_info[i].exception_state & | ||
652 | DCPU_WANT_MASTER)) | ||
653 | cpu_relax(); | ||
654 | } | ||
655 | } | 658 | } |
656 | 659 | ||
657 | kgdb_restore: | 660 | kgdb_restore: |
@@ -666,8 +669,15 @@ kgdb_restore: | |||
666 | arch_kgdb_ops.correct_hw_break(); | 669 | arch_kgdb_ops.correct_hw_break(); |
667 | if (trace_on) | 670 | if (trace_on) |
668 | tracing_on(); | 671 | tracing_on(); |
672 | |||
673 | kgdb_info[cpu].exception_state &= | ||
674 | ~(DCPU_WANT_MASTER | DCPU_IS_SLAVE); | ||
675 | kgdb_info[cpu].enter_kgdb--; | ||
676 | smp_mb__before_atomic_dec(); | ||
677 | atomic_dec(&masters_in_kgdb); | ||
669 | /* Free kgdb_active */ | 678 | /* Free kgdb_active */ |
670 | atomic_set(&kgdb_active, -1); | 679 | atomic_set(&kgdb_active, -1); |
680 | raw_spin_unlock(&dbg_master_lock); | ||
671 | dbg_touch_watchdogs(); | 681 | dbg_touch_watchdogs(); |
672 | local_irq_restore(flags); | 682 | local_irq_restore(flags); |
673 | 683 | ||
@@ -686,7 +696,6 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | |||
686 | { | 696 | { |
687 | struct kgdb_state kgdb_var; | 697 | struct kgdb_state kgdb_var; |
688 | struct kgdb_state *ks = &kgdb_var; | 698 | struct kgdb_state *ks = &kgdb_var; |
689 | int ret; | ||
690 | 699 | ||
691 | ks->cpu = raw_smp_processor_id(); | 700 | ks->cpu = raw_smp_processor_id(); |
692 | ks->ex_vector = evector; | 701 | ks->ex_vector = evector; |
@@ -697,11 +706,10 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | |||
697 | 706 | ||
698 | if (kgdb_reenter_check(ks)) | 707 | if (kgdb_reenter_check(ks)) |
699 | return 0; /* Ouch, double exception ! */ | 708 | return 0; /* Ouch, double exception ! */ |
700 | kgdb_info[ks->cpu].exception_state |= DCPU_WANT_MASTER; | 709 | if (kgdb_info[ks->cpu].enter_kgdb != 0) |
701 | ret = kgdb_cpu_enter(ks, regs); | 710 | return 0; |
702 | kgdb_info[ks->cpu].exception_state &= ~(DCPU_WANT_MASTER | | 711 | |
703 | DCPU_IS_SLAVE); | 712 | return kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER); |
704 | return ret; | ||
705 | } | 713 | } |
706 | 714 | ||
707 | int kgdb_nmicallback(int cpu, void *regs) | 715 | int kgdb_nmicallback(int cpu, void *regs) |
@@ -714,12 +722,9 @@ int kgdb_nmicallback(int cpu, void *regs) | |||
714 | ks->cpu = cpu; | 722 | ks->cpu = cpu; |
715 | ks->linux_regs = regs; | 723 | ks->linux_regs = regs; |
716 | 724 | ||
717 | if (!atomic_read(&cpu_in_kgdb[cpu]) && | 725 | if (kgdb_info[ks->cpu].enter_kgdb == 0 && |
718 | atomic_read(&kgdb_active) != -1 && | 726 | raw_spin_is_locked(&dbg_master_lock)) { |
719 | atomic_read(&kgdb_active) != cpu) { | 727 | kgdb_cpu_enter(ks, regs, DCPU_IS_SLAVE); |
720 | kgdb_info[cpu].exception_state |= DCPU_IS_SLAVE; | ||
721 | kgdb_cpu_enter(ks, regs); | ||
722 | kgdb_info[cpu].exception_state &= ~DCPU_IS_SLAVE; | ||
723 | return 0; | 728 | return 0; |
724 | } | 729 | } |
725 | #endif | 730 | #endif |
diff --git a/kernel/debug/debug_core.h b/kernel/debug/debug_core.h index c5d753d80f67..3494c28a7e7a 100644 --- a/kernel/debug/debug_core.h +++ b/kernel/debug/debug_core.h | |||
@@ -40,6 +40,7 @@ struct debuggerinfo_struct { | |||
40 | int exception_state; | 40 | int exception_state; |
41 | int ret_state; | 41 | int ret_state; |
42 | int irq_depth; | 42 | int irq_depth; |
43 | int enter_kgdb; | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | extern struct debuggerinfo_struct kgdb_info[]; | 46 | extern struct debuggerinfo_struct kgdb_info[]; |