2222#include <linux/init.h>
2323#include <linux/smp.h>
2424#include <linux/profile.h>
25+ #include <linux/clocksource.h>
2526
2627#include <asm/uaccess.h>
2728#include <asm/io.h>
@@ -172,121 +173,23 @@ unsigned long profile_pc(struct pt_regs *regs)
172173EXPORT_SYMBOL (profile_pc );
173174
174175
175- /*
176- * Return the number of micro-seconds that elapsed since the last
177- * update to wall time (aka xtime). The xtime_lock
178- * must be at least read-locked when calling this routine.
179- */
180- static inline unsigned long gettimeoffset (void )
181- {
182- #ifndef CONFIG_SMP
183- /*
184- * FIXME: This won't work on smp because jiffies are updated by cpu 0.
185- * Once parisc-linux learns the cr16 difference between processors,
186- * this could be made to work.
187- */
188- unsigned long now ;
189- unsigned long prev_tick ;
190- unsigned long next_tick ;
191- unsigned long elapsed_cycles ;
192- unsigned long usec ;
193- unsigned long cpuid = smp_processor_id ();
194- unsigned long cpt = clocktick ;
176+ /* clock source code */
195177
196- next_tick = cpu_data [cpuid ].it_value ;
197- now = mfctl (16 ); /* Read the hardware interval timer. */
198-
199- prev_tick = next_tick - cpt ;
200-
201- /* Assume Scenario 1: "now" is later than prev_tick. */
202- elapsed_cycles = now - prev_tick ;
203-
204- /* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */
205- #if HZ == 1000
206- if (elapsed_cycles > (cpt << 10 ) )
207- #elif HZ == 250
208- if (elapsed_cycles > (cpt << 8 ) )
209- #elif HZ == 100
210- if (elapsed_cycles > (cpt << 7 ) )
211- #else
212- #warn WTF is HZ set to anyway?
213- if (elapsed_cycles > (HZ * cpt ) )
214- #endif
215- {
216- /* Scenario 3: clock ticks are missing. */
217- printk (KERN_CRIT "gettimeoffset(CPU %ld): missing %ld ticks!"
218- " cycles %lX prev/now/next %lX/%lX/%lX clock %lX\n" ,
219- cpuid , elapsed_cycles / cpt ,
220- elapsed_cycles , prev_tick , now , next_tick , cpt );
221- }
222-
223- /* FIXME: Can we improve the precision? Not with PAGE0. */
224- usec = (elapsed_cycles * 10000 ) / PAGE0 -> mem_10msec ;
225- return usec ;
226- #else
227- return 0 ;
228- #endif
229- }
230-
231- void
232- do_gettimeofday (struct timeval * tv )
178+ static cycle_t read_cr16 (void )
233179{
234- unsigned long flags , seq , usec , sec ;
235-
236- /* Hold xtime_lock and adjust timeval. */
237- do {
238- seq = read_seqbegin_irqsave (& xtime_lock , flags );
239- usec = gettimeoffset ();
240- sec = xtime .tv_sec ;
241- usec += (xtime .tv_nsec / 1000 );
242- } while (read_seqretry_irqrestore (& xtime_lock , seq , flags ));
243-
244- /* Move adjusted usec's into sec's. */
245- while (usec >= USEC_PER_SEC ) {
246- usec -= USEC_PER_SEC ;
247- ++ sec ;
248- }
249-
250- /* Return adjusted result. */
251- tv -> tv_sec = sec ;
252- tv -> tv_usec = usec ;
180+ return get_cycles ();
253181}
254182
255- EXPORT_SYMBOL (do_gettimeofday );
256-
257- int
258- do_settimeofday (struct timespec * tv )
259- {
260- time_t wtm_sec , sec = tv -> tv_sec ;
261- long wtm_nsec , nsec = tv -> tv_nsec ;
262-
263- if ((unsigned long )tv -> tv_nsec >= NSEC_PER_SEC )
264- return - EINVAL ;
265-
266- write_seqlock_irq (& xtime_lock );
267- {
268- /*
269- * This is revolting. We need to set "xtime"
270- * correctly. However, the value in this location is
271- * the value at the most recent update of wall time.
272- * Discover what correction gettimeofday would have
273- * done, and then undo it!
274- */
275- nsec -= gettimeoffset () * 1000 ;
183+ static struct clocksource clocksource_cr16 = {
184+ .name = "cr16" ,
185+ .rating = 300 ,
186+ .read = read_cr16 ,
187+ .mask = CLOCKSOURCE_MASK (BITS_PER_LONG ),
188+ .mult = 0 , /* to be set */
189+ .shift = 22 ,
190+ .is_continuous = 1 ,
191+ };
276192
277- wtm_sec = wall_to_monotonic .tv_sec + (xtime .tv_sec - sec );
278- wtm_nsec = wall_to_monotonic .tv_nsec + (xtime .tv_nsec - nsec );
279-
280- set_normalized_timespec (& xtime , sec , nsec );
281- set_normalized_timespec (& wall_to_monotonic , wtm_sec , wtm_nsec );
282-
283- ntp_clear ();
284- }
285- write_sequnlock_irq (& xtime_lock );
286- clock_was_set ();
287- return 0 ;
288- }
289- EXPORT_SYMBOL (do_settimeofday );
290193
291194/*
292195 * XXX: We can do better than this.
@@ -312,11 +215,22 @@ void __init start_cpu_itimer(void)
312215void __init time_init (void )
313216{
314217 static struct pdc_tod tod_data ;
218+ unsigned long current_cr16_khz ;
315219
316220 clocktick = (100 * PAGE0 -> mem_10msec ) / HZ ;
317221
318222 start_cpu_itimer (); /* get CPU 0 started */
319223
224+ /* register at clocksource framework */
225+ current_cr16_khz = PAGE0 -> mem_10msec /10 ; /* kHz */
226+ clocksource_cr16 .mult = clocksource_khz2mult (current_cr16_khz ,
227+ clocksource_cr16 .shift );
228+ /* lower the rating if we already know its unstable: */
229+ if (num_online_cpus ()> 1 )
230+ clocksource_cr16 .rating = 200 ;
231+
232+ clocksource_register (& clocksource_cr16 );
233+
320234 if (pdc_tod_read (& tod_data ) == 0 ) {
321235 unsigned long flags ;
322236
0 commit comments