diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2007-02-16 04:27:33 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-16 11:13:57 -0500 |
commit | 92c7e00254b2d0efc1e36ac3e45474ce1871b6b2 (patch) | |
tree | 9314279ec92bbbe57ac79667860b49d4df6c12cd /kernel | |
parent | 26a08eb301a2e3fce5a501e3dd26cf3ec46591d7 (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>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/time/clocksource.c | 120 |
1 files changed, 58 insertions, 62 deletions
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 | */ |
49 | static struct clocksource *curr_clocksource = &clocksource_jiffies; | 49 | static struct clocksource *curr_clocksource = &clocksource_jiffies; |
50 | static struct clocksource *next_clocksource; | 50 | static struct clocksource *next_clocksource; |
51 | static struct clocksource *clocksource_override; | ||
51 | static LIST_HEAD(clocksource_list); | 52 | static LIST_HEAD(clocksource_list); |
52 | static DEFINE_SPINLOCK(clocksource_lock); | 53 | static DEFINE_SPINLOCK(clocksource_lock); |
53 | static char override_name[32]; | 54 | static 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 | */ |
95 | static struct clocksource *select_clocksource(void) | 95 | static 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 | */ |
129 | static int is_registered_source(struct clocksource *c) | 109 | static 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 | */ |
151 | int clocksource_register(struct clocksource *c) | 138 | int 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 | } |
171 | EXPORT_SYMBOL(clocksource_register); | 150 | EXPORT_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 | */ |
180 | void clocksource_reselect(void) | 156 | void 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 | } |
188 | EXPORT_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) | |||
221 | static ssize_t sysfs_override_clocksource(struct sys_device *dev, | 198 | static 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 | ||