Skip to content

Commit

Permalink
sparc,leon: Sparc-Leon SMP support
Browse files Browse the repository at this point in the history
Support SMP for a Sparc-Leon multiprocessor system.
Add Leon specific SMP code to arch/sparc/kernel/leon_smp.c.

Signed-off-by: Konrad Eisele <konrad@gaisler.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Konrad Eisele authored and David S. Miller committed Nov 2, 2009
1 parent b6727b1 commit 8401707
Show file tree
Hide file tree
Showing 11 changed files with 732 additions and 3 deletions.
28 changes: 28 additions & 0 deletions arch/sparc/include/asm/leon.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,30 @@ extern int leon_flush_needed(void);
extern void leon_switch_mm(void);
extern int srmmu_swprobe_trace;

#ifdef CONFIG_SMP
extern int leon_smp_nrcpus(void);
extern void leon_clear_profile_irq(int cpu);
extern void leon_smp_done(void);
extern void leon_boot_cpus(void);
extern int leon_boot_one_cpu(int i);
void leon_init_smp(void);
extern void cpu_probe(void);
extern void cpu_idle(void);
extern void init_IRQ(void);
extern void cpu_panic(void);
extern int __leon_processor_id(void);
void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu);

extern unsigned int real_irq_entry[], smpleon_ticker[];
extern unsigned int patchme_maybe_smp_msg[];
extern unsigned long trapbase_cpu1[];
extern unsigned long trapbase_cpu2[];
extern unsigned long trapbase_cpu3[];
extern unsigned int t_nmi[], linux_trap_ipi15_leon[];
extern unsigned int linux_trap_ipi15_sun4m[];

#endif /* CONFIG_SMP */

#endif /* __KERNEL__ */

#endif /* __ASSEMBLY__ */
Expand All @@ -356,6 +380,10 @@ extern int srmmu_swprobe_trace;
#define leon_switch_mm() do {} while (0)
#define leon_init_IRQ() do {} while (0)
#define init_leon() do {} while (0)
#define leon_smp_done() do {} while (0)
#define leon_boot_cpus() do {} while (0)
#define leon_boot_one_cpu(i) 1
#define leon_init_smp() do {} while (0)

#endif /* !defined(CONFIG_SPARC_LEON) */

Expand Down
9 changes: 9 additions & 0 deletions arch/sparc/include/asm/smp_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,15 @@ static inline int hard_smp4d_processor_id(void)
return cpuid;
}

extern inline int hard_smpleon_processor_id(void)
{
int cpuid;
__asm__ __volatile__("rd %%asr17,%0\n\t"
"srl %0,28,%0" :
"=&r" (cpuid) : );
return cpuid;
}

#ifndef MODULE
static inline int hard_smp_processor_id(void)
{
Expand Down
2 changes: 1 addition & 1 deletion arch/sparc/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ obj-y += dma.o
obj-$(CONFIG_SPARC32_PCI) += pcic.o

obj-$(CONFIG_SMP) += trampoline_$(BITS).o smp_$(BITS).o
obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o
obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o leon_smp.o
obj-$(CONFIG_SPARC64_SMP) += hvtramp.o

obj-y += auxio_$(BITS).o
Expand Down
33 changes: 33 additions & 0 deletions arch/sparc/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,39 @@ linux_trap_ipi15_sun4d:
/* FIXME */
1: b,a 1b

#ifdef CONFIG_SPARC_LEON

.globl smpleon_ticker
/* SMP per-cpu ticker interrupts are handled specially. */
smpleon_ticker:
SAVE_ALL
or %l0, PSR_PIL, %g2
wr %g2, 0x0, %psr
WRITE_PAUSE
wr %g2, PSR_ET, %psr
WRITE_PAUSE
call leon_percpu_timer_interrupt
add %sp, STACKFRAME_SZ, %o0
wr %l0, PSR_ET, %psr
WRITE_PAUSE
RESTORE_ALL

.align 4
.globl linux_trap_ipi15_leon
linux_trap_ipi15_leon:
SAVE_ALL
or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr
WRITE_PAUSE
wr %l4, PSR_ET, %psr
WRITE_PAUSE
call leon_cross_call_irq
nop
b ret_trap_lockless_ipi
clr %l6

#endif /* CONFIG_SPARC_LEON */

#endif /* CONFIG_SMP */

/* This routine handles illegal instructions and privileged
Expand Down
22 changes: 22 additions & 0 deletions arch/sparc/kernel/head_32.S
Original file line number Diff line number Diff line change
Expand Up @@ -811,8 +811,30 @@ found_version:
got_prop:
#ifdef CONFIG_SPARC_LEON
/* no cpu-type check is needed, it is a SPARC-LEON */
#ifdef CONFIG_SMP
ba leon_smp_init
nop

.global leon_smp_init
leon_smp_init:
sethi %hi(boot_cpu_id), %g1 ! master always 0
stb %g0, [%g1 + %lo(boot_cpu_id)]
sethi %hi(boot_cpu_id4), %g1 ! master always 0
stb %g0, [%g1 + %lo(boot_cpu_id4)]

rd %asr17,%g1
srl %g1,28,%g1

cmp %g0,%g1
beq sun4c_continue_boot !continue with master
nop

ba leon_smp_cpu_startup
nop
#else
ba sun4c_continue_boot
nop
#endif
#endif
set cputypval, %o2
ldub [%o2 + 0x4], %l1
Expand Down
5 changes: 5 additions & 0 deletions arch/sparc/kernel/ioport.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,13 @@
#include <asm/dma.h>
#include <asm/iommu.h>
#include <asm/io-unit.h>
#include <asm/leon.h>

#ifdef CONFIG_SPARC_LEON
#define mmu_inval_dma_area(p, l) leon_flush_dcache_all()
#else
#define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */
#endif

static struct resource *_sparc_find_resource(struct resource *r,
unsigned long);
Expand Down
84 changes: 84 additions & 0 deletions arch/sparc/kernel/leon_kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
#include <linux/of_platform.h>
#include <linux/interrupt.h>
#include <linux/of_device.h>

#include <asm/oplib.h>
#include <asm/timer.h>
#include <asm/prom.h>
#include <asm/leon.h>
#include <asm/leon_amba.h>
#include <asm/traps.h>
#include <asm/cacheflush.h>

#include "prom.h"
#include "irq.h"
Expand Down Expand Up @@ -115,6 +118,21 @@ void __init leon_init_timers(irq_handler_t counter_fn)
(((1000000 / 100) - 1)));
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0);

#ifdef CONFIG_SMP
leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs;
leon_percpu_timer_dev[0].irq = leon3_gptimer_irq+1;

if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) &
(1<<LEON3_GPTIMER_SEPIRQ))) {
prom_printf("irq timer not configured with seperate irqs \n");
BUG();
}

LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].val, 0);
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/100) - 1)));
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0);
# endif

} else {
printk(KERN_ERR "No Timer/irqctrl found\n");
BUG();
Expand All @@ -130,11 +148,41 @@ void __init leon_init_timers(irq_handler_t counter_fn)
prom_halt();
}

# ifdef CONFIG_SMP
{
unsigned long flags;
struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (leon_percpu_timer_dev[0].irq - 1)];

/* For SMP we use the level 14 ticker, however the bootup code
* has copied the firmwares level 14 vector into boot cpu's
* trap table, we must fix this now or we get squashed.
*/
local_irq_save(flags);

patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */

/* Adjust so that we jump directly to smpleon_ticker */
trap_table->inst_three += smpleon_ticker - real_irq_entry;

local_flush_cache_all();
local_irq_restore(flags);
}
# endif

if (leon3_gptimer_regs) {
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl,
LEON3_GPTIMER_EN |
LEON3_GPTIMER_RL |
LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN);

#ifdef CONFIG_SMP
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl,
LEON3_GPTIMER_EN |
LEON3_GPTIMER_RL |
LEON3_GPTIMER_LD |
LEON3_GPTIMER_IRQEN);
#endif

}
}

Expand Down Expand Up @@ -175,6 +223,42 @@ void __init leon_node_init(struct device_node *dp, struct device_node ***nextp)
}
}

#ifdef CONFIG_SMP

void leon_set_cpu_int(int cpu, int level)
{
unsigned long mask;
mask = get_irqmask(level);
LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask);
}

static void leon_clear_ipi(int cpu, int level)
{
unsigned long mask;
mask = get_irqmask(level);
LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask<<16);
}

static void leon_set_udt(int cpu)
{
}

void leon_clear_profile_irq(int cpu)
{
}

void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu)
{
unsigned long mask, flags, *addr;
mask = get_irqmask(irq_nr);
local_irq_save(flags);
addr = (unsigned long *)&(leon3_irqctrl_regs->mask[cpu]);
LEON3_BYPASS_STORE_PA(addr, (LEON3_BYPASS_LOAD_PA(addr) | (mask)));
local_irq_restore(flags);
}

#endif

void __init leon_init_IRQ(void)
{
sparc_init_timers = leon_init_timers;
Expand Down
Loading

0 comments on commit 8401707

Please sign in to comment.