diff options
author | Takashi YOSHII <takashi.yoshii.zj@renesas.com> | 2010-12-17 02:25:09 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-12-17 05:38:33 -0500 |
commit | 65ada547d68dc075aa06df92fe325bff07cbc606 (patch) | |
tree | 8c8ab2cc7814d6f85f6cb3a4b40e5165e5a0a7ad /drivers/clocksource | |
parent | b3444d164be8f977f4133ef0c6f4a18f2741373f (diff) |
clocksource: sh_cmt: Remove nested spinlock fix
There are control flow that sh_cmt_set_next() does double
spin-lock. The callers sh_cmt_{start,stop}() already have
lock. But another callers sh_cmt_clock_event_{start,next}()
does not.
Now sh_cmt_set_next() does not lock by itself. All the
callers should hold spin-lock before calling it.
[damm@opensource.se: use __sh_cmt_set_next() to simplify code]
[damm@opensource.se: added stable, suitable for v2.6.35 + v2.6.36]
Cc: stable@kernel.org
Signed-off-by: Takashi YOSHII <takashi.yoshii.zj@renesas.com>
Signed-off-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/clocksource')
-rw-r--r-- | drivers/clocksource/sh_cmt.c | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index d68d3aa1814b..f975d24890fa 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c | |||
@@ -283,16 +283,21 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p, | |||
283 | } while (delay); | 283 | } while (delay); |
284 | } | 284 | } |
285 | 285 | ||
286 | static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta) | 286 | static void __sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta) |
287 | { | 287 | { |
288 | unsigned long flags; | ||
289 | |||
290 | if (delta > p->max_match_value) | 288 | if (delta > p->max_match_value) |
291 | dev_warn(&p->pdev->dev, "delta out of range\n"); | 289 | dev_warn(&p->pdev->dev, "delta out of range\n"); |
292 | 290 | ||
293 | spin_lock_irqsave(&p->lock, flags); | ||
294 | p->next_match_value = delta; | 291 | p->next_match_value = delta; |
295 | sh_cmt_clock_event_program_verify(p, 0); | 292 | sh_cmt_clock_event_program_verify(p, 0); |
293 | } | ||
294 | |||
295 | static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta) | ||
296 | { | ||
297 | unsigned long flags; | ||
298 | |||
299 | spin_lock_irqsave(&p->lock, flags); | ||
300 | __sh_cmt_set_next(p, delta); | ||
296 | spin_unlock_irqrestore(&p->lock, flags); | 301 | spin_unlock_irqrestore(&p->lock, flags); |
297 | } | 302 | } |
298 | 303 | ||
@@ -359,7 +364,7 @@ static int sh_cmt_start(struct sh_cmt_priv *p, unsigned long flag) | |||
359 | 364 | ||
360 | /* setup timeout if no clockevent */ | 365 | /* setup timeout if no clockevent */ |
361 | if ((flag == FLAG_CLOCKSOURCE) && (!(p->flags & FLAG_CLOCKEVENT))) | 366 | if ((flag == FLAG_CLOCKSOURCE) && (!(p->flags & FLAG_CLOCKEVENT))) |
362 | sh_cmt_set_next(p, p->max_match_value); | 367 | __sh_cmt_set_next(p, p->max_match_value); |
363 | out: | 368 | out: |
364 | spin_unlock_irqrestore(&p->lock, flags); | 369 | spin_unlock_irqrestore(&p->lock, flags); |
365 | 370 | ||
@@ -381,7 +386,7 @@ static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag) | |||
381 | 386 | ||
382 | /* adjust the timeout to maximum if only clocksource left */ | 387 | /* adjust the timeout to maximum if only clocksource left */ |
383 | if ((flag == FLAG_CLOCKEVENT) && (p->flags & FLAG_CLOCKSOURCE)) | 388 | if ((flag == FLAG_CLOCKEVENT) && (p->flags & FLAG_CLOCKSOURCE)) |
384 | sh_cmt_set_next(p, p->max_match_value); | 389 | __sh_cmt_set_next(p, p->max_match_value); |
385 | 390 | ||
386 | spin_unlock_irqrestore(&p->lock, flags); | 391 | spin_unlock_irqrestore(&p->lock, flags); |
387 | } | 392 | } |