aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2007-02-16 04:27:33 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-16 11:13:57 -0500
commit92c7e00254b2d0efc1e36ac3e45474ce1871b6b2 (patch)
tree9314279ec92bbbe57ac79667860b49d4df6c12cd
parent26a08eb301a2e3fce5a501e3dd26cf3ec46591d7 (diff)
[PATCH] Simplify the registration of clocksources
Enqueue clocksources in rating order to make selection of the clocksource easier. Also check the match with an user override at enqueue time. Preparatory patch for the generic clocksource verification. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu> Cc: john stultz <johnstul@us.ibm.com> Cc: Roman Zippel <zippel@linux-m68k.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/i386/kernel/tsc.c3
-rw-r--r--include/linux/clocksource.h6
-rw-r--r--kernel/time/clocksource.c120
3 files changed, 62 insertions, 67 deletions
diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c
index d4000649942a..6f6971da761c 100644
--- a/arch/i386/kernel/tsc.c
+++ b/arch/i386/kernel/tsc.c
@@ -323,8 +323,7 @@ static int tsc_update_callback(void)
323 323
324 /* check to see if we should switch to the safe clocksource: */ 324 /* check to see if we should switch to the safe clocksource: */
325 if (clocksource_tsc.rating != 0 && check_tsc_unstable()) { 325 if (clocksource_tsc.rating != 0 && check_tsc_unstable()) {
326 clocksource_tsc.rating = 0; 326 clocksource_change_rating(&clocksource_tsc, 0);
327 clocksource_reselect();
328 change = 1; 327 change = 1;
329 } 328 }
330 329
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 1622d23a8dc3..55d714052374 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -178,8 +178,8 @@ static inline void clocksource_calculate_interval(struct clocksource *c,
178 178
179 179
180/* used to install a new clocksource */ 180/* used to install a new clocksource */
181int clocksource_register(struct clocksource*); 181extern int clocksource_register(struct clocksource*);
182void clocksource_reselect(void); 182extern struct clocksource* clocksource_get_next(void);
183struct clocksource* clocksource_get_next(void); 183extern void clocksource_change_rating(struct clocksource *cs, int rating);
184 184
185#endif /* _LINUX_CLOCKSOURCE_H */ 185#endif /* _LINUX_CLOCKSOURCE_H */
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index d9ef176c4e09..2f6a3d6e43bc 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -48,6 +48,7 @@ extern struct clocksource clocksource_jiffies;
48 */ 48 */
49static struct clocksource *curr_clocksource = &clocksource_jiffies; 49static struct clocksource *curr_clocksource = &clocksource_jiffies;
50static struct clocksource *next_clocksource; 50static struct clocksource *next_clocksource;
51static struct clocksource *clocksource_override;
51static LIST_HEAD(clocksource_list); 52static LIST_HEAD(clocksource_list);
52static DEFINE_SPINLOCK(clocksource_lock); 53static DEFINE_SPINLOCK(clocksource_lock);
53static char override_name[32]; 54static char override_name[32];
@@ -84,60 +85,46 @@ struct clocksource *clocksource_get_next(void)
84} 85}
85 86
86/** 87/**
87 * select_clocksource - Finds the best registered clocksource. 88 * select_clocksource - Selects the best registered clocksource.
88 * 89 *
89 * Private function. Must hold clocksource_lock when called. 90 * Private function. Must hold clocksource_lock when called.
90 * 91 *
91 * Looks through the list of registered clocksources, returning 92 * Select the clocksource with the best rating, or the clocksource,
92 * the one with the highest rating value. If there is a clocksource 93 * which is selected by userspace override.
93 * name that matches the override string, it returns that clocksource.
94 */ 94 */
95static struct clocksource *select_clocksource(void) 95static struct clocksource *select_clocksource(void)
96{ 96{
97 struct clocksource *best = NULL; 97 if (list_empty(&clocksource_list))
98 struct list_head *tmp; 98 return NULL;
99
100 list_for_each(tmp, &clocksource_list) {
101 struct clocksource *src;
102 99
103 src = list_entry(tmp, struct clocksource, list); 100 if (clocksource_override)
104 if (!best) 101 return clocksource_override;
105 best = src;
106
107 /* check for override: */
108 if (strlen(src->name) == strlen(override_name) &&
109 !strcmp(src->name, override_name)) {
110 best = src;
111 break;
112 }
113 /* pick the highest rating: */
114 if (src->rating > best->rating)
115 best = src;
116 }
117 102
118 return best; 103 return list_entry(clocksource_list.next, struct clocksource, list);
119} 104}
120 105
121/** 106/*
122 * is_registered_source - Checks if clocksource is registered 107 * Enqueue the clocksource sorted by rating
123 * @c: pointer to a clocksource
124 *
125 * Private helper function. Must hold clocksource_lock when called.
126 *
127 * Returns one if the clocksource is already registered, zero otherwise.
128 */ 108 */
129static int is_registered_source(struct clocksource *c) 109static int clocksource_enqueue(struct clocksource *c)
130{ 110{
131 int len = strlen(c->name); 111 struct list_head *tmp, *entry = &clocksource_list;
132 struct list_head *tmp;
133 112
134 list_for_each(tmp, &clocksource_list) { 113 list_for_each(tmp, &clocksource_list) {
135 struct clocksource *src; 114 struct clocksource *cs;
136 115
137 src = list_entry(tmp, struct clocksource, list); 116 cs = list_entry(tmp, struct clocksource, list);
138 if (strlen(src->name) == len && !strcmp(src->name, c->name)) 117 if (cs == c)
139 return 1; 118 return -EBUSY;
119 /* Keep track of the place, where to insert */
120 if (cs->rating >= c->rating)
121 entry = tmp;
140 } 122 }
123 list_add(&c->list, entry);
124
125 if (strlen(c->name) == strlen(override_name) &&
126 !strcmp(c->name, override_name))
127 clocksource_override = c;
141 128
142 return 0; 129 return 0;
143} 130}
@@ -150,42 +137,32 @@ static int is_registered_source(struct clocksource *c)
150 */ 137 */
151int clocksource_register(struct clocksource *c) 138int clocksource_register(struct clocksource *c)
152{ 139{
153 int ret = 0;
154 unsigned long flags; 140 unsigned long flags;
141 int ret = 0;
155 142
156 spin_lock_irqsave(&clocksource_lock, flags); 143 spin_lock_irqsave(&clocksource_lock, flags);
157 /* check if clocksource is already registered */ 144 ret = clocksource_enqueue(c);
158 if (is_registered_source(c)) { 145 if (!ret)
159 printk("register_clocksource: Cannot register %s. "
160 "Already registered!", c->name);
161 ret = -EBUSY;
162 } else {
163 /* register it */
164 list_add(&c->list, &clocksource_list);
165 /* scan the registered clocksources, and pick the best one */
166 next_clocksource = select_clocksource(); 146 next_clocksource = select_clocksource();
167 }
168 spin_unlock_irqrestore(&clocksource_lock, flags); 147 spin_unlock_irqrestore(&clocksource_lock, flags);
169 return ret; 148 return ret;
170} 149}
171EXPORT_SYMBOL(clocksource_register); 150EXPORT_SYMBOL(clocksource_register);
172 151
173/** 152/**
174 * clocksource_reselect - Rescan list for next clocksource 153 * clocksource_change_rating - Change the rating of a registered clocksource
175 * 154 *
176 * A quick helper function to be used if a clocksource changes its
177 * rating. Forces the clocksource list to be re-scanned for the best
178 * clocksource.
179 */ 155 */
180void clocksource_reselect(void) 156void clocksource_change_rating(struct clocksource *cs, int rating)
181{ 157{
182 unsigned long flags; 158 unsigned long flags;
183 159
184 spin_lock_irqsave(&clocksource_lock, flags); 160 spin_lock_irqsave(&clocksource_lock, flags);
161 list_del(&cs->list);
162 clocksource_enqueue(cs);
185 next_clocksource = select_clocksource(); 163 next_clocksource = select_clocksource();
186 spin_unlock_irqrestore(&clocksource_lock, flags); 164 spin_unlock_irqrestore(&clocksource_lock, flags);
187} 165}
188EXPORT_SYMBOL(clocksource_reselect);
189 166
190#ifdef CONFIG_SYSFS 167#ifdef CONFIG_SYSFS
191/** 168/**
@@ -221,7 +198,11 @@ sysfs_show_current_clocksources(struct sys_device *dev, char *buf)
221static ssize_t sysfs_override_clocksource(struct sys_device *dev, 198static ssize_t sysfs_override_clocksource(struct sys_device *dev,
222 const char *buf, size_t count) 199 const char *buf, size_t count)
223{ 200{
201 struct clocksource *ovr = NULL;
202 struct list_head *tmp;
224 size_t ret = count; 203 size_t ret = count;
204 int len;
205
225 /* strings from sysfs write are not 0 terminated! */ 206 /* strings from sysfs write are not 0 terminated! */
226 if (count >= sizeof(override_name)) 207 if (count >= sizeof(override_name))
227 return -EINVAL; 208 return -EINVAL;
@@ -229,17 +210,32 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev,
229 /* strip of \n: */ 210 /* strip of \n: */
230 if (buf[count-1] == '\n') 211 if (buf[count-1] == '\n')
231 count--; 212 count--;
232 if (count < 1)
233 return -EINVAL;
234 213
235 spin_lock_irq(&clocksource_lock); 214 spin_lock_irq(&clocksource_lock);
236 215
237 /* copy the name given: */ 216 if (count > 0)
238 memcpy(override_name, buf, count); 217 memcpy(override_name, buf, count);
239 override_name[count] = 0; 218 override_name[count] = 0;
240 219
241 /* try to select it: */ 220 len = strlen(override_name);
242 next_clocksource = select_clocksource(); 221 if (len) {
222 ovr = clocksource_override;
223 /* try to select it: */
224 list_for_each(tmp, &clocksource_list) {
225 struct clocksource *cs;
226
227 cs = list_entry(tmp, struct clocksource, list);
228 if (strlen(cs->name) == len &&
229 !strcmp(cs->name, override_name))
230 ovr = cs;
231 }
232 }
233
234 /* Reselect, when the override name has changed */
235 if (ovr != clocksource_override) {
236 clocksource_override = ovr;
237 next_clocksource = select_clocksource();
238 }
243 239
244 spin_unlock_irq(&clocksource_lock); 240 spin_unlock_irq(&clocksource_lock);
245 241