diff options
| author | Soren Brinkmann <soren.brinkmann@xilinx.com> | 2013-04-03 12:17:12 -0700 | 
|---|---|---|
| committer | Mike Turquette <mturquette@linaro.org> | 2013-04-10 16:33:53 -0700 | 
| commit | fb72a0590b770f7da6a02bde6b8a147a3d9f6168 (patch) | |
| tree | b842b02beb3a44b0d595f0b6020b8ed71c8f448e | |
| parent | 312f0f0b9a4e3e2cc8ad1bbc4577a6dff025cdf6 (diff) | |
| download | olio-linux-3.10-fb72a0590b770f7da6a02bde6b8a147a3d9f6168.tar.xz olio-linux-3.10-fb72a0590b770f7da6a02bde6b8a147a3d9f6168.zip  | |
clk: Properly handle notifier return values
Notifiers may return NOTIFY_(OK|DONE|STOP|BAD). The CCF uses an
inconsistent mix of checking against NOTIFY_STOP or NOTIFY_BAD.
This inconsistency leaves errors undetected in some cases:
clk_set_parent() calls __clk_speculate_rates(), which stops when it
hits a NOTIFIER_BAD (STOP is ignored), and passes this value back to the
caller.
clk_set_parent() compares this return value against NOTIFY_STOP only,
ignoring NOTIFY_BAD returns.
Use NOTIFY_STOP_MASK to detect a negative notifier return value and
document all four return value options.
Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
| -rw-r--r-- | drivers/clk/clk.c | 10 | ||||
| -rw-r--r-- | include/linux/clk.h | 8 | 
2 files changed, 9 insertions, 9 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index de6b459de78..d65ef178e6e 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1027,16 +1027,16 @@ static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)  	else  		new_rate = parent_rate; -	/* abort the rate change if a driver returns NOTIFY_BAD */ +	/* abort rate change if a driver returns NOTIFY_BAD or NOTIFY_STOP */  	if (clk->notifier_count)  		ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate); -	if (ret == NOTIFY_BAD) +	if (ret & NOTIFY_STOP_MASK)  		goto out;  	hlist_for_each_entry(child, &clk->children, child_node) {  		ret = __clk_speculate_rates(child, new_rate); -		if (ret == NOTIFY_BAD) +		if (ret & NOTIFY_STOP_MASK)  			break;  	} @@ -1129,7 +1129,7 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even  	if (clk->notifier_count) {  		ret = __clk_notify(clk, event, clk->rate, clk->new_rate); -		if (ret == NOTIFY_BAD) +		if (ret & NOTIFY_STOP_MASK)  			fail_clk = clk;  	} @@ -1484,7 +1484,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)  		ret = __clk_speculate_rates(clk, p_rate);  	/* abort if a driver objects */ -	if (ret == NOTIFY_STOP) +	if (ret & NOTIFY_STOP_MASK)  		goto out;  	/* do the re-parent */ diff --git a/include/linux/clk.h b/include/linux/clk.h index b3ac22d0fc1..9a6d04524b1 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -28,16 +28,16 @@ struct clk;   * PRE_RATE_CHANGE - called immediately before the clk rate is changed,   *     to indicate that the rate change will proceed.  Drivers must   *     immediately terminate any operations that will be affected by the - *     rate change.  Callbacks may either return NOTIFY_DONE or - *     NOTIFY_STOP. + *     rate change.  Callbacks may either return NOTIFY_DONE, NOTIFY_OK, + *     NOTIFY_STOP or NOTIFY_BAD.   *   * ABORT_RATE_CHANGE: called if the rate change failed for some reason   *     after PRE_RATE_CHANGE.  In this case, all registered notifiers on   *     the clk will be called with ABORT_RATE_CHANGE. Callbacks must - *     always return NOTIFY_DONE. + *     always return NOTIFY_DONE or NOTIFY_OK.   *   * POST_RATE_CHANGE - called after the clk rate change has successfully - *     completed.  Callbacks must always return NOTIFY_DONE. + *     completed.  Callbacks must always return NOTIFY_DONE or NOTIFY_OK.   *   */  #define PRE_RATE_CHANGE			BIT(0)  |