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
91a2fcc8
Commit
91a2fcc8
authored
Oct 11, 2007
by
Ralf Baechle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[MIPS] Consolidate all variants of MIPS cp0 timer interrupt handlers.
Signed-off-by:
Ralf Baechle
<
ralf@linux-mips.org
>
parent
90b02340
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
88 additions
and
292 deletions
+88
-292
arch/mips/au1000/common/irq.c
arch/mips/au1000/common/irq.c
+1
-3
arch/mips/au1000/common/time.c
arch/mips/au1000/common/time.c
+0
-40
arch/mips/kernel/smtc.c
arch/mips/kernel/smtc.c
+1
-1
arch/mips/kernel/time.c
arch/mips/kernel/time.c
+69
-24
arch/mips/mips-boards/generic/time.c
arch/mips/mips-boards/generic/time.c
+5
-107
arch/mips/mipssim/sim_time.c
arch/mips/mipssim/sim_time.c
+0
-72
arch/mips/sgi-ip22/ip22-int.c
arch/mips/sgi-ip22/ip22-int.c
+2
-3
arch/mips/sgi-ip22/ip22-time.c
arch/mips/sgi-ip22/ip22-time.c
+0
-10
arch/mips/sibyte/bcm1480/time.c
arch/mips/sibyte/bcm1480/time.c
+1
-12
arch/mips/sibyte/sb1250/time.c
arch/mips/sibyte/sb1250/time.c
+1
-12
include/asm-mips/time.h
include/asm-mips/time.h
+8
-8
No files found.
arch/mips/au1000/common/irq.c
View file @
91a2fcc8
...
...
@@ -65,8 +65,6 @@
#define EXT_INTC1_REQ1 5
/* IP 5 */
#define MIPS_TIMER_IP 7
/* IP 7 */
extern
void
mips_timer_interrupt
(
void
);
void
(
*
board_init_irq
)(
void
);
static
DEFINE_SPINLOCK
(
irq_lock
);
...
...
@@ -635,7 +633,7 @@ asmlinkage void plat_irq_dispatch(void)
unsigned
int
pending
=
read_c0_status
()
&
read_c0_cause
()
&
ST0_IM
;
if
(
pending
&
CAUSEF_IP7
)
mips_timer_interrupt
(
);
ll_timer_interrupt
(
63
);
else
if
(
pending
&
CAUSEF_IP2
)
intc0_req0_irqdispatch
();
else
if
(
pending
&
CAUSEF_IP3
)
...
...
arch/mips/au1000/common/time.c
View file @
91a2fcc8
...
...
@@ -64,48 +64,8 @@ static unsigned long last_pc0, last_match20;
static
DEFINE_SPINLOCK
(
time_lock
);
static
inline
void
ack_r4ktimer
(
unsigned
long
newval
)
{
write_c0_compare
(
newval
);
}
/*
* There are a lot of conceptually broken versions of the MIPS timer interrupt
* handler floating around. This one is rather different, but the algorithm
* is provably more robust.
*/
unsigned
long
wtimer
;
void
mips_timer_interrupt
(
void
)
{
int
irq
=
63
;
irq_enter
();
kstat_this_cpu
.
irqs
[
irq
]
++
;
if
(
r4k_offset
==
0
)
goto
null
;
do
{
kstat_this_cpu
.
irqs
[
irq
]
++
;
do_timer
(
1
);
#ifndef CONFIG_SMP
update_process_times
(
user_mode
(
get_irq_regs
()));
#endif
r4k_cur
+=
r4k_offset
;
ack_r4ktimer
(
r4k_cur
);
}
while
(((
unsigned
long
)
read_c0_count
()
-
r4k_cur
)
<
0x7fffffff
);
irq_exit
();
return
;
null:
ack_r4ktimer
(
0
);
irq_exit
();
}
#ifdef CONFIG_PM
irqreturn_t
counter0_irq
(
int
irq
,
void
*
dev_id
)
{
...
...
arch/mips/kernel/smtc.c
View file @
91a2fcc8
...
...
@@ -867,7 +867,7 @@ void ipi_decode(struct smtc_ipi *pipi)
#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG
clock_hang_reported
[
dest_copy
]
=
0
;
#endif
/* CONFIG_SMTC_IDLE_HOOK_DEBUG */
local_timer_interrupt
(
0
,
NULL
);
local_timer_interrupt
(
0
);
irq_exit
();
break
;
case
LINUX_SMP_IPI
:
...
...
arch/mips/kernel/time.c
View file @
91a2fcc8
...
...
@@ -144,7 +144,7 @@ void local_timer_interrupt(int irq, void *dev_id)
* High-level timer interrupt service routines. This function
* is set as irqaction->handler and is invoked through do_IRQ.
*/
irqreturn_t
timer_interrupt
(
int
irq
,
void
*
dev_id
)
static
irqreturn_t
timer_interrupt
(
int
irq
,
void
*
dev_id
)
{
write_seqlock
(
&
xtime_lock
);
...
...
@@ -174,9 +174,10 @@ int null_perf_irq(void)
return
0
;
}
EXPORT_SYMBOL
(
null_perf_irq
);
int
(
*
perf_irq
)(
void
)
=
null_perf_irq
;
EXPORT_SYMBOL
(
null_perf_irq
);
EXPORT_SYMBOL
(
perf_irq
);
/*
...
...
@@ -208,35 +209,79 @@ static inline int handle_perf_irq (int r2)
!
r2
;
}
asmlinkage
void
ll_timer_interrupt
(
int
irq
)
void
ll_timer_interrupt
(
int
irq
,
void
*
dev_id
)
{
int
r2
=
cpu_has_mips_r2
;
int
cpu
=
smp_processor_id
()
;
irq_enter
();
kstat_this_cpu
.
irqs
[
irq
]
++
;
#ifdef CONFIG_MIPS_MT_SMTC
/*
* In an SMTC system, one Count/Compare set exists per VPE.
* Which TC within a VPE gets the interrupt is essentially
* random - we only know that it shouldn't be one with
* IXMT set. Whichever TC gets the interrupt needs to
* send special interprocessor interrupts to the other
* TCs to make sure that they schedule, etc.
*
* That code is specific to the SMTC kernel, not to
* the a particular platform, so it's invoked from
* the general MIPS timer_interrupt routine.
*/
/*
* We could be here due to timer interrupt,
* perf counter overflow, or both.
*/
(
void
)
handle_perf_irq
(
1
);
if
(
read_c0_cause
()
&
(
1
<<
30
))
{
/*
* There are things we only want to do once per tick
* in an "MP" system. One TC of each VPE will take
* the actual timer interrupt. The others will get
* timer broadcast IPIs. We use whoever it is that takes
* the tick on VPE 0 to run the full timer_interrupt().
*/
if
(
cpu_data
[
cpu
].
vpe_id
==
0
)
{
timer_interrupt
(
irq
,
NULL
);
}
else
{
write_c0_compare
(
read_c0_count
()
+
(
mips_hpt_frequency
/
HZ
));
local_timer_interrupt
(
irq
,
dev_id
);
}
smtc_timer_broadcast
(
cpu_data
[
cpu
].
vpe_id
);
}
#else
/* CONFIG_MIPS_MT_SMTC */
int
r2
=
cpu_has_mips_r2
;
if
(
handle_perf_irq
(
r2
))
goto
out
;
return
;
if
(
r2
&&
((
read_c0_cause
()
&
(
1
<<
30
))
==
0
))
goto
out
;
timer_interrupt
(
irq
,
NULL
);
out:
irq_exit
();
}
asmlinkage
void
ll_local_timer_interrupt
(
int
irq
)
{
irq_enter
();
if
(
smp_processor_id
()
!=
0
)
kstat_this_cpu
.
irqs
[
irq
]
++
;
/* we keep interrupt disabled all the time */
local_timer_interrupt
(
irq
,
NULL
);
return
;
irq_exit
();
if
(
cpu
==
0
)
{
/*
* CPU 0 handles the global timer interrupt job and process
* accounting resets count/compare registers to trigger next
* timer int.
*/
timer_interrupt
(
irq
,
NULL
);
}
else
{
/* Everyone else needs to reset the timer int here as
ll_local_timer_interrupt doesn't */
/*
* FIXME: need to cope with counter underflow.
* More support needs to be added to kernel/time for
* counter/timer interrupts on multiple CPU's
*/
write_c0_compare
(
read_c0_count
()
+
(
mips_hpt_frequency
/
HZ
));
/*
* Other CPUs should do profiling and process accounting
*/
local_timer_interrupt
(
irq
,
dev_id
);
}
#endif
/* CONFIG_MIPS_MT_SMTC */
}
/*
...
...
arch/mips/mips-boards/generic/time.c
View file @
91a2fcc8
...
...
@@ -67,108 +67,6 @@ static void mips_perf_dispatch(void)
do_IRQ
(
cp0_perfcount_irq
);
}
/*
* Redeclare until I get around mopping the timer code insanity on MIPS.
*/
extern
int
null_perf_irq
(
void
);
extern
int
(
*
perf_irq
)(
void
);
/*
* Possibly handle a performance counter interrupt.
* Return true if the timer interrupt should not be checked
*/
static
inline
int
handle_perf_irq
(
int
r2
)
{
/*
* The performance counter overflow interrupt may be shared with the
* timer interrupt (cp0_perfcount_irq < 0). If it is and a
* performance counter has overflowed (perf_irq() == IRQ_HANDLED)
* and we can't reliably determine if a counter interrupt has also
* happened (!r2) then don't check for a timer interrupt.
*/
return
(
cp0_perfcount_irq
<
0
)
&&
perf_irq
()
==
IRQ_HANDLED
&&
!
r2
;
}
irqreturn_t
mips_timer_interrupt
(
int
irq
,
void
*
dev_id
)
{
int
cpu
=
smp_processor_id
();
#ifdef CONFIG_MIPS_MT_SMTC
/*
* In an SMTC system, one Count/Compare set exists per VPE.
* Which TC within a VPE gets the interrupt is essentially
* random - we only know that it shouldn't be one with
* IXMT set. Whichever TC gets the interrupt needs to
* send special interprocessor interrupts to the other
* TCs to make sure that they schedule, etc.
*
* That code is specific to the SMTC kernel, not to
* the a particular platform, so it's invoked from
* the general MIPS timer_interrupt routine.
*/
/*
* We could be here due to timer interrupt,
* perf counter overflow, or both.
*/
(
void
)
handle_perf_irq
(
1
);
if
(
read_c0_cause
()
&
(
1
<<
30
))
{
/*
* There are things we only want to do once per tick
* in an "MP" system. One TC of each VPE will take
* the actual timer interrupt. The others will get
* timer broadcast IPIs. We use whoever it is that takes
* the tick on VPE 0 to run the full timer_interrupt().
*/
if
(
cpu_data
[
cpu
].
vpe_id
==
0
)
{
timer_interrupt
(
irq
,
NULL
);
}
else
{
write_c0_compare
(
read_c0_count
()
+
(
mips_hpt_frequency
/
HZ
));
local_timer_interrupt
(
irq
,
dev_id
);
}
smtc_timer_broadcast
();
}
#else
/* CONFIG_MIPS_MT_SMTC */
int
r2
=
cpu_has_mips_r2
;
if
(
handle_perf_irq
(
r2
))
goto
out
;
if
(
r2
&&
((
read_c0_cause
()
&
(
1
<<
30
))
==
0
))
goto
out
;
if
(
cpu
==
0
)
{
/*
* CPU 0 handles the global timer interrupt job and process
* accounting resets count/compare registers to trigger next
* timer int.
*/
timer_interrupt
(
irq
,
NULL
);
}
else
{
/* Everyone else needs to reset the timer int here as
ll_local_timer_interrupt doesn't */
/*
* FIXME: need to cope with counter underflow.
* More support needs to be added to kernel/time for
* counter/timer interrupts on multiple CPU's
*/
write_c0_compare
(
read_c0_count
()
+
(
mips_hpt_frequency
/
HZ
));
/*
* Other CPUs should do profiling and process accounting
*/
local_timer_interrupt
(
irq
,
dev_id
);
}
out:
#endif
/* CONFIG_MIPS_MT_SMTC */
return
IRQ_HANDLED
;
}
/*
* Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect
*/
...
...
@@ -246,7 +144,7 @@ void __init plat_time_init(void)
mips_scroll_message
();
}
irqreturn_t
mips_perf_interrupt
(
int
irq
,
void
*
dev_id
)
static
irqreturn_t
mips_perf_interrupt
(
int
irq
,
void
*
dev_id
)
{
return
perf_irq
();
}
...
...
@@ -257,8 +155,10 @@ static struct irqaction perf_irqaction = {
.
name
=
"performance"
,
};
void
__init
plat_perf_setup
(
struct
irqaction
*
irq
)
void
__init
plat_perf_setup
(
void
)
{
struct
irqaction
*
irq
=
&
perf_irqaction
;
cp0_perfcount_irq
=
-
1
;
#ifdef MSC01E_INT_BASE
...
...
@@ -297,8 +197,6 @@ void __init plat_timer_setup(struct irqaction *irq)
mips_cpu_timer_irq
=
MIPS_CPU_IRQ_BASE
+
cp0_compare_irq
;
}
/* we are using the cpu counter for timer interrupts */
irq
->
handler
=
mips_timer_interrupt
;
/* we use our own handler */
#ifdef CONFIG_MIPS_MT_SMTC
setup_irq_smtc
(
mips_cpu_timer_irq
,
irq
,
0x100
<<
cp0_compare_irq
);
#else
...
...
@@ -308,5 +206,5 @@ void __init plat_timer_setup(struct irqaction *irq)
set_irq_handler
(
mips_cpu_timer_irq
,
handle_percpu_irq
);
#endif
plat_perf_setup
(
&
perf_irqaction
);
plat_perf_setup
();
}
arch/mips/mipssim/sim_time.c
View file @
91a2fcc8
...
...
@@ -23,77 +23,6 @@
unsigned
long
cpu_khz
;
irqreturn_t
sim_timer_interrupt
(
int
irq
,
void
*
dev_id
)
{
#ifdef CONFIG_SMP
int
cpu
=
smp_processor_id
();
/*
* CPU 0 handles the global timer interrupt job
* resets count/compare registers to trigger next timer int.
*/
#ifndef CONFIG_MIPS_MT_SMTC
if
(
cpu
==
0
)
{
timer_interrupt
(
irq
,
dev_id
);
}
else
{
/* Everyone else needs to reset the timer int here as
ll_local_timer_interrupt doesn't */
/*
* FIXME: need to cope with counter underflow.
* More support needs to be added to kernel/time for
* counter/timer interrupts on multiple CPU's
*/
write_c0_compare
(
read_c0_count
()
+
(
mips_hpt_frequency
/
HZ
));
}
#else
/* SMTC */
/*
* In SMTC system, one Count/Compare set exists per VPE.
* Which TC within a VPE gets the interrupt is essentially
* random - we only know that it shouldn't be one with
* IXMT set. Whichever TC gets the interrupt needs to
* send special interprocessor interrupts to the other
* TCs to make sure that they schedule, etc.
*
* That code is specific to the SMTC kernel, not to
* the simulation platform, so it's invoked from
* the general MIPS timer_interrupt routine.
*
* We have a problem in that the interrupt vector code
* had to turn off the timer IM bit to avoid redundant
* entries, but we may never get to mips_cpu_irq_end
* to turn it back on again if the scheduler gets
* involved. So we clear the pending timer here,
* and re-enable the mask...
*/
int
vpflags
=
dvpe
();
write_c0_compare
(
read_c0_count
()
-
1
);
clear_c0_cause
(
0x100
<<
cp0_compare_irq
);
set_c0_status
(
0x100
<<
cp0_compare_irq
);
irq_enable_hazard
();
evpe
(
vpflags
);
if
(
cpu_data
[
cpu
].
vpe_id
==
0
)
timer_interrupt
(
irq
,
dev_id
);
else
write_c0_compare
(
read_c0_count
()
+
(
mips_hpt_frequency
/
HZ
));
smtc_timer_broadcast
(
cpu_data
[
cpu
].
vpe_id
);
#endif
/* CONFIG_MIPS_MT_SMTC */
/*
* every CPU should do profiling and process accounting
*/
local_timer_interrupt
(
irq
,
dev_id
);
return
IRQ_HANDLED
;
#else
return
timer_interrupt
(
irq
,
dev_id
);
#endif
}
/*
* Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect
*/
...
...
@@ -185,7 +114,6 @@ void __init plat_timer_setup(struct irqaction *irq)
}
/* we are using the cpu counter for timer interrupts */
irq
->
handler
=
sim_timer_interrupt
;
setup_irq
(
mips_cpu_timer_irq
,
irq
);
#ifdef CONFIG_SMP
...
...
arch/mips/sgi-ip22/ip22-int.c
View file @
91a2fcc8
...
...
@@ -20,10 +20,10 @@
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/irq_cpu.h>
#include <asm/sgi/ioc.h>
#include <asm/sgi/hpc3.h>
#include <asm/sgi/ip22.h>
#include <asm/time.h>
/* #define DEBUG_SGINT */
...
...
@@ -204,7 +204,6 @@ static struct irqaction map1_cascade = {
#define SGI_INTERRUPTS SGINT_LOCAL3
#endif
extern
void
indy_r4k_timer_interrupt
(
void
);
extern
void
indy_8254timer_irq
(
void
);
/*
...
...
@@ -243,7 +242,7 @@ asmlinkage void plat_irq_dispatch(void)
* First we check for r4k counter/timer IRQ.
*/
if
(
pending
&
CAUSEF_IP7
)
indy_r4k_timer_interrupt
(
);
ll_timer_interrupt
(
SGI_TIMER_IRQ
,
NULL
);
else
if
(
pending
&
CAUSEF_IP2
)
indy_local0_irqdispatch
();
else
if
(
pending
&
CAUSEF_IP3
)
...
...
arch/mips/sgi-ip22/ip22-time.c
View file @
91a2fcc8
...
...
@@ -189,16 +189,6 @@ void indy_8254timer_irq(void)
irq_exit
();
}
void
indy_r4k_timer_interrupt
(
void
)
{
int
irq
=
SGI_TIMER_IRQ
;
irq_enter
();
kstat_this_cpu
.
irqs
[
irq
]
++
;
timer_interrupt
(
irq
,
NULL
);
irq_exit
();
}
void
__init
plat_timer_setup
(
struct
irqaction
*
irq
)
{
/* over-write the handler, we use our own way */
...
...
arch/mips/sibyte/bcm1480/time.c
View file @
91a2fcc8
...
...
@@ -103,18 +103,7 @@ void bcm1480_timer_interrupt(void)
__raw_writeq
(
M_SCD_TIMER_ENABLE
|
M_SCD_TIMER_MODE_CONTINUOUS
,
IOADDR
(
A_SCD_TIMER_REGISTER
(
cpu
,
R_SCD_TIMER_CFG
)));
if
(
cpu
==
0
)
{
/*
* CPU 0 handles the global timer interrupt job
*/
ll_timer_interrupt
(
irq
);
}
else
{
/*
* other CPUs should just do profiling and process accounting
*/
ll_local_timer_interrupt
(
irq
);
}
ll_timer_interrupt
(
irq
);
}
static
cycle_t
bcm1480_hpt_read
(
void
)
...
...
arch/mips/sibyte/sb1250/time.c
View file @
91a2fcc8
...
...
@@ -125,18 +125,7 @@ void sb1250_timer_interrupt(void)
____raw_writeq
(
M_SCD_TIMER_ENABLE
|
M_SCD_TIMER_MODE_CONTINUOUS
,
IOADDR
(
A_SCD_TIMER_REGISTER
(
cpu
,
R_SCD_TIMER_CFG
)));
if
(
cpu
==
0
)
{
/*
* CPU 0 handles the global timer interrupt job
*/
ll_timer_interrupt
(
irq
);
}
else
{
/*
* other CPUs should just do profiling and process accounting
*/
ll_local_timer_interrupt
(
irq
);
}
ll_timer_interrupt
(
irq
);
}
/*
...
...
include/asm-mips/time.h
View file @
91a2fcc8
...
...
@@ -49,20 +49,14 @@ extern void (*mips_timer_ack)(void);
extern
struct
clocksource
clocksource_mips
;
/*
*
high-level timer interrupt routines
.
*
The low-level timer interrupt routine
.
*/
extern
irqreturn_t
timer_interrupt
(
int
irq
,
void
*
dev_id
);
/*
* the corresponding low-level timer interrupt routine.
*/
extern
asmlinkage
void
ll_timer_interrupt
(
int
irq
);
extern
void
ll_timer_interrupt
(
int
irq
,
void
*
dev_id
);
/*
* profiling and process accouting is done separately in local_timer_interrupt
*/
extern
void
local_timer_interrupt
(
int
irq
,
void
*
dev_id
);
extern
asmlinkage
void
ll_local_timer_interrupt
(
int
irq
);
/*
* board specific routines required by time_init().
...
...
@@ -78,4 +72,10 @@ extern void plat_timer_setup(struct irqaction *irq);
*/
extern
unsigned
int
mips_hpt_frequency
;
/*
* The performance counter IRQ on MIPS is a close relative to the timer IRQ
* so it lives here.
*/
extern
int
(
*
perf_irq
)(
void
);
#endif
/* _ASM_TIME_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