Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 260395
b: refs/heads/master
c: b830ac1
h: refs/heads/master
i:
  260393: 6337325
  260391: b48386d
v: v3
  • Loading branch information
Thomas Gleixner authored and Linus Torvalds committed Jul 26, 2011
1 parent 65c775d commit 72ad11c
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 20 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 431e2bcc371016824f419baa745f82388258f3ee
refs/heads/master: b830ac1d9a2262093bb0f3f6a2fd2a1c8278daf5
56 changes: 37 additions & 19 deletions trunk/drivers/rtc/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,29 @@ void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
}
EXPORT_SYMBOL_GPL(rtc_irq_unregister);

static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
{
/*
* We unconditionally cancel the timer here, because otherwise
* we could run into BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
* when we manage to start the timer before the callback
* returns HRTIMER_RESTART.
*
* We cannot use hrtimer_cancel() here as a running callback
* could be blocked on rtc->irq_task_lock and hrtimer_cancel()
* would spin forever.
*/
if (hrtimer_try_to_cancel(&rtc->pie_timer) < 0)
return -1;

if (enabled) {
ktime_t period = ktime_set(0, NSEC_PER_SEC / rtc->irq_freq);

hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL);
}
return 0;
}

/**
* rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs
* @rtc: the rtc device
Expand All @@ -651,24 +674,21 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled
int err = 0;
unsigned long flags;

retry:
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != NULL && task == NULL)
err = -EBUSY;
if (rtc->irq_task != task)
err = -EACCES;
if (err)
goto out;

if (enabled) {
ktime_t period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq);
hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL);
} else {
hrtimer_cancel(&rtc->pie_timer);
if (!err) {
if (rtc_update_hrtimer(rtc, enabled) < 0) {
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
cpu_relax();
goto retry;
}
rtc->pie_enabled = enabled;
}
rtc->pie_enabled = enabled;
out:
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);

return err;
}
EXPORT_SYMBOL_GPL(rtc_irq_set_state);
Expand All @@ -690,20 +710,18 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)

if (freq <= 0 || freq > 5000)
return -EINVAL;

retry:
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != NULL && task == NULL)
err = -EBUSY;
if (rtc->irq_task != task)
err = -EACCES;
if (err == 0) {
if (!err) {
rtc->irq_freq = freq;
if (rtc->pie_enabled) {
ktime_t period;
hrtimer_cancel(&rtc->pie_timer);
period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq);
hrtimer_start(&rtc->pie_timer, period,
HRTIMER_MODE_REL);
if (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) {
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
cpu_relax();
goto retry;
}
}
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
Expand Down

0 comments on commit 72ad11c

Please sign in to comment.