POK(kernelpart)
timer.c
Go to the documentation of this file.
1 /*
2  * POK header
3  *
4  * The following file is a part of the POK project. Any modification should
5  * made according to the POK licence. You CANNOT use this file or a part of
6  * this file is this part of a file for your own project
7  *
8  * For more information on the POK licence, please see our LICENCE FILE
9  *
10  * Please follow the coding guidelines described in doc/CODING_GUIDELINES
11  *
12  * Copyright (c) 2007-2009 POK team
13  *
14  * Created by julien on Thu Jan 15 23:34:13 2009
15  */
16 
17 
18 #include <errno.h>
19 #include <bsp.h>
20 #include <core/time.h>
21 #include <core/sched.h>
22 
23 /* From platform. */
24 #define BUS_FREQ (100 * 1000000U)
25 
26 #define FREQ_DIV 40
27 
28 /* Last time when decr was set. */
29 static unsigned long long time_last;
30 
31 /* Decrementer optimal value. */
32 static unsigned int time_inter;
33 
34 /* Correctly get time base - handle carry. */
35 static inline unsigned long long get_ppc_tb (void)
36 {
37  unsigned int u;
38  unsigned int l;
39  unsigned int u1;
40 
41  asm ("1:\n\t"
42  "mftbu %0\n\t"
43  "mftb %1\n\t"
44  "mftbu %2\n\t"
45  "cmpw %2,%0\n\t"
46  "bne 1b\n"
47  : "=r"(u), "=r"(l), "=r"(u1));
48  return (((unsigned long long)u) << 32) | l;
49 }
50 
51 /* Compute new value for the decrementer. If the value is in the future,
52  sets the decrementer else returns an error. */
53 static int pok_arch_set_decr (void)
54 {
55  unsigned long long time_new = time_last + time_inter;
56  unsigned long long time_cur = get_ppc_tb();
57  int delta = time_new - time_cur;
58 
59  time_last = time_new;
60 
61  if (delta < 0)
62  {
63  return POK_ERRNO_EINVAL;
64  }
65  else
66  {
67  asm volatile ("mtdec %0" : : "r"(delta));
68  return POK_ERRNO_OK;
69  }
70 }
71 
72 /* Called by the interrupt handled. */
73 void pok_arch_decr_int (void)
74 {
75  int err;
76 
77  do
78  {
79  err = pok_arch_set_decr();
80 
81  pok_tick_counter += FREQ_DIV;
82  } while (err != POK_ERRNO_OK);
83 
84  pok_sched ();
85 }
86 
88 {
89  time_inter = (BUS_FREQ * FREQ_DIV) / POK_TIMER_FREQUENCY;
90  time_last = get_ppc_tb ();
91  pok_arch_set_decr();
92 
93  return (POK_ERRNO_OK);
94 }