summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorAndrew Morton <akpm@digeo.com>2002-10-29 23:31:37 -0800
committerLinus Torvalds <torvalds@penguin.transmeta.com>2002-10-29 23:31:37 -0800
commitcf228cdc908ed78c54475aa3f91b775d1f1f7da1 (patch)
treed17cc558d178b139691e7c1018b16f1b707af2c0 /kernel
parentc12e16e28b4cf576840cff509caf0c06ff4dc299 (diff)
[PATCH] percpu: convert timers
Patch from Dipankar Sarma <dipankar@in.ibm.com> This patch changes the per-CPU data in timer management (tvec_bases) to use per_cpu data area and makes it safe for cpu_possible allocation by using CPU notifiers. End result - saving space. Depends on cpu_possible patch.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/timer.c75
1 files changed, 51 insertions, 24 deletions
diff --git a/kernel/timer.c b/kernel/timer.c
index 58c80293060b..ebb2b6c627cc 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -24,6 +24,7 @@
#include <linux/percpu.h>
#include <linux/init.h>
#include <linux/mm.h>
+#include <linux/notifier.h>
#include <asm/uaccess.h>
@@ -62,7 +63,8 @@ struct tvec_t_base_s {
typedef struct tvec_t_base_s tvec_base_t;
-static tvec_base_t tvec_bases[NR_CPUS] __cacheline_aligned;
+/* Fake initialization */
+static DEFINE_PER_CPU(tvec_base_t, tvec_bases) = { SPIN_LOCK_UNLOCKED };
/* Fake initialization needed to avoid compiler breakage */
static DEFINE_PER_CPU(struct tasklet_struct, timer_tasklet) = { NULL };
@@ -122,7 +124,7 @@ static inline void internal_add_timer(tvec_base_t *base, timer_t *timer)
void add_timer(timer_t *timer)
{
int cpu = get_cpu();
- tvec_base_t *base = tvec_bases + cpu;
+ tvec_base_t *base = &per_cpu(tvec_bases, cpu);
unsigned long flags;
BUG_ON(timer_pending(timer) || !timer->function);
@@ -143,7 +145,7 @@ void add_timer(timer_t *timer)
*/
void add_timer_on(struct timer_list *timer, int cpu)
{
- tvec_base_t *base = tvec_bases+ cpu;
+ tvec_base_t *base = &per_cpu(tvec_bases, cpu);
unsigned long flags;
BUG_ON(timer_pending(timer) || !timer->function);
@@ -189,7 +191,7 @@ int mod_timer(timer_t *timer, unsigned long expires)
return 1;
local_irq_save(flags);
- new_base = tvec_bases + smp_processor_id();
+ new_base = &per_cpu(tvec_bases, smp_processor_id());
repeat:
old_base = timer->base;
@@ -285,15 +287,17 @@ repeat:
*/
int del_timer_sync(timer_t *timer)
{
- tvec_base_t *base = tvec_bases;
+ tvec_base_t *base;
int i, ret = 0;
del_again:
ret += del_timer(timer);
- for (i = 0; i < NR_CPUS; i++, base++) {
+ for (i = 0; i < NR_CPUS; i++) {
if (!cpu_online(i))
continue;
+
+ base = &per_cpu(tvec_bases, i);
if (base->running_timer == timer) {
while (base->running_timer == timer) {
cpu_relax();
@@ -731,7 +735,7 @@ unsigned long last_time_offset;
*/
static void run_timer_tasklet(unsigned long data)
{
- tvec_base_t *base = tvec_bases + smp_processor_id();
+ tvec_base_t *base = &per_cpu(tvec_bases, smp_processor_id());
if ((long)(jiffies - base->timer_jiffies) >= 0)
__run_timers(base);
@@ -1086,23 +1090,46 @@ out:
return 0;
}
-void __init init_timers(void)
+static void __devinit init_timers_cpu(int cpu)
{
- int i, j;
-
- for (i = 0; i < NR_CPUS; i++) {
- tvec_base_t *base;
-
- base = tvec_bases + i;
- spin_lock_init(&base->lock);
- for (j = 0; j < TVN_SIZE; j++) {
- INIT_LIST_HEAD(base->tv5.vec + j);
- INIT_LIST_HEAD(base->tv4.vec + j);
- INIT_LIST_HEAD(base->tv3.vec + j);
- INIT_LIST_HEAD(base->tv2.vec + j);
- }
- for (j = 0; j < TVR_SIZE; j++)
- INIT_LIST_HEAD(base->tv1.vec + j);
- tasklet_init(&per_cpu(timer_tasklet, i), run_timer_tasklet, 0);
+ int j;
+ tvec_base_t *base;
+
+ base = &per_cpu(tvec_bases, cpu);
+ spin_lock_init(&base->lock);
+ for (j = 0; j < TVN_SIZE; j++) {
+ INIT_LIST_HEAD(base->tv5.vec + j);
+ INIT_LIST_HEAD(base->tv4.vec + j);
+ INIT_LIST_HEAD(base->tv3.vec + j);
+ INIT_LIST_HEAD(base->tv2.vec + j);
+ }
+ for (j = 0; j < TVR_SIZE; j++)
+ INIT_LIST_HEAD(base->tv1.vec + j);
+ tasklet_init(&per_cpu(timer_tasklet, cpu), run_timer_tasklet, 0UL);
+}
+
+static int __devinit timer_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ long cpu = (long)hcpu;
+ switch(action) {
+ case CPU_UP_PREPARE:
+ init_timers_cpu(cpu);
+ break;
+ default:
+ break;
}
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __devinitdata timers_nb = {
+ .notifier_call = timer_cpu_notify,
+};
+
+
+void __init init_timers(void)
+{
+ timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
+ (void *)(long)smp_processor_id());
+ register_cpu_notifier(&timers_nb);
}