Skip to content

Commit

Permalink
Merge branch 'smp' into devel
Browse files Browse the repository at this point in the history
  • Loading branch information
Russell King authored and Russell King committed Jun 1, 2009
2 parents a22f277 + e03cdad commit c7f7ff1
Show file tree
Hide file tree
Showing 17 changed files with 398 additions and 307 deletions.
15 changes: 15 additions & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,9 @@ source "kernel/time/Kconfig"
config SMP
bool "Symmetric Multi-Processing (EXPERIMENTAL)"
depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP)
depends on GENERIC_CLOCKEVENTS
select USE_GENERIC_SMP_HELPERS
select HAVE_ARM_SCU if ARCH_REALVIEW
help
This enables support for systems with more than one CPU. If you have
a system with only one CPU, like most personal computers, say N. If
Expand All @@ -862,6 +864,18 @@ config SMP

If you don't know what to do here, say N.

config HAVE_ARM_SCU
bool
depends on SMP
help
This option enables support for the ARM system coherency unit

config HAVE_ARM_TWD
bool
depends on SMP
help
This options enables support for the ARM timer and watchdog unit

choice
prompt "Memory split"
default VMSPLIT_3G
Expand Down Expand Up @@ -902,6 +916,7 @@ config LOCAL_TIMERS
bool "Use local timer interrupts"
depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || REALVIEW_EB_A9MP)
default y
select HAVE_ARM_TWD if ARCH_REALVIEW
help
Enable support for local timers on SMP platforms, rather then the
legacy IPI broadcast method. Local timers allows the system
Expand Down
21 changes: 0 additions & 21 deletions arch/arm/include/asm/hardware/arm_twd.h

This file was deleted.

63 changes: 63 additions & 0 deletions arch/arm/include/asm/localtimer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* arch/arm/include/asm/localtimer.h
*
* Copyright (C) 2004-2005 ARM Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_ARM_LOCALTIMER_H
#define __ASM_ARM_LOCALTIMER_H

struct clock_event_device;

/*
* Setup a per-cpu timer, whether it be a local timer or dummy broadcast
*/
void percpu_timer_setup(void);

/*
* Called from assembly, this is the local timer IRQ handler
*/
asmlinkage void do_local_timer(struct pt_regs *);


#ifdef CONFIG_LOCAL_TIMERS

#ifdef CONFIG_HAVE_ARM_TWD

#include "smp_twd.h"

#define local_timer_ack() twd_timer_ack()
#define local_timer_stop() twd_timer_stop()

#else

/*
* Platform provides this to acknowledge a local timer IRQ.
* Returns true if the local timer IRQ is to be processed.
*/
int local_timer_ack(void);

/*
* Stop a local timer interrupt.
*/
void local_timer_stop(void);

#endif

/*
* Setup a local timer interrupt for a CPU.
*/
void local_timer_setup(struct clock_event_device *);

#else

static inline void local_timer_stop(void)
{
}

#endif

#endif
42 changes: 1 addition & 41 deletions arch/arm/include/asm/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ extern void show_ipi_list(struct seq_file *p);
asmlinkage void do_IPI(struct pt_regs *regs);

/*
* Setup the SMP cpu_possible_map
* Setup the set of possible CPUs (via set_cpu_possible)
*/
extern void smp_init_cpus(void);

Expand All @@ -55,11 +55,6 @@ extern void smp_store_cpu_info(unsigned int cpuid);
*/
extern void smp_cross_call(const struct cpumask *mask);

/*
* Broadcast a clock event to other CPUs.
*/
extern void smp_timer_broadcast(const struct cpumask *mask);

/*
* Boot a secondary CPU, and assign it the specified idle task.
* This also gives us the initial stack to use for this CPU.
Expand Down Expand Up @@ -100,44 +95,9 @@ extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask

/*
* Local timer interrupt handling function (can be IPI'ed).
*/
extern void local_timer_interrupt(void);

#ifdef CONFIG_LOCAL_TIMERS

/*
* Stop a local timer interrupt.
*/
extern void local_timer_stop(void);

/*
* Platform provides this to acknowledge a local timer IRQ
*/
extern int local_timer_ack(void);

#else

static inline void local_timer_stop(void)
{
}

#endif

/*
* Setup a local timer interrupt for a CPU.
*/
extern void local_timer_setup(void);

/*
* show local interrupt info
*/
extern void show_local_irqs(struct seq_file *);

/*
* Called from assembly, this is the local timer IRQ handler
*/
asmlinkage void do_local_timer(struct pt_regs *);

#endif /* ifndef __ASM_ARM_SMP_H */
7 changes: 7 additions & 0 deletions arch/arm/include/asm/smp_scu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef __ASMARM_ARCH_SCU_H
#define __ASMARM_ARCH_SCU_H

unsigned int scu_get_core_count(void __iomem *);
void scu_enable(void __iomem *);

#endif
12 changes: 12 additions & 0 deletions arch/arm/include/asm/smp_twd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef __ASMARM_SMP_TWD_H
#define __ASMARM_SMP_TWD_H

struct clock_event_device;

extern void __iomem *twd_base;

void twd_timer_stop(void);
int twd_timer_ack(void);
void twd_timer_setup(struct clock_event_device *);

#endif
2 changes: 2 additions & 0 deletions arch/arm/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ obj-$(CONFIG_ARTHUR) += arthur.o
obj-$(CONFIG_ISA_DMA) += dma-isa.o
obj-$(CONFIG_PCI) += bios32.o isa.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o
obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o
Expand Down
62 changes: 51 additions & 11 deletions arch/arm/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include <linux/smp.h>
#include <linux/seq_file.h>
#include <linux/irq.h>
#include <linux/percpu.h>
#include <linux/clockchips.h>

#include <asm/atomic.h>
#include <asm/cacheflush.h>
Expand All @@ -32,6 +34,7 @@
#include <asm/processor.h>
#include <asm/tlbflush.h>
#include <asm/ptrace.h>
#include <asm/localtimer.h>

/*
* as from 2.5, kernels no longer have an init_tasks structure
Expand Down Expand Up @@ -163,7 +166,7 @@ int __cpuexit __cpu_disable(void)
* Take this CPU offline. Once we clear this, we can't return,
* and we must not schedule until we're ready to give up the cpu.
*/
cpu_clear(cpu, cpu_online_map);
set_cpu_online(cpu, false);

/*
* OK - migrate IRQs away from this CPU
Expand Down Expand Up @@ -274,9 +277,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
local_fiq_enable();

/*
* Setup local timer for this CPU.
* Setup the percpu timer for this CPU.
*/
local_timer_setup();
percpu_timer_setup();

calibrate_delay();

Expand All @@ -285,7 +288,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
/*
* OK, now it's safe to let the boot CPU continue
*/
cpu_set(cpu, cpu_online_map);
set_cpu_online(cpu, true);

/*
* OK, it's off to the idle thread for us
Expand Down Expand Up @@ -383,10 +386,16 @@ void show_local_irqs(struct seq_file *p)
seq_putc(p, '\n');
}

/*
* Timer (local or broadcast) support
*/
static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent);

static void ipi_timer(void)
{
struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
irq_enter();
local_timer_interrupt();
evt->event_handler(evt);
irq_exit();
}

Expand All @@ -405,6 +414,42 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs)
}
#endif

#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
static void smp_timer_broadcast(const struct cpumask *mask)
{
send_ipi_message(mask, IPI_TIMER);
}

static void broadcast_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
}

static void local_timer_setup(struct clock_event_device *evt)
{
evt->name = "dummy_timer";
evt->features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_DUMMY;
evt->rating = 400;
evt->mult = 1;
evt->set_mode = broadcast_timer_set_mode;
evt->broadcast = smp_timer_broadcast;

clockevents_register_device(evt);
}
#endif

void __cpuinit percpu_timer_setup(void)
{
unsigned int cpu = smp_processor_id();
struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);

evt->cpumask = cpumask_of(cpu);

local_timer_setup(evt);
}

static DEFINE_SPINLOCK(stop_lock);

/*
Expand All @@ -417,7 +462,7 @@ static void ipi_cpu_stop(unsigned int cpu)
dump_stack();
spin_unlock(&stop_lock);

cpu_clear(cpu, cpu_online_map);
set_cpu_online(cpu, false);

local_fiq_disable();
local_irq_disable();
Expand Down Expand Up @@ -501,11 +546,6 @@ void smp_send_reschedule(int cpu)
send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
}

void smp_timer_broadcast(const struct cpumask *mask)
{
send_ipi_message(mask, IPI_TIMER);
}

void smp_send_stop(void)
{
cpumask_t mask = cpu_online_map;
Expand Down
48 changes: 48 additions & 0 deletions arch/arm/kernel/smp_scu.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* linux/arch/arm/kernel/smp_scu.c
*
* Copyright (C) 2002 ARM Ltd.
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/io.h>

#include <asm/smp_scu.h>
#include <asm/cacheflush.h>

#define SCU_CTRL 0x00
#define SCU_CONFIG 0x04
#define SCU_CPU_STATUS 0x08
#define SCU_INVALIDATE 0x0c
#define SCU_FPGA_REVISION 0x10

/*
* Get the number of CPU cores from the SCU configuration
*/
unsigned int __init scu_get_core_count(void __iomem *scu_base)
{
unsigned int ncores = __raw_readl(scu_base + SCU_CONFIG);
return (ncores & 0x03) + 1;
}

/*
* Enable the SCU
*/
void __init scu_enable(void __iomem *scu_base)
{
u32 scu_ctrl;

scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
scu_ctrl |= 1;
__raw_writel(scu_ctrl, scu_base + SCU_CTRL);

/*
* Ensure that the data accessed by CPU0 before the SCU was
* initialised is visible to the other CPUs.
*/
flush_cache_all();
}
Loading

0 comments on commit c7f7ff1

Please sign in to comment.