Skip to content

Commit

Permalink
Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…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
  ...
  • Loading branch information
Linus Torvalds committed Mar 20, 2012
2 parents 2ba6894 + a078c6d commit 161f7a7
Show file tree
Hide file tree
Showing 17 changed files with 343 additions and 252 deletions.
1 change: 0 additions & 1 deletion arch/x86/include/asm/hardirq.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
typedef struct {
unsigned int __softirq_pending;
unsigned int __nmi_count; /* arch dependent */
unsigned int irq0_irqs;
#ifdef CONFIG_X86_LOCAL_APIC
unsigned int apic_timer_irqs; /* arch dependent */
unsigned int irq_spurious_count;
Expand Down
3 changes: 0 additions & 3 deletions arch/x86/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,6 @@ EXPORT_SYMBOL(profile_pc);
*/
static irqreturn_t timer_interrupt(int irq, void *dev_id)
{
/* Keep nmi watchdog up to date */
inc_irq_stat(irq0_irqs);

global_clock_event->event_handler(global_clock_event);

/* MCA bus quirk: Acknowledge irq0 by setting bit 7 in port 0x61 */
Expand Down
29 changes: 24 additions & 5 deletions arch/x86/kernel/tsc_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ static __cpuinitdata int nr_warps;
/*
* TSC-warp measurement loop running on both CPUs:
*/
static __cpuinit void check_tsc_warp(void)
static __cpuinit void check_tsc_warp(unsigned int timeout)
{
cycles_t start, now, prev, end;
int i;
Expand All @@ -51,9 +51,9 @@ static __cpuinit void check_tsc_warp(void)
start = get_cycles();
rdtsc_barrier();
/*
* The measurement runs for 20 msecs:
* The measurement runs for 'timeout' msecs:
*/
end = start + tsc_khz * 20ULL;
end = start + (cycles_t) tsc_khz * timeout;
now = start;

for (i = 0; ; i++) {
Expand Down Expand Up @@ -98,6 +98,25 @@ static __cpuinit void check_tsc_warp(void)
now-start, end-start);
}

/*
* If the target CPU coming online doesn't have any of its core-siblings
* online, a timeout of 20msec will be used for the TSC-warp measurement
* loop. Otherwise a smaller timeout of 2msec will be used, as we have some
* information about this socket already (and this information grows as we
* have more and more logical-siblings in that socket).
*
* Ideally we should be able to skip the TSC sync check on the other
* core-siblings, if the first logical CPU in a socket passed the sync test.
* But as the TSC is per-logical CPU and can potentially be modified wrongly
* by the bios, TSC sync test for smaller duration should be able
* to catch such errors. Also this will catch the condition where all the
* cores in the socket doesn't get reset at the same time.
*/
static inline unsigned int loop_timeout(int cpu)
{
return (cpumask_weight(cpu_core_mask(cpu)) > 1) ? 2 : 20;
}

/*
* Source CPU calls into this - it waits for the freshly booted
* target CPU to arrive and then starts the measurement:
Expand Down Expand Up @@ -135,7 +154,7 @@ void __cpuinit check_tsc_sync_source(int cpu)
*/
atomic_inc(&start_count);

check_tsc_warp();
check_tsc_warp(loop_timeout(cpu));

while (atomic_read(&stop_count) != cpus-1)
cpu_relax();
Expand Down Expand Up @@ -183,7 +202,7 @@ void __cpuinit check_tsc_sync_target(void)
while (atomic_read(&start_count) != cpus)
cpu_relax();

check_tsc_warp();
check_tsc_warp(loop_timeout(smp_processor_id()));

/*
* Ok, we are done:
Expand Down
24 changes: 16 additions & 8 deletions drivers/clocksource/acpi_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/async.h>
#include <asm/io.h>

/*
Expand Down Expand Up @@ -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);
Expand All @@ -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
*/
Expand Down
5 changes: 1 addition & 4 deletions drivers/clocksource/clksrc-dbx500-prcmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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);
}
3 changes: 1 addition & 2 deletions drivers/clocksource/cs5535-clockevt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down Expand Up @@ -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,
};

Expand Down
2 changes: 1 addition & 1 deletion drivers/clocksource/cyclone.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
24 changes: 8 additions & 16 deletions drivers/clocksource/scx200_hrt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand All @@ -71,27 +69,21 @@ 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;
}

/* write timer config */
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);
Expand Down
30 changes: 27 additions & 3 deletions drivers/rtc/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -847,7 +870,8 @@ void rtc_timer_do_work(struct work_struct *work)
err = __rtc_set_alarm(rtc, &alarm);
if (err == -ETIME)
goto again;
}
} else
rtc_alarm_disable(rtc);

mutex_unlock(&rtc->ops_lock);
}
Expand Down
7 changes: 0 additions & 7 deletions include/linux/clocksource.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,13 +319,6 @@ static inline void __clocksource_updatefreq_khz(struct clocksource *cs, u32 khz)
__clocksource_updatefreq_scale(cs, 1000, khz);
}

static inline void
clocksource_calc_mult_shift(struct clocksource *cs, u32 freq, u32 minsec)
{
return clocks_calc_mult_shift(&cs->mult, &cs->shift, freq,
NSEC_PER_SEC, minsec);
}

#ifdef CONFIG_GENERIC_TIME_VSYSCALL
extern void
update_vsyscall(struct timespec *ts, struct timespec *wtm,
Expand Down
4 changes: 4 additions & 0 deletions include/linux/math64.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#if BITS_PER_LONG == 64

#define div64_long(x,y) div64_s64((x),(y))

/**
* div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder
*
Expand Down Expand Up @@ -45,6 +47,8 @@ static inline s64 div64_s64(s64 dividend, s64 divisor)

#elif BITS_PER_LONG == 32

#define div64_long(x,y) div_s64((x),(y))

#ifndef div_u64_rem
static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
{
Expand Down
Loading

0 comments on commit 161f7a7

Please sign in to comment.