VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / arch / ia64 / kernel / cyclone.c
1 #include <linux/smp.h>
2 #include <linux/time.h>
3 #include <linux/errno.h>
4
5 /* IBM Summit (EXA) Cyclone counter code*/
6 #define CYCLONE_CBAR_ADDR 0xFEB00CD0
7 #define CYCLONE_PMCC_OFFSET 0x51A0
8 #define CYCLONE_MPMC_OFFSET 0x51D0
9 #define CYCLONE_MPCS_OFFSET 0x51A8
10 #define CYCLONE_TIMER_FREQ 100000000
11
12 int use_cyclone;
13 void __init cyclone_setup(void)
14 {
15         use_cyclone = 1;
16 }
17
18 static u32* volatile cyclone_timer;     /* Cyclone MPMC0 register */
19 static u32 last_update_cyclone;
20
21 static unsigned long offset_base;
22
23 static unsigned long get_offset_cyclone(void)
24 {
25         u32 now;
26         unsigned long offset;
27
28         /* Read the cyclone timer */
29         now = readl(cyclone_timer);
30         /* .. relative to previous update*/
31         offset = now - last_update_cyclone;
32
33         /* convert cyclone ticks to nanoseconds */
34         offset = (offset*NSEC_PER_SEC)/CYCLONE_TIMER_FREQ;
35
36         /* our adjusted time in nanoseconds */
37         return offset_base + offset;
38 }
39
40 static void update_cyclone(long delta_nsec)
41 {
42         u32 now;
43         unsigned long offset;
44
45         /* Read the cyclone timer */
46         now = readl(cyclone_timer);
47         /* .. relative to previous update*/
48         offset = now - last_update_cyclone;
49
50         /* convert cyclone ticks to nanoseconds */
51         offset = (offset*NSEC_PER_SEC)/CYCLONE_TIMER_FREQ;
52
53         offset += offset_base;
54
55         /* Be careful about signed/unsigned comparisons here: */
56         if (delta_nsec < 0 || (unsigned long) delta_nsec < offset)
57                 offset_base = offset - delta_nsec;
58         else
59                 offset_base = 0;
60
61         last_update_cyclone = now;
62 }
63
64 static void reset_cyclone(void)
65 {
66         offset_base = 0;
67         last_update_cyclone = readl(cyclone_timer);
68 }
69
70 struct time_interpolator cyclone_interpolator = {
71         .get_offset =   get_offset_cyclone,
72         .update =       update_cyclone,
73         .reset =        reset_cyclone,
74         .frequency =    CYCLONE_TIMER_FREQ,
75         .drift =        -100,
76 };
77
78 int __init init_cyclone_clock(void)
79 {
80         u64* reg;
81         u64 base;       /* saved cyclone base address */
82         u64 offset;     /* offset from pageaddr to cyclone_timer register */
83         int i;
84
85         if (!use_cyclone)
86                 return -ENODEV;
87
88         printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
89
90         /* find base address */
91         offset = (CYCLONE_CBAR_ADDR);
92         reg = (u64*)ioremap_nocache(offset, sizeof(u64));
93         if(!reg){
94                 printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
95                 use_cyclone = 0;
96                 return -ENODEV;
97         }
98         base = readq(reg);
99         if(!base){
100                 printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
101                 use_cyclone = 0;
102                 return -ENODEV;
103         }
104         iounmap(reg);
105
106         /* setup PMCC */
107         offset = (base + CYCLONE_PMCC_OFFSET);
108         reg = (u64*)ioremap_nocache(offset, sizeof(u64));
109         if(!reg){
110                 printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
111                 use_cyclone = 0;
112                 return -ENODEV;
113         }
114         writel(0x00000001,reg);
115         iounmap(reg);
116
117         /* setup MPCS */
118         offset = (base + CYCLONE_MPCS_OFFSET);
119         reg = (u64*)ioremap_nocache(offset, sizeof(u64));
120         if(!reg){
121                 printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
122                 use_cyclone = 0;
123                 return -ENODEV;
124         }
125         writel(0x00000001,reg);
126         iounmap(reg);
127
128         /* map in cyclone_timer */
129         offset = (base + CYCLONE_MPMC_OFFSET);
130         cyclone_timer = (u32*)ioremap_nocache(offset, sizeof(u32));
131         if(!cyclone_timer){
132                 printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
133                 use_cyclone = 0;
134                 return -ENODEV;
135         }
136
137         /*quick test to make sure its ticking*/
138         for(i=0; i<3; i++){
139                 u32 old = readl(cyclone_timer);
140                 int stall = 100;
141                 while(stall--) barrier();
142                 if(readl(cyclone_timer) == old){
143                         printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
144                         iounmap(cyclone_timer);
145                         cyclone_timer = 0;
146                         use_cyclone = 0;
147                         return -ENODEV;
148                 }
149         }
150         /* initialize last tick */
151         last_update_cyclone = readl(cyclone_timer);
152         register_time_interpolator(&cyclone_interpolator);
153
154         return 0;
155 }
156
157 __initcall(init_cyclone_clock);