From patchwork Thu Aug 21 13:47:45 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tero Kristo X-Patchwork-Id: 4758031 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 789FEC0338 for ; Thu, 21 Aug 2014 13:50:09 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 558972017D for ; Thu, 21 Aug 2014 13:50:08 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9F5152017E for ; Thu, 21 Aug 2014 13:50:06 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XKSiq-00065h-0S; Thu, 21 Aug 2014 13:48:12 +0000 Received: from devils.ext.ti.com ([198.47.26.153]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XKSim-0005wl-1d for linux-arm-kernel@lists.infradead.org; Thu, 21 Aug 2014 13:48:08 +0000 Received: from dflxv15.itg.ti.com ([128.247.5.124]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id s7LDljus022889; Thu, 21 Aug 2014 08:47:45 -0500 Received: from DLEE70.ent.ti.com (dlee70.ent.ti.com [157.170.170.113]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id s7LDljgk023249; Thu, 21 Aug 2014 08:47:45 -0500 Received: from dflp33.itg.ti.com (10.64.6.16) by DLEE70.ent.ti.com (157.170.170.113) with Microsoft SMTP Server id 14.3.174.1; Thu, 21 Aug 2014 08:47:44 -0500 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp33.itg.ti.com (8.14.3/8.13.8) with ESMTP id s7LDlgHp031898; Thu, 21 Aug 2014 08:47:43 -0500 From: Tero Kristo To: , , , , Subject: [PATCH] clk: prevent erronous parsing of children during rate change Date: Thu, 21 Aug 2014 16:47:45 +0300 Message-ID: <1408628866-32351-1-git-send-email-t-kristo@ti.com> X-Mailer: git-send-email 1.7.9.5 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140821_064808_171697_8C0915D8 X-CRM114-Status: UNSURE ( 9.76 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -5.7 (-----) Cc: linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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. Signed-off-by: Tero Kristo To: Mike Turquette Reported-by: Nishanth Menon Tested-by: Nishanth Menon --- drivers/clk/clk.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index b76fa69..bacc06f 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1467,6 +1467,7 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even static void clk_change_rate(struct clk *clk) { struct clk *child; + struct hlist_node *tmp; unsigned long old_rate; unsigned long best_parent_rate = 0; bool skip_set_rate = false; @@ -1502,7 +1503,11 @@ static void clk_change_rate(struct clk *clk) if (clk->notifier_count && old_rate != clk->rate) __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate); - hlist_for_each_entry(child, &clk->children, child_node) { + /* + * Use safe iteration, as change_rate can actually swap parents + * for certain clock types. + */ + hlist_for_each_entry_safe(child, tmp, &clk->children, child_node) { /* Skip children who will be reparented to another clock */ if (child->new_parent && child->new_parent != clk) continue;