diff options
author | Graf Yang <graf.yang@analog.com> | 2008-11-18 04:48:22 -0500 |
---|---|---|
committer | Bryan Wu <cooloney@kernel.org> | 2008-11-18 04:48:22 -0500 |
commit | 8f65873e47784a390949f0d61e5692dbf2a8253e (patch) | |
tree | 4d9509bf5e52ebac190d79de04b783829d44f49e /arch/blackfin/kernel/time.c | |
parent | b8a989893cbdeb6c97a7b5af5f38fb0e480235f9 (diff) |
Blackfin arch: SMP supporting patchset: Blackfin kernel and memory management code
Blackfin dual core BF561 processor can support SMP like features.
https://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:smp-like
In this patch, we provide SMP extend to Blackfin kernel and memory management code
Singed-off-by: Graf Yang <graf.yang@analog.com>
Signed-off-by: Mike Frysinger <vapier.adi@gmail.com>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
Diffstat (limited to 'arch/blackfin/kernel/time.c')
-rw-r--r-- | arch/blackfin/kernel/time.c | 114 |
1 files changed, 79 insertions, 35 deletions
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c index eb2352320454..06de2ce67a9e 100644 --- a/arch/blackfin/kernel/time.c +++ b/arch/blackfin/kernel/time.c | |||
@@ -34,9 +34,11 @@ | |||
34 | #include <linux/interrupt.h> | 34 | #include <linux/interrupt.h> |
35 | #include <linux/time.h> | 35 | #include <linux/time.h> |
36 | #include <linux/irq.h> | 36 | #include <linux/irq.h> |
37 | #include <linux/delay.h> | ||
37 | 38 | ||
38 | #include <asm/blackfin.h> | 39 | #include <asm/blackfin.h> |
39 | #include <asm/time.h> | 40 | #include <asm/time.h> |
41 | #include <asm/gptimers.h> | ||
40 | 42 | ||
41 | /* This is an NTP setting */ | 43 | /* This is an NTP setting */ |
42 | #define TICK_SIZE (tick_nsec / 1000) | 44 | #define TICK_SIZE (tick_nsec / 1000) |
@@ -46,11 +48,14 @@ static unsigned long gettimeoffset(void); | |||
46 | 48 | ||
47 | static struct irqaction bfin_timer_irq = { | 49 | static struct irqaction bfin_timer_irq = { |
48 | .name = "BFIN Timer Tick", | 50 | .name = "BFIN Timer Tick", |
51 | #ifdef CONFIG_IRQ_PER_CPU | ||
52 | .flags = IRQF_DISABLED | IRQF_PERCPU, | ||
53 | #else | ||
49 | .flags = IRQF_DISABLED | 54 | .flags = IRQF_DISABLED |
55 | #endif | ||
50 | }; | 56 | }; |
51 | 57 | ||
52 | static void | 58 | void setup_core_timer(void) |
53 | time_sched_init(irq_handler_t timer_routine) | ||
54 | { | 59 | { |
55 | u32 tcount; | 60 | u32 tcount; |
56 | 61 | ||
@@ -71,12 +76,41 @@ time_sched_init(irq_handler_t timer_routine) | |||
71 | CSYNC(); | 76 | CSYNC(); |
72 | 77 | ||
73 | bfin_write_TCNTL(7); | 78 | bfin_write_TCNTL(7); |
79 | } | ||
80 | |||
81 | #ifdef CONFIG_TICK_SOURCE_SYSTMR0 | ||
82 | void setup_system_timer0(void) | ||
83 | { | ||
84 | /* Power down the core timer, just to play safe. */ | ||
85 | bfin_write_TCNTL(0); | ||
86 | |||
87 | disable_gptimers(TIMER0bit); | ||
88 | set_gptimer_status(0, TIMER_STATUS_TRUN0); | ||
89 | while (get_gptimer_status(0) & TIMER_STATUS_TRUN0) | ||
90 | udelay(10); | ||
91 | |||
92 | set_gptimer_config(0, 0x59); /* IRQ enable, periodic, PWM_OUT, SCLKed, OUT PAD disabled */ | ||
93 | set_gptimer_period(TIMER0_id, get_sclk() / HZ); | ||
94 | set_gptimer_pwidth(TIMER0_id, 1); | ||
95 | SSYNC(); | ||
96 | enable_gptimers(TIMER0bit); | ||
97 | } | ||
98 | #endif | ||
74 | 99 | ||
100 | static void | ||
101 | time_sched_init(irqreturn_t(*timer_routine) (int, void *)) | ||
102 | { | ||
103 | #ifdef CONFIG_TICK_SOURCE_SYSTMR0 | ||
104 | setup_system_timer0(); | ||
105 | #else | ||
106 | setup_core_timer(); | ||
107 | #endif | ||
75 | bfin_timer_irq.handler = (irq_handler_t)timer_routine; | 108 | bfin_timer_irq.handler = (irq_handler_t)timer_routine; |
76 | /* call setup_irq instead of request_irq because request_irq calls | 109 | #ifdef CONFIG_TICK_SOURCE_SYSTMR0 |
77 | * kmalloc which has not been initialized yet | 110 | setup_irq(IRQ_TIMER0, &bfin_timer_irq); |
78 | */ | 111 | #else |
79 | setup_irq(IRQ_CORETMR, &bfin_timer_irq); | 112 | setup_irq(IRQ_CORETMR, &bfin_timer_irq); |
113 | #endif | ||
80 | } | 114 | } |
81 | 115 | ||
82 | /* | 116 | /* |
@@ -87,17 +121,23 @@ static unsigned long gettimeoffset(void) | |||
87 | unsigned long offset; | 121 | unsigned long offset; |
88 | unsigned long clocks_per_jiffy; | 122 | unsigned long clocks_per_jiffy; |
89 | 123 | ||
124 | #ifdef CONFIG_TICK_SOURCE_SYSTMR0 | ||
125 | clocks_per_jiffy = bfin_read_TIMER0_PERIOD(); | ||
126 | offset = bfin_read_TIMER0_COUNTER() / \ | ||
127 | (((clocks_per_jiffy + 1) * HZ) / USEC_PER_SEC); | ||
128 | |||
129 | if ((get_gptimer_status(0) & TIMER_STATUS_TIMIL0) && offset < (100000 / HZ / 2)) | ||
130 | offset += (USEC_PER_SEC / HZ); | ||
131 | #else | ||
90 | clocks_per_jiffy = bfin_read_TPERIOD(); | 132 | clocks_per_jiffy = bfin_read_TPERIOD(); |
91 | offset = | 133 | offset = (clocks_per_jiffy - bfin_read_TCOUNT()) / \ |
92 | (clocks_per_jiffy - | 134 | (((clocks_per_jiffy + 1) * HZ) / USEC_PER_SEC); |
93 | bfin_read_TCOUNT()) / (((clocks_per_jiffy + 1) * HZ) / | ||
94 | USEC_PER_SEC); | ||
95 | 135 | ||
96 | /* Check if we just wrapped the counters and maybe missed a tick */ | 136 | /* Check if we just wrapped the counters and maybe missed a tick */ |
97 | if ((bfin_read_ILAT() & (1 << IRQ_CORETMR)) | 137 | if ((bfin_read_ILAT() & (1 << IRQ_CORETMR)) |
98 | && (offset < (100000 / HZ / 2))) | 138 | && (offset < (100000 / HZ / 2))) |
99 | offset += (USEC_PER_SEC / HZ); | 139 | offset += (USEC_PER_SEC / HZ); |
100 | 140 | #endif | |
101 | return offset; | 141 | return offset; |
102 | } | 142 | } |
103 | 143 | ||
@@ -120,34 +160,38 @@ irqreturn_t timer_interrupt(int irq, void *dummy) | |||
120 | static long last_rtc_update; | 160 | static long last_rtc_update; |
121 | 161 | ||
122 | write_seqlock(&xtime_lock); | 162 | write_seqlock(&xtime_lock); |
123 | 163 | #ifdef CONFIG_TICK_SOURCE_SYSTMR0 | |
124 | do_timer(1); | 164 | if (get_gptimer_status(0) & TIMER_STATUS_TIMIL0) { |
125 | 165 | #endif | |
126 | profile_tick(CPU_PROFILING); | 166 | do_timer(1); |
127 | 167 | ||
128 | /* | 168 | |
129 | * If we have an externally synchronized Linux clock, then update | 169 | /* |
130 | * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be | 170 | * If we have an externally synchronized Linux clock, then update |
131 | * called as close as possible to 500 ms before the new second starts. | 171 | * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be |
132 | */ | 172 | * called as close as possible to 500 ms before the new second starts. |
133 | 173 | */ | |
134 | if (ntp_synced() && | 174 | |
135 | xtime.tv_sec > last_rtc_update + 660 && | 175 | if (ntp_synced() && |
136 | (xtime.tv_nsec / NSEC_PER_USEC) >= | 176 | xtime.tv_sec > last_rtc_update + 660 && |
137 | 500000 - ((unsigned)TICK_SIZE) / 2 | 177 | (xtime.tv_nsec / NSEC_PER_USEC) >= |
138 | && (xtime.tv_nsec / NSEC_PER_USEC) <= | 178 | 500000 - ((unsigned)TICK_SIZE) / 2 |
139 | 500000 + ((unsigned)TICK_SIZE) / 2) { | 179 | && (xtime.tv_nsec / NSEC_PER_USEC) <= |
140 | if (set_rtc_mmss(xtime.tv_sec) == 0) | 180 | 500000 + ((unsigned)TICK_SIZE) / 2) { |
141 | last_rtc_update = xtime.tv_sec; | 181 | if (set_rtc_mmss(xtime.tv_sec) == 0) |
142 | else | 182 | last_rtc_update = xtime.tv_sec; |
143 | /* Do it again in 60s. */ | 183 | else |
144 | last_rtc_update = xtime.tv_sec - 600; | 184 | /* Do it again in 60s. */ |
185 | last_rtc_update = xtime.tv_sec - 600; | ||
186 | } | ||
187 | #ifdef CONFIG_TICK_SOURCE_SYSTMR0 | ||
188 | set_gptimer_status(0, TIMER_STATUS_TIMIL0); | ||
145 | } | 189 | } |
190 | #endif | ||
146 | write_sequnlock(&xtime_lock); | 191 | write_sequnlock(&xtime_lock); |
147 | 192 | ||
148 | #ifndef CONFIG_SMP | ||
149 | update_process_times(user_mode(get_irq_regs())); | 193 | update_process_times(user_mode(get_irq_regs())); |
150 | #endif | 194 | profile_tick(CPU_PROFILING); |
151 | 195 | ||
152 | return IRQ_HANDLED; | 196 | return IRQ_HANDLED; |
153 | } | 197 | } |