From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752690AbcJJX15 (ORCPT ); Mon, 10 Oct 2016 19:27:57 -0400 Received: from mail-pa0-f66.google.com ([209.85.220.66]:33962 "EHLO mail-pa0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752378AbcJJX1z (ORCPT ); Mon, 10 Oct 2016 19:27:55 -0400 From: Caesar Wang To: khilman@linaro.org, heiko@sntech.de Cc: zhangqing@rock-chips.com, linux-rockchip@lists.infradead.org, linux-kernel@vger.kernel.org, tfiga@chromium.org, Caesar Wang Subject: [PATCH] soc: rockchip: avoid infinite loop for power domain Date: Tue, 11 Oct 2016 07:11:07 +0800 Message-Id: <1476141067-21186-1-git-send-email-wxt@rock-chips.com> X-Mailer: git-send-email 1.9.1 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In some cases, we have met the infinite loop in rockchip_pmu_set_idle_request. This patch adds the error message and avoid infinite loop if it fails to get the ack. Signed-off-by: Caesar Wang --- drivers/soc/rockchip/pm_domains.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 7acd151..cb2a076 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -105,12 +106,24 @@ static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd) return (val & pd_info->idle_mask) == pd_info->idle_mask; } +static u32 rockchip_pmu_read_ack(struct rockchip_pmu *pmu) +{ + u32 val; + + regmap_read(pmu->regmap, pmu->info->ack_offset, &val); + return val; +} + static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, bool idle) { const struct rockchip_domain_info *pd_info = pd->info; + struct generic_pm_domain *genpd = &pd->genpd; struct rockchip_pmu *pmu = pd->pmu; unsigned int val; + u32 target_ack; + bool target_idle; + int ret; if (pd_info->req_mask == 0) return 0; @@ -120,12 +133,26 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, dsb(sy); - do { - regmap_read(pmu->regmap, pmu->info->ack_offset, &val); - } while ((val & pd_info->ack_mask) != (idle ? pd_info->ack_mask : 0)); + /* Wait util idle_ack = 1 */ + target_ack = idle ? pd_info->ack_mask : 0; + ret = readx_poll_timeout_atomic(rockchip_pmu_read_ack, pmu, val, + (val & pd_info->ack_mask) == target_ack, 0, 10000); + if (ret) { + dev_err(pmu->dev, + "failed to get ack on domain '%s', val=0x%x\n", + genpd->name, val); + return ret; + } - while (rockchip_pmu_domain_is_idle(pd) != idle) - cpu_relax(); + ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_idle, pd, + target_idle, target_idle == idle, + 0, 10000); + if (ret) { + dev_err(pmu->dev, + "failed to set idle on domain '%s', val=0x%x\n", + genpd->name, target_idle); + return ret; + } return 0; } -- 1.9.1