diff options
author | Arjan van de Ven <arjan@linux.intel.com> | 2012-01-30 23:23:30 -0500 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2012-02-01 21:39:46 -0500 |
commit | b519508298e0292e1771eecf14aaf67755adc39d (patch) | |
tree | 31fd0675057bb14e3dcff26d585fd512614b181b /drivers/clocksource | |
parent | 12d6d41276def096cb3f7dc36f438db9ed6a0a8d (diff) |
clocksource: Load the ACPI PM clocksource asynchronously
The ACPI clocksource takes quite some time to initialize,
and this increases the boot time of the kernel for a
double digit percentage. This while almost all modern
systems will be using the HPET already anyway.
This patch turns the clocksource loading into an asynchronous
operation; which means it won't hold up the boot while
still becoming available normally.
To make this work well, an udelay() had to be turned into an
usleep_range() so that on UP systems, we yield the CPU to
regular boot tasks instead of spinning.
CC: John Stultz <johnstul@us.ibm.com>
CC: Thomas Gleixner <tglx@linutronix.de>
CC: Len Brown <lenb@kernel.org>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'drivers/clocksource')
-rw-r--r-- | drivers/clocksource/acpi_pm.c | 24 |
1 files changed, 16 insertions, 8 deletions
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 6b5cf02c35c8..82e882028fcf 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
26 | #include <linux/async.h> | ||
26 | #include <asm/io.h> | 27 | #include <asm/io.h> |
27 | 28 | ||
28 | /* | 29 | /* |
@@ -179,17 +180,15 @@ static int verify_pmtmr_rate(void) | |||
179 | /* Number of reads we try to get two different values */ | 180 | /* Number of reads we try to get two different values */ |
180 | #define ACPI_PM_READ_CHECKS 10000 | 181 | #define ACPI_PM_READ_CHECKS 10000 |
181 | 182 | ||
182 | static int __init init_acpi_pm_clocksource(void) | 183 | static void __init acpi_pm_clocksource_async(void *unused, async_cookie_t cookie) |
183 | { | 184 | { |
184 | cycle_t value1, value2; | 185 | cycle_t value1, value2; |
185 | unsigned int i, j = 0; | 186 | unsigned int i, j = 0; |
186 | 187 | ||
187 | if (!pmtmr_ioport) | ||
188 | return -ENODEV; | ||
189 | 188 | ||
190 | /* "verify" this timing source: */ | 189 | /* "verify" this timing source: */ |
191 | for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) { | 190 | for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) { |
192 | udelay(100 * j); | 191 | usleep_range(100 * j, 100 * j + 100); |
193 | value1 = clocksource_acpi_pm.read(&clocksource_acpi_pm); | 192 | value1 = clocksource_acpi_pm.read(&clocksource_acpi_pm); |
194 | for (i = 0; i < ACPI_PM_READ_CHECKS; i++) { | 193 | for (i = 0; i < ACPI_PM_READ_CHECKS; i++) { |
195 | value2 = clocksource_acpi_pm.read(&clocksource_acpi_pm); | 194 | value2 = clocksource_acpi_pm.read(&clocksource_acpi_pm); |
@@ -203,25 +202,34 @@ static int __init init_acpi_pm_clocksource(void) | |||
203 | " 0x%#llx, 0x%#llx - aborting.\n", | 202 | " 0x%#llx, 0x%#llx - aborting.\n", |
204 | value1, value2); | 203 | value1, value2); |
205 | pmtmr_ioport = 0; | 204 | pmtmr_ioport = 0; |
206 | return -EINVAL; | 205 | return; |
207 | } | 206 | } |
208 | if (i == ACPI_PM_READ_CHECKS) { | 207 | if (i == ACPI_PM_READ_CHECKS) { |
209 | printk(KERN_INFO "PM-Timer failed consistency check " | 208 | printk(KERN_INFO "PM-Timer failed consistency check " |
210 | " (0x%#llx) - aborting.\n", value1); | 209 | " (0x%#llx) - aborting.\n", value1); |
211 | pmtmr_ioport = 0; | 210 | pmtmr_ioport = 0; |
212 | return -ENODEV; | 211 | return; |
213 | } | 212 | } |
214 | } | 213 | } |
215 | 214 | ||
216 | if (verify_pmtmr_rate() != 0){ | 215 | if (verify_pmtmr_rate() != 0){ |
217 | pmtmr_ioport = 0; | 216 | pmtmr_ioport = 0; |
218 | return -ENODEV; | 217 | return; |
219 | } | 218 | } |
220 | 219 | ||
221 | return clocksource_register_hz(&clocksource_acpi_pm, | 220 | clocksource_register_hz(&clocksource_acpi_pm, |
222 | PMTMR_TICKS_PER_SEC); | 221 | PMTMR_TICKS_PER_SEC); |
223 | } | 222 | } |
224 | 223 | ||
224 | static int __init init_acpi_pm_clocksource(void) | ||
225 | { | ||
226 | if (!pmtmr_ioport) | ||
227 | return -ENODEV; | ||
228 | |||
229 | async_schedule(acpi_pm_clocksource_async, NULL); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
225 | /* We use fs_initcall because we want the PCI fixups to have run | 233 | /* We use fs_initcall because we want the PCI fixups to have run |
226 | * but we still need to load before device_initcall | 234 | * but we still need to load before device_initcall |
227 | */ | 235 | */ |