Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: prevent erronous parsing of children during rate change

In some cases, clocks can switch their parent with clk_set_rate, for
example clk_mux can do this in some cases. Current implementation of
clk_change_rate uses un-safe list iteration on the clock children, which
will cause wrong clocks to be parsed in case any of the clock children
change their parents during the change rate operation. Fixed by using
the safe list iterator instead.

The problem was detected due to some divide by zero errors generated
by clock init on dra7-evm board, see discussion under
http://article.gmane.org/gmane.linux.ports.arm.kernel/349180 for details.

Fixes: 71472c0c06cf ("clk: add support for clock reparent on set_rate")
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Reported-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>

authored by

Tero Kristo and committed by
Mike Turquette
067bb174 f4ee3c84

+6 -1
+6 -1
drivers/clk/clk.c
··· 1467 1467 static void clk_change_rate(struct clk *clk) 1468 1468 { 1469 1469 struct clk *child; 1470 + struct hlist_node *tmp; 1470 1471 unsigned long old_rate; 1471 1472 unsigned long best_parent_rate = 0; 1472 1473 bool skip_set_rate = false; ··· 1503 1502 if (clk->notifier_count && old_rate != clk->rate) 1504 1503 __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate); 1505 1504 1506 - hlist_for_each_entry(child, &clk->children, child_node) { 1505 + /* 1506 + * Use safe iteration, as change_rate can actually swap parents 1507 + * for certain clock types. 1508 + */ 1509 + hlist_for_each_entry_safe(child, tmp, &clk->children, child_node) { 1507 1510 /* Skip children who will be reparented to another clock */ 1508 1511 if (child->new_parent && child->new_parent != clk) 1509 1512 continue;