@@ -16,7 +16,7 @@ config SPARC
select OF_PROMTREE
select HAVE_IDE
select HAVE_OPROFILE
- select HAVE_ARCH_KGDB if !SMP || SPARC64
+ select HAVE_ARCH_KGDB
select HAVE_ARCH_TRACEHOOK
select ARCH_WANT_OPTIONAL_GPIOLIB
select RTC_CLASS
@@ -60,6 +60,9 @@ void smp_info(struct seq_file *);
BTFIXUPDEF_CALL(void, smp_cross_call, smpfunc_t, cpumask_t, unsigned long, unsigned long, unsigned long, unsigned long)
BTFIXUPDEF_CALL(int, __hard_smp_processor_id, void)
+#ifdef CONFIG_KGDB
+BTFIXUPDEF_CALL(void, smp_ipi_kgdbcapture, int);
+#endif
BTFIXUPDEF_CALL(void, smp_ipi_resched, int);
BTFIXUPDEF_CALL(void, smp_ipi_single, int);
BTFIXUPDEF_CALL(void, smp_ipi_mask_one, int);
@@ -433,7 +433,7 @@ smpleon_ipi:
wr %g2, PSR_ET, %psr
WRITE_PAUSE
call leonsmp_ipi_interrupt
- add %sp, STACKFRAME_SZ, %o1 ! pt_regs
+ add %sp, STACKFRAME_SZ, %o0 ! pt_regs
wr %l0, PSR_ET, %psr
WRITE_PAUSE
RESTORE_ALL
@@ -90,6 +90,6 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int)
/* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */
#define SUN4D_IPI_IRQ 14
-extern void sun4d_ipi_interrupt(void);
+extern void sun4d_ipi_interrupt(struct pt_regs *regs);
#endif
@@ -9,6 +9,8 @@
#include <asm/head.h>
#include <linux/kernel.h>
+#include <linux/kgdb.h>
+#include <linux/kdebug.h>
#include <linux/sched.h>
#include <linux/threads.h>
#include <linux/smp.h>
@@ -42,6 +44,7 @@
#include <asm/asi.h>
#include <asm/leon.h>
#include <asm/leon_amba.h>
+#include <asm/kdebug.h>
#include "kernel.h"
@@ -306,6 +309,7 @@ struct leon_ipi_work {
int single;
int msk;
int resched;
+ int kgdbcapture;
};
static DEFINE_PER_CPU_SHARED_ALIGNED(struct leon_ipi_work, leon_ipi_work);
@@ -340,7 +344,7 @@ static void __init leon_ipi_init(void)
for_each_possible_cpu(cpu) {
work = &per_cpu(leon_ipi_work, cpu);
- work->single = work->msk = work->resched = 0;
+ work->single = work->msk = work->resched = work->kgdbcapture = 0;
}
}
@@ -355,6 +359,19 @@ static void leon_ipi_single(int cpu)
set_cpu_int(cpu, leon_ipi_irq);
}
+#ifdef CONFIG_KGDB
+static void leon_ipi_kgdbcapture(int cpu)
+{
+ struct leon_ipi_work *work = &per_cpu(leon_ipi_work, cpu);
+
+ /* Mark work */
+ work->kgdbcapture = 1;
+
+ /* Generate IRQ on the CPU */
+ set_cpu_int(cpu, leon_ipi_irq);
+}
+#endif
+
static void leon_ipi_mask_one(int cpu)
{
struct leon_ipi_work *work = &per_cpu(leon_ipi_work, cpu);
@@ -377,7 +394,7 @@ static void leon_ipi_resched(int cpu)
set_cpu_int(cpu, leon_ipi_irq);
}
-void leonsmp_ipi_interrupt(void)
+void leonsmp_ipi_interrupt(struct pt_regs *regs)
{
struct leon_ipi_work *work = &__get_cpu_var(leon_ipi_work);
@@ -393,6 +410,13 @@ void leonsmp_ipi_interrupt(void)
work->resched = 0;
smp_resched_interrupt();
}
+ if (work->kgdbcapture) {
+ work->kgdbcapture = 0;
+#ifdef CONFIG_KGDB
+ if (atomic_read(&kgdb_active) != -1)
+ kgdb_nmicallback(raw_smp_processor_id(), regs);
+#endif
+ }
}
static struct smp_funcall {
@@ -548,6 +572,9 @@ void __init leon_init_smp(void)
BTFIXUPSET_CALL(smp_cross_call, leon_cross_call, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(__hard_smp_processor_id, __leon_processor_id,
BTFIXUPCALL_NORM);
+#ifdef CONFIG_KGDB
+ BTFIXUPSET_CALL(smp_ipi_kgdbcapture, leon_ipi_kgdbcapture, BTFIXUPCALL_NORM);
+#endif
BTFIXUPSET_CALL(smp_ipi_resched, leon_ipi_resched, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(smp_ipi_single, leon_ipi_single, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(smp_ipi_mask_one, leon_ipi_mask_one, BTFIXUPCALL_NORM);
@@ -179,6 +179,20 @@ void smp_call_function_interrupt(void)
irq_exit();
}
+#ifdef CONFIG_KGDB
+void kgdb_roundup_cpus(unsigned long flags)
+{
+ int i, this_cpu = smp_processor_id();
+ const cpumask_t *mask = cpu_online_mask;
+
+ for_each_cpu(i, mask) {
+ if (i == this_cpu || !cpu_online(i))
+ continue;
+ BTFIXUP_CALL(smp_ipi_kgdbcapture)(i);
+ }
+}
+#endif
+
void smp_flush_cache_all(void)
{
xc0((smpfunc_t) BTFIXUP_CALL(local_flush_cache_all));
@@ -158,7 +158,7 @@ void sun4d_handler_irq(int pil, struct pt_regs *regs)
* IRQ can happen at the same time, so both cases are always handled.
*/
if (pil == SUN4D_IPI_IRQ)
- sun4d_ipi_interrupt();
+ sun4d_ipi_interrupt(regs);
#endif
old_regs = set_irq_regs(regs);
@@ -10,6 +10,7 @@
#include <linux/profile.h>
#include <linux/delay.h>
#include <linux/cpu.h>
+#include <linux/kgdb.h>
#include <asm/sbi.h>
#include <asm/mmu.h>
@@ -196,6 +197,7 @@ struct sun4d_ipi_work {
int single;
int msk;
int resched;
+ int kgdbcapture;
};
static DEFINE_PER_CPU_SHARED_ALIGNED(struct sun4d_ipi_work, sun4d_ipi_work);
@@ -210,11 +212,11 @@ static void __init smp4d_ipi_init(void)
for_each_possible_cpu(cpu) {
work = &per_cpu(sun4d_ipi_work, cpu);
- work->single = work->msk = work->resched = 0;
+ work->single = work->msk = work->resched = work->kgdbcapture = 0;
}
}
-void sun4d_ipi_interrupt(void)
+void sun4d_ipi_interrupt(struct pt_regs *regs)
{
struct sun4d_ipi_work *work = &__get_cpu_var(sun4d_ipi_work);
@@ -230,7 +232,28 @@ void sun4d_ipi_interrupt(void)
work->resched = 0;
smp_resched_interrupt();
}
+ if (work->kgdbcapture) {
+ work->kgdbcapture = 0;
+#ifdef CONFIG_KGDB
+ if (atomic_read(&kgdb_active) != -1)
+ kgdb_nmicallback(raw_smp_processor_id(), regs);
+#endif
+ }
+
+}
+
+#ifdef CONFIG_KGDB
+static void smp4d_ipi_kgdbcapture(int cpu)
+{
+ struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu);
+
+ /* Mark work */
+ work->kgdbcapture = 1;
+
+ /* Generate IRQ on the CPU */
+ sun4d_send_ipi(cpu, SUN4D_IPI_IRQ);
}
+#endif
static void smp4d_ipi_single(int cpu)
{
@@ -430,6 +453,9 @@ void __init sun4d_init_smp(void)
BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current);
BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM);
+#ifdef CONFIG_KGDB
+ BTFIXUPSET_CALL(smp_ipi_kgdbcapture, smp4d_ipi_kgdbcapture, BTFIXUPCALL_NORM);
+#endif
BTFIXUPSET_CALL(smp_ipi_resched, smp4d_ipi_resched, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(smp_ipi_single, smp4d_ipi_single, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(smp_ipi_mask_one, smp4d_ipi_mask_one, BTFIXUPCALL_NORM);
@@ -159,6 +159,14 @@ static void __init smp4m_ipi_init(void)
{
}
+#ifdef CONFIG_KGDB
+static void smp4m_ipi_kgdbcapture(int cpu)
+{
+ printk(KERN_INFO "Note: Not implemented yet\n");
+ BUG();
+}
+#endif
+
static void smp4m_ipi_resched(int cpu)
{
set_cpu_int(cpu, IRQ_IPI_RESCHED);
@@ -316,6 +324,9 @@ void __init sun4m_init_smp(void)
BTFIXUPSET_BLACKBOX(load_current, smp4m_blackbox_current);
BTFIXUPSET_CALL(smp_cross_call, smp4m_cross_call, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4m_processor_id, BTFIXUPCALL_NORM);
+#ifdef CONFIG_KGDB
+ BTFIXUPSET_CALL(smp_ipi_kgdbcapture, smp4m_ipi_kgdbcapture, BTFIXUPCALL_NORM);
+#endif
BTFIXUPSET_CALL(smp_ipi_resched, smp4m_ipi_resched, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(smp_ipi_single, smp4m_ipi_single, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(smp_ipi_mask_one, smp4m_ipi_mask_one, BTFIXUPCALL_NORM);
This patch enables KGDB support when SMP is enabled. kgdb_nmicallback calls for leon and sun4d are implemented. For sun4m the smp4m_ipi_kgdbcapture is still a stub to be implemented later. Signed-off-by: Konrad Eisele <konrad@gaisler.com> --- arch/sparc/Kconfig | 2 +- arch/sparc/include/asm/smp_32.h | 3 +++ arch/sparc/kernel/entry.S | 2 +- arch/sparc/kernel/irq.h | 2 +- arch/sparc/kernel/leon_smp.c | 31 +++++++++++++++++++++++++++++-- arch/sparc/kernel/smp_32.c | 14 ++++++++++++++ arch/sparc/kernel/sun4d_irq.c | 2 +- arch/sparc/kernel/sun4d_smp.c | 30 ++++++++++++++++++++++++++++-- arch/sparc/kernel/sun4m_smp.c | 11 +++++++++++ 9 files changed, 89 insertions(+), 8 deletions(-)