diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-20 21:32:09 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-20 21:32:09 +0400 |
commit | 161f7a7161191ab9c2e97f787829ef8dd2b95771 (patch) | |
tree | 9776d3f963c7f0d247b7fb324eab4811a1302f67 /drivers | |
parent | 2ba68940c893c8f0bfc8573c041254251bb6aeab (diff) | |
parent | a078c6d0e6288fad6d83fb6d5edd91ddb7b6ab33 (diff) | |
download | linux-161f7a7161191ab9c2e97f787829ef8dd2b95771.tar.xz |
Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer changes for v3.4 from Ingo Molnar
* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (32 commits)
ntp: Fix integer overflow when setting time
math: Introduce div64_long
cs5535-clockevt: Allow the MFGPT IRQ to be shared
cs5535-clockevt: Don't ignore MFGPT on SMP-capable kernels
x86/time: Eliminate unused irq0_irqs counter
clocksource: scx200_hrt: Fix the build
x86/tsc: Reduce the TSC sync check time for core-siblings
timer: Fix bad idle check on irq entry
nohz: Remove ts->Einidle checks before restarting the tick
nohz: Remove update_ts_time_stat from tick_nohz_start_idle
clockevents: Leave the broadcast device in shutdown mode when not needed
clocksource: Load the ACPI PM clocksource asynchronously
clocksource: scx200_hrt: Convert scx200 to use clocksource_register_hz
clocksource: Get rid of clocksource_calc_mult_shift()
clocksource: dbx500: convert to clocksource_register_hz()
clocksource: scx200_hrt: use pr_<level> instead of printk
time: Move common updates to a function
time: Reorder so the hot data is together
time: Remove most of xtime_lock usage in timekeeping.c
ntp: Add ntp_lock to replace xtime_locking
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clocksource/acpi_pm.c | 24 | ||||
-rw-r--r-- | drivers/clocksource/clksrc-dbx500-prcmu.c | 5 | ||||
-rw-r--r-- | drivers/clocksource/cs5535-clockevt.c | 3 | ||||
-rw-r--r-- | drivers/clocksource/cyclone.c | 2 | ||||
-rw-r--r-- | drivers/clocksource/scx200_hrt.c | 24 | ||||
-rw-r--r-- | drivers/rtc/interface.c | 30 |
6 files changed, 54 insertions, 34 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 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/delay.h> +#include <linux/async.h> #include <asm/io.h> /* @@ -179,17 +180,15 @@ static int verify_pmtmr_rate(void) /* Number of reads we try to get two different values */ #define ACPI_PM_READ_CHECKS 10000 -static int __init init_acpi_pm_clocksource(void) +static void __init acpi_pm_clocksource_async(void *unused, async_cookie_t cookie) { cycle_t value1, value2; unsigned int i, j = 0; - if (!pmtmr_ioport) - return -ENODEV; /* "verify" this timing source: */ for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) { - udelay(100 * j); + usleep_range(100 * j, 100 * j + 100); value1 = clocksource_acpi_pm.read(&clocksource_acpi_pm); for (i = 0; i < ACPI_PM_READ_CHECKS; i++) { value2 = clocksource_acpi_pm.read(&clocksource_acpi_pm); @@ -203,25 +202,34 @@ static int __init init_acpi_pm_clocksource(void) " 0x%#llx, 0x%#llx - aborting.\n", value1, value2); pmtmr_ioport = 0; - return -EINVAL; + return; } if (i == ACPI_PM_READ_CHECKS) { printk(KERN_INFO "PM-Timer failed consistency check " " (0x%#llx) - aborting.\n", value1); pmtmr_ioport = 0; - return -ENODEV; + return; } } if (verify_pmtmr_rate() != 0){ pmtmr_ioport = 0; - return -ENODEV; + return; } - return clocksource_register_hz(&clocksource_acpi_pm, + clocksource_register_hz(&clocksource_acpi_pm, PMTMR_TICKS_PER_SEC); } +static int __init init_acpi_pm_clocksource(void) +{ + if (!pmtmr_ioport) + return -ENODEV; + + async_schedule(acpi_pm_clocksource_async, NULL); + return 0; +} + /* We use fs_initcall because we want the PCI fixups to have run * but we still need to load before device_initcall */ diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c index fb6b6d28b60e..c26c369eb9e6 100644 --- a/drivers/clocksource/clksrc-dbx500-prcmu.c +++ b/drivers/clocksource/clksrc-dbx500-prcmu.c @@ -52,7 +52,6 @@ static struct clocksource clocksource_dbx500_prcmu = { .name = "dbx500-prcmu-timer", .rating = 300, .read = clksrc_dbx500_prcmu_read, - .shift = 10, .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -90,7 +89,5 @@ void __init clksrc_dbx500_prcmu_init(void __iomem *base) setup_sched_clock(dbx500_prcmu_sched_clock_read, 32, RATE_32K); #endif - clocksource_calc_mult_shift(&clocksource_dbx500_prcmu, - RATE_32K, SCHED_CLOCK_MIN_WRAP); - clocksource_register(&clocksource_dbx500_prcmu); + clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K); } diff --git a/drivers/clocksource/cs5535-clockevt.c b/drivers/clocksource/cs5535-clockevt.c index b7dab32ce63c..540795cd0760 100644 --- a/drivers/clocksource/cs5535-clockevt.c +++ b/drivers/clocksource/cs5535-clockevt.c @@ -100,7 +100,6 @@ static struct clock_event_device cs5535_clockevent = { .set_mode = mfgpt_set_mode, .set_next_event = mfgpt_next_event, .rating = 250, - .cpumask = cpu_all_mask, .shift = 32 }; @@ -133,7 +132,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id) static struct irqaction mfgptirq = { .handler = mfgpt_tick, - .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER, + .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER | IRQF_SHARED, .name = DRV_NAME, }; diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c index 72f811f73e9c..9e0998f22885 100644 --- a/drivers/clocksource/cyclone.c +++ b/drivers/clocksource/cyclone.c @@ -55,11 +55,11 @@ static int __init init_cyclone_clocksource(void) } /* even on 64bit systems, this is only 32bits: */ base = readl(reg); + iounmap(reg); if (!base) { printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n"); return -ENODEV; } - iounmap(reg); /* setup PMCC: */ offset = base + CYCLONE_PMCC_OFFSET; diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c index 27f4d9637b62..64f9e8294434 100644 --- a/drivers/clocksource/scx200_hrt.c +++ b/drivers/clocksource/scx200_hrt.c @@ -49,9 +49,6 @@ static cycle_t read_hrt(struct clocksource *cs) return (cycle_t) inl(scx200_cb_base + SCx200_TIMER_OFFSET); } -#define HRT_SHIFT_1 22 -#define HRT_SHIFT_27 26 - static struct clocksource cs_hrt = { .name = "scx200_hrt", .rating = 250, @@ -63,6 +60,7 @@ static struct clocksource cs_hrt = { static int __init init_hrt_clocksource(void) { + u32 freq; /* Make sure scx200 has initialized the configuration block */ if (!scx200_cb_present()) return -ENODEV; @@ -71,7 +69,7 @@ static int __init init_hrt_clocksource(void) if (!request_region(scx200_cb_base + SCx200_TIMER_OFFSET, SCx200_TIMER_SIZE, "NatSemi SCx200 High-Resolution Timer")) { - printk(KERN_WARNING NAME ": unable to lock timer region\n"); + pr_warn("unable to lock timer region\n"); return -ENODEV; } @@ -79,19 +77,13 @@ static int __init init_hrt_clocksource(void) outb(HR_TMEN | (mhz27 ? HR_TMCLKSEL : 0), scx200_cb_base + SCx200_TMCNFG_OFFSET); - if (mhz27) { - cs_hrt.shift = HRT_SHIFT_27; - cs_hrt.mult = clocksource_hz2mult((HRT_FREQ + ppm) * 27, - cs_hrt.shift); - } else { - cs_hrt.shift = HRT_SHIFT_1; - cs_hrt.mult = clocksource_hz2mult(HRT_FREQ + ppm, - cs_hrt.shift); - } - printk(KERN_INFO "enabling scx200 high-res timer (%s MHz +%d ppm)\n", - mhz27 ? "27":"1", ppm); + freq = (HRT_FREQ + ppm); + if (mhz27) + freq *= 27; + + pr_info("enabling scx200 high-res timer (%s MHz +%d ppm)\n", mhz27 ? "27":"1", ppm); - return clocksource_register(&cs_hrt); + return clocksource_register_hz(&cs_hrt, freq); } module_init(init_hrt_clocksource); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 8a1c031391d6..dc87eda65814 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -73,6 +73,8 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) err = -EINVAL; mutex_unlock(&rtc->ops_lock); + /* A timer might have just expired */ + schedule_work(&rtc->irqwork); return err; } EXPORT_SYMBOL_GPL(rtc_set_time); @@ -112,6 +114,8 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) err = -EINVAL; mutex_unlock(&rtc->ops_lock); + /* A timer might have just expired */ + schedule_work(&rtc->irqwork); return err; } @@ -380,18 +384,27 @@ EXPORT_SYMBOL_GPL(rtc_set_alarm); int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { int err; + struct rtc_time now; err = rtc_valid_tm(&alarm->time); if (err != 0) return err; + err = rtc_read_time(rtc, &now); + if (err) + return err; + err = mutex_lock_interruptible(&rtc->ops_lock); if (err) return err; rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); rtc->aie_timer.period = ktime_set(0, 0); - if (alarm->enabled) { + + /* Alarm has to be enabled & in the futrure for us to enqueue it */ + if (alarm->enabled && (rtc_tm_to_ktime(now).tv64 < + rtc->aie_timer.node.expires.tv64)) { + rtc->aie_timer.enabled = 1; timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node); } @@ -763,6 +776,14 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) return 0; } +static void rtc_alarm_disable(struct rtc_device *rtc) +{ + if (!rtc->ops || !rtc->ops->alarm_irq_enable) + return; + + rtc->ops->alarm_irq_enable(rtc->dev.parent, false); +} + /** * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue * @rtc rtc device @@ -784,8 +805,10 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) struct rtc_wkalrm alarm; int err; next = timerqueue_getnext(&rtc->timerqueue); - if (!next) + if (!next) { + rtc_alarm_disable(rtc); return; + } alarm.time = rtc_ktime_to_tm(next->expires); alarm.enabled = 1; err = __rtc_set_alarm(rtc, &alarm); @@ -847,7 +870,8 @@ again: err = __rtc_set_alarm(rtc, &alarm); if (err == -ETIME) goto again; - } + } else + rtc_alarm_disable(rtc); mutex_unlock(&rtc->ops_lock); } |