Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
c7f7ff17
Commit
c7f7ff17
authored
Jun 01, 2009
by
Russell King
Committed by
Russell King
Jun 01, 2009
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'smp' into devel
parents
a22f277b
e03cdade
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
398 additions
and
307 deletions
+398
-307
arch/arm/Kconfig
arch/arm/Kconfig
+15
-0
arch/arm/include/asm/hardware/arm_twd.h
arch/arm/include/asm/hardware/arm_twd.h
+0
-21
arch/arm/include/asm/localtimer.h
arch/arm/include/asm/localtimer.h
+63
-0
arch/arm/include/asm/smp.h
arch/arm/include/asm/smp.h
+1
-41
arch/arm/include/asm/smp_scu.h
arch/arm/include/asm/smp_scu.h
+7
-0
arch/arm/include/asm/smp_twd.h
arch/arm/include/asm/smp_twd.h
+12
-0
arch/arm/kernel/Makefile
arch/arm/kernel/Makefile
+2
-0
arch/arm/kernel/smp.c
arch/arm/kernel/smp.c
+51
-11
arch/arm/kernel/smp_scu.c
arch/arm/kernel/smp_scu.c
+48
-0
arch/arm/kernel/smp_twd.c
arch/arm/kernel/smp_twd.c
+175
-0
arch/arm/mach-realview/Makefile
arch/arm/mach-realview/Makefile
+2
-1
arch/arm/mach-realview/core.h
arch/arm/mach-realview/core.h
+0
-3
arch/arm/mach-realview/include/mach/scu.h
arch/arm/mach-realview/include/mach/scu.h
+0
-13
arch/arm/mach-realview/localtimer.c
arch/arm/mach-realview/localtimer.c
+5
-183
arch/arm/mach-realview/platsmp.c
arch/arm/mach-realview/platsmp.c
+15
-34
arch/arm/mach-realview/realview_eb.c
arch/arm/mach-realview/realview_eb.c
+1
-0
arch/arm/mach-realview/realview_pb11mp.c
arch/arm/mach-realview/realview_pb11mp.c
+1
-0
No files found.
arch/arm/Kconfig
View file @
c7f7ff17
...
...
@@ -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
...
...
@@ -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
...
...
@@ -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
...
...
arch/arm/include/asm/hardware/arm_twd.h
deleted
100644 → 0
View file @
a22f277b
#ifndef __ASM_HARDWARE_TWD_H
#define __ASM_HARDWARE_TWD_H
#define TWD_TIMER_LOAD 0x00
#define TWD_TIMER_COUNTER 0x04
#define TWD_TIMER_CONTROL 0x08
#define TWD_TIMER_INTSTAT 0x0C
#define TWD_WDOG_LOAD 0x20
#define TWD_WDOG_COUNTER 0x24
#define TWD_WDOG_CONTROL 0x28
#define TWD_WDOG_INTSTAT 0x2C
#define TWD_WDOG_RESETSTAT 0x30
#define TWD_WDOG_DISABLE 0x34
#define TWD_TIMER_CONTROL_ENABLE (1 << 0)
#define TWD_TIMER_CONTROL_ONESHOT (0 << 1)
#define TWD_TIMER_CONTROL_PERIODIC (1 << 1)
#define TWD_TIMER_CONTROL_IT_ENABLE (1 << 2)
#endif
arch/arm/include/asm/localtimer.h
0 → 100644
View file @
c7f7ff17
/*
* 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
arch/arm/include/asm/smp.h
View file @
c7f7ff17
...
...
@@ -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
);
...
...
@@ -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.
...
...
@@ -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 */
arch/arm/include/asm/smp_scu.h
0 → 100644
View file @
c7f7ff17
#ifndef __ASMARM_ARCH_SCU_H
#define __ASMARM_ARCH_SCU_H
unsigned
int
scu_get_core_count
(
void
__iomem
*
);
void
scu_enable
(
void
__iomem
*
);
#endif
arch/arm/include/asm/smp_twd.h
0 → 100644
View file @
c7f7ff17
#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
arch/arm/kernel/Makefile
View file @
c7f7ff17
...
...
@@ -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
...
...
arch/arm/kernel/smp.c
View file @
c7f7ff17
...
...
@@ -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>
...
...
@@ -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
...
...
@@ -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
...
...
@@ -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
();
...
...
@@ -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
...
...
@@ -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
();
}
...
...
@@ -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
);
/*
...
...
@@ -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
();
...
...
@@ -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
;
...
...
arch/arm/kernel/smp_scu.c
0 → 100644
View file @
c7f7ff17
/*
* 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
();
}
arch/arm/kernel/smp_twd.c
0 → 100644
View file @
c7f7ff17
/*
* linux/arch/arm/kernel/smp_twd.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/kernel.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/smp.h>
#include <linux/jiffies.h>
#include <linux/clockchips.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <asm/smp_twd.h>
#include <asm/hardware/gic.h>
#define TWD_TIMER_LOAD 0x00
#define TWD_TIMER_COUNTER 0x04
#define TWD_TIMER_CONTROL 0x08
#define TWD_TIMER_INTSTAT 0x0C
#define TWD_WDOG_LOAD 0x20
#define TWD_WDOG_COUNTER 0x24
#define TWD_WDOG_CONTROL 0x28
#define TWD_WDOG_INTSTAT 0x2C
#define TWD_WDOG_RESETSTAT 0x30
#define TWD_WDOG_DISABLE 0x34
#define TWD_TIMER_CONTROL_ENABLE (1 << 0)
#define TWD_TIMER_CONTROL_ONESHOT (0 << 1)
#define TWD_TIMER_CONTROL_PERIODIC (1 << 1)
#define TWD_TIMER_CONTROL_IT_ENABLE (1 << 2)
/* set up by the platform code */
void
__iomem
*
twd_base
;
static
unsigned
long
twd_timer_rate
;
static
void
twd_set_mode
(
enum
clock_event_mode
mode
,
struct
clock_event_device
*
clk
)
{
unsigned
long
ctrl
;
switch
(
mode
)
{
case
CLOCK_EVT_MODE_PERIODIC
:
/* timer load already set up */
ctrl
=
TWD_TIMER_CONTROL_ENABLE
|
TWD_TIMER_CONTROL_IT_ENABLE
|
TWD_TIMER_CONTROL_PERIODIC
;
break
;
case
CLOCK_EVT_MODE_ONESHOT
:
/* period set, and timer enabled in 'next_event' hook */
ctrl
=
TWD_TIMER_CONTROL_IT_ENABLE
|
TWD_TIMER_CONTROL_ONESHOT
;
break
;
case
CLOCK_EVT_MODE_UNUSED
:
case
CLOCK_EVT_MODE_SHUTDOWN
:
default:
ctrl
=
0
;
}
__raw_writel
(
ctrl
,
twd_base
+
TWD_TIMER_CONTROL
);
}
static
int
twd_set_next_event
(
unsigned
long
evt
,
struct
clock_event_device
*
unused
)
{
unsigned
long
ctrl
=
__raw_readl
(
twd_base
+
TWD_TIMER_CONTROL
);
ctrl
|=
TWD_TIMER_CONTROL_ENABLE
;
__raw_writel
(
evt
,
twd_base
+
TWD_TIMER_COUNTER
);
__raw_writel
(
ctrl
,
twd_base
+
TWD_TIMER_CONTROL
);
return
0
;
}
/*
* local_timer_ack: checks for a local timer interrupt.
*
* If a local timer interrupt has occurred, acknowledge and return 1.
* Otherwise, return 0.
*/
int
twd_timer_ack
(
void
)
{
if
(
__raw_readl
(
twd_base
+
TWD_TIMER_INTSTAT
))
{
__raw_writel
(
1
,
twd_base
+
TWD_TIMER_INTSTAT
);
return
1
;
}
return
0
;
}
static
void
__cpuinit
twd_calibrate_rate
(
void
)
{
unsigned
long
load
,
count
;
u64
waitjiffies
;
/*
* If this is the first time round, we need to work out how fast
* the timer ticks
*/
if
(
twd_timer_rate
==
0
)
{
printk
(
KERN_INFO
"Calibrating local timer... "
);
/* Wait for a tick to start */
waitjiffies
=
get_jiffies_64
()
+
1
;
while
(
get_jiffies_64
()
<
waitjiffies
)
udelay
(
10
);
/* OK, now the tick has started, let's get the timer going */
waitjiffies
+=
5
;
/* enable, no interrupt or reload */
__raw_writel
(
0x1
,
twd_base
+
TWD_TIMER_CONTROL
);
/* maximum value */
__raw_writel
(
0xFFFFFFFFU
,
twd_base
+
TWD_TIMER_COUNTER
);
while
(
get_jiffies_64
()
<
waitjiffies
)
udelay
(
10
);
count
=
__raw_readl
(
twd_base
+
TWD_TIMER_COUNTER
);
twd_timer_rate
=
(
0xFFFFFFFFU
-
count
)
*
(
HZ
/
5
);
printk
(
"%lu.%02luMHz.
\n
"
,
twd_timer_rate
/
1000000
,
(
twd_timer_rate
/
100000
)
%
100
);
}
load
=
twd_timer_rate
/
HZ
;
__raw_writel
(
load
,
twd_base
+
TWD_TIMER_LOAD
);
}
/*
* Setup the local clock events for a CPU.
*/
void
__cpuinit
twd_timer_setup
(
struct
clock_event_device
*
clk
)
{
unsigned
long
flags
;
twd_calibrate_rate
();
clk
->
name
=
"local_timer"
;
clk
->
features
=
CLOCK_EVT_FEAT_PERIODIC
|
CLOCK_EVT_FEAT_ONESHOT
;
clk
->
rating
=
350
;
clk
->
set_mode
=
twd_set_mode
;
clk
->
set_next_event
=
twd_set_next_event
;
clk
->
shift
=
20
;
clk
->
mult
=
div_sc
(
twd_timer_rate
,
NSEC_PER_SEC
,
clk
->
shift
);
clk
->
max_delta_ns
=
clockevent_delta2ns
(
0xffffffff
,
clk
);
clk
->
min_delta_ns
=
clockevent_delta2ns
(
0xf
,
clk
);
/* Make sure our local interrupt controller has this enabled */
local_irq_save
(
flags
);
get_irq_chip
(
clk
->
irq
)
->
unmask
(
clk
->
irq
);
local_irq_restore
(
flags
);
clockevents_register_device
(
clk
);
}
/*
* take a local timer down
*/
void
__cpuexit
twd_timer_stop
(
void
)
{
__raw_writel
(
0
,
twd_base
+
TWD_TIMER_CONTROL
);
}
arch/arm/mach-realview/Makefile
View file @
c7f7ff17
...
...
@@ -7,5 +7,6 @@ obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o
obj-$(CONFIG_MACH_REALVIEW_PB11MP)
+=
realview_pb11mp.o
obj-$(CONFIG_MACH_REALVIEW_PB1176)
+=
realview_pb1176.o
obj-$(CONFIG_MACH_REALVIEW_PBA8)
+=
realview_pba8.o
obj-$(CONFIG_SMP)
+=
platsmp.o headsmp.o
localtimer.o
obj-$(CONFIG_SMP)
+=
platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU)
+=
hotplug.o
obj-$(CONFIG_LOCAL_TIMERS)
+=
localtimer.o
arch/arm/mach-realview/core.h
View file @
c7f7ff17
...
...
@@ -51,9 +51,6 @@ extern struct mmc_platform_data realview_mmc0_plat_data;
extern
struct
mmc_platform_data
realview_mmc1_plat_data
;
extern
struct
clcd_board
clcd_plat_data
;
extern
void
__iomem
*
gic_cpu_base_addr
;
#ifdef CONFIG_LOCAL_TIMERS
extern
void
__iomem
*
twd_base
;
#endif
extern
void
__iomem
*
timer0_va_base
;
extern
void
__iomem
*
timer1_va_base
;
extern
void
__iomem
*
timer2_va_base
;
...
...
arch/arm/mach-realview/include/mach/scu.h
deleted
100644 → 0
View file @
a22f277b
#ifndef __ASMARM_ARCH_SCU_H
#define __ASMARM_ARCH_SCU_H
/*
* SCU registers
*/
#define SCU_CTRL 0x00
#define SCU_CONFIG 0x04
#define SCU_CPU_STATUS 0x08
#define SCU_INVALIDATE 0x0c
#define SCU_FPGA_REVISION 0x10
#endif
arch/arm/mach-realview/localtimer.c
View file @
c7f7ff17
...
...
@@ -9,196 +9,18 @@
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/smp.h>
#include <linux/jiffies.h>
#include <linux/percpu.h>
#include <linux/clockchips.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <asm/hardware/arm_twd.h>
#include <asm/hardware/gic.h>
#include <mach/hardware.h>
#include <asm/irq.h>
static
DEFINE_PER_CPU
(
struct
clock_event_device
,
local_clockevent
);
/*
* Used on SMP for either the local timer or IPI_TIMER
*/
void
local_timer_interrupt
(
void
)
{
struct
clock_event_device
*
clk
=
&
__get_cpu_var
(
local_clockevent
);
clk
->
event_handler
(
clk
);
}
#ifdef CONFIG_LOCAL_TIMERS
/* set up by the platform code */
void
__iomem
*
twd_base
;
static
unsigned
long
mpcore_timer_rate
;
static
void
local_timer_set_mode
(
enum
clock_event_mode
mode
,
struct
clock_event_device
*
clk
)
{
unsigned
long
ctrl
;
switch
(
mode
)
{
case
CLOCK_EVT_MODE_PERIODIC
:
/* timer load already set up */
ctrl
=
TWD_TIMER_CONTROL_ENABLE
|
TWD_TIMER_CONTROL_IT_ENABLE
|
TWD_TIMER_CONTROL_PERIODIC
;
break
;
case
CLOCK_EVT_MODE_ONESHOT
:
/* period set, and timer enabled in 'next_event' hook */
ctrl
=
TWD_TIMER_CONTROL_IT_ENABLE
|
TWD_TIMER_CONTROL_ONESHOT
;
break
;
case
CLOCK_EVT_MODE_UNUSED
:
case
CLOCK_EVT_MODE_SHUTDOWN
:
default:
ctrl
=
0
;
}
__raw_writel
(
ctrl
,
twd_base
+
TWD_TIMER_CONTROL
);
}
static
int
local_timer_set_next_event
(
unsigned
long
evt
,
struct
clock_event_device
*
unused
)
{
unsigned
long
ctrl
=
__raw_readl
(
twd_base
+
TWD_TIMER_CONTROL
);
__raw_writel
(
evt
,
twd_base
+
TWD_TIMER_COUNTER
);
__raw_writel
(
ctrl
|
TWD_TIMER_CONTROL_ENABLE
,
twd_base
+
TWD_TIMER_CONTROL
);
return
0
;
}
/*
* local_timer_ack: checks for a local timer interrupt.
*
* If a local timer interrupt has occurred, acknowledge and return 1.
* Otherwise, return 0.
*/
int
local_timer_ack
(
void
)
{
if
(
__raw_readl
(
twd_base
+
TWD_TIMER_INTSTAT
))
{
__raw_writel
(
1
,
twd_base
+
TWD_TIMER_INTSTAT
);
return
1
;
}
return
0
;
}
static
void
__cpuinit
twd_calibrate_rate
(
void
)
{
unsigned
long
load
,
count
;
u64
waitjiffies
;
/*
* If this is the first time round, we need to work out how fast
* the timer ticks
*/
if
(
mpcore_timer_rate
==
0
)
{
printk
(
"Calibrating local timer... "
);
/* Wait for a tick to start */
waitjiffies
=
get_jiffies_64
()
+
1
;
while
(
get_jiffies_64
()
<
waitjiffies
)
udelay
(
10
);
/* OK, now the tick has started, let's get the timer going */
waitjiffies
+=
5
;
/* enable, no interrupt or reload */
__raw_writel
(
0x1
,
twd_base
+
TWD_TIMER_CONTROL
);
/* maximum value */
__raw_writel
(
0xFFFFFFFFU
,
twd_base
+
TWD_TIMER_COUNTER
);
while
(
get_jiffies_64
()
<
waitjiffies
)
udelay
(
10
);
count
=
__raw_readl
(
twd_base
+
TWD_TIMER_COUNTER
);
mpcore_timer_rate
=
(
0xFFFFFFFFU
-
count
)
*
(
HZ
/
5
);
printk
(
"%lu.%02luMHz.
\n
"
,
mpcore_timer_rate
/
1000000
,
(
mpcore_timer_rate
/
100000
)
%
100
);
}
load
=
mpcore_timer_rate
/
HZ
;
__raw_writel
(
load
,
twd_base
+
TWD_TIMER_LOAD
);
}
#include <asm/smp_twd.h>
#include <asm/localtimer.h>
/*
* Setup the local clock events for a CPU.
*/
void
__cpuinit
local_timer_setup
(
void
)
{
unsigned
int
cpu
=
smp_processor_id
();
struct
clock_event_device
*
clk
=
&
per_cpu
(
local_clockevent
,
cpu
);
unsigned
long
flags
;
twd_calibrate_rate
();
clk
->
name
=
"local_timer"
;
clk
->
features
=
CLOCK_EVT_FEAT_PERIODIC
|
CLOCK_EVT_FEAT_ONESHOT
;
clk
->
rating
=
350
;
clk
->
set_mode
=
local_timer_set_mode
;
clk
->
set_next_event
=
local_timer_set_next_event
;
clk
->
irq
=
IRQ_LOCALTIMER
;
clk
->
cpumask
=
cpumask_of
(
cpu
);
clk
->
shift
=
20
;
clk
->
mult
=
div_sc
(
mpcore_timer_rate
,
NSEC_PER_SEC
,
clk
->
shift
);
clk
->
max_delta_ns
=
clockevent_delta2ns
(
0xffffffff
,
clk
);
clk
->
min_delta_ns
=
clockevent_delta2ns
(
0xf
,
clk
);
/* Make sure our local interrupt controller has this enabled */
local_irq_save
(
flags
);
get_irq_chip
(
IRQ_LOCALTIMER
)
->
unmask
(
IRQ_LOCALTIMER
);
local_irq_restore
(
flags
);
clockevents_register_device
(
clk
);
}
/*
* take a local timer down
*/
void
__cpuexit
local_timer_stop
(
void
)
void
__cpuinit
local_timer_setup
(
struct
clock_event_device
*
evt
)
{
__raw_writel
(
0
,
twd_base
+
TWD_TIMER_CONTROL
);
evt
->
irq
=
IRQ_LOCALTIMER
;
twd_timer_setup
(
evt
);
}
#else
/* CONFIG_LOCAL_TIMERS */
static
void
dummy_timer_set_mode
(
enum
clock_event_mode
mode
,
struct
clock_event_device
*
clk
)
{
}
void
__cpuinit
local_timer_setup
(
void
)
{
unsigned
int
cpu
=
smp_processor_id
();
struct
clock_event_device
*
clk
=
&
per_cpu
(
local_clockevent
,
cpu
);
clk
->
name
=
"dummy_timer"
;
clk
->
features
=
CLOCK_EVT_FEAT_ONESHOT
|
CLOCK_EVT_FEAT_PERIODIC
|
CLOCK_EVT_FEAT_DUMMY
;
clk
->
rating
=
400
;
clk
->
mult
=
1
;
clk
->
set_mode
=
dummy_timer_set_mode
;
clk
->
broadcast
=
smp_timer_broadcast
;
clk
->
cpumask
=
cpumask_of
(
cpu
);
clockevents_register_device
(
clk
);
}
#endif
/* !CONFIG_LOCAL_TIMERS */
arch/arm/mach-realview/platsmp.c
View file @
c7f7ff17
...
...
@@ -19,10 +19,11 @@
#include <asm/cacheflush.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/localtimer.h>
#include <mach/board-eb.h>
#include <mach/board-pb11mp.h>
#include <
mach/
scu.h>
#include <
asm/smp_
scu.h>
#include "core.h"
...
...
@@ -44,31 +45,12 @@ static void __iomem *scu_base_addr(void)
return
(
void
__iomem
*
)
0
;
}
static
unsigned
int
__ini
t
get_core_count
(
void
)
static
inline
unsigned
in
t
get_core_count
(
void
)
{
unsigned
int
ncores
;
void
__iomem
*
scu_base
=
scu_base_addr
();
if
(
scu_base
)
{
ncores
=
__raw_readl
(
scu_base
+
SCU_CONFIG
);
ncores
=
(
ncores
&
0x03
)
+
1
;
}
else
ncores
=
1
;
return
ncores
;
}
/*
* Setup the SCU
*/
static
void
scu_enable
(
void
)
{
u32
scu_ctrl
;
void
__iomem
*
scu_base
=
scu_base_addr
();
scu_ctrl
=
__raw_readl
(
scu_base
+
SCU_CTRL
);
scu_ctrl
|=
1
;
__raw_writel
(
scu_ctrl
,
scu_base
+
SCU_CTRL
);
if
(
scu_base
)
return
scu_get_core_count
(
scu_base
);
return
1
;
}
static
DEFINE_SPINLOCK
(
boot_lock
);
...
...
@@ -184,7 +166,7 @@ void __init smp_init_cpus(void)
unsigned
int
i
,
ncores
=
get_core_count
();
for
(
i
=
0
;
i
<
ncores
;
i
++
)
cpu_set
(
i
,
cpu_possible_map
);
set_cpu_possible
(
i
,
true
);
}
void
__init
smp_prepare_cpus
(
unsigned
int
max_cpus
)
...
...
@@ -217,19 +199,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
if
(
max_cpus
>
ncores
)
max_cpus
=
ncores
;
#if defined(CONFIG_LOCAL_TIMERS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
/*
* Enable the local timer or broadcast device for the boot CPU.
*/
local_timer_setup
();
#endif
/*
* Initialise the present map, which describes the set of CPUs
* actually populated at the present time.
*/
for
(
i
=
0
;
i
<
max_cpus
;
i
++
)
cpu_set
(
i
,
cpu_present_map
);
set_cpu_present
(
i
,
true
);
/*
* Initialise the SCU if there are more than one CPU and let
...
...
@@ -239,7 +214,13 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
* WFI
*/
if
(
max_cpus
>
1
)
{
scu_enable
();
/*
* Enable the local timer or broadcast device for the
* boot CPU, but only if we have more than one CPU.
*/
percpu_timer_setup
();
scu_enable
(
scu_base_addr
());
poke_milo
();
}
}
arch/arm/mach-realview/realview_eb.c
View file @
c7f7ff17
...
...
@@ -32,6 +32,7 @@
#include <asm/hardware/gic.h>
#include <asm/hardware/icst307.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/localtimer.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
...
...
arch/arm/mach-realview/realview_pb11mp.c
View file @
c7f7ff17
...
...
@@ -32,6 +32,7 @@
#include <asm/hardware/gic.h>
#include <asm/hardware/icst307.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/localtimer.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment