From patchwork Fri May 22 14:35:54 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: grygorii.strashko@linaro.org X-Patchwork-Id: 475621 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 0A13F140E44 for ; Sat, 23 May 2015 00:36:20 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757159AbbEVOgS (ORCPT ); Fri, 22 May 2015 10:36:18 -0400 Received: from mail-lb0-f173.google.com ([209.85.217.173]:34300 "EHLO mail-lb0-f173.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757258AbbEVOgP (ORCPT ); Fri, 22 May 2015 10:36:15 -0400 Received: by lbcmx3 with SMTP id mx3so14323817lbc.1 for ; Fri, 22 May 2015 07:36:13 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=xKRFyeAJDZDFGwEey1HMp8DDhokclsxprVaBIq1T9Dc=; b=W5DLQY1HodNm8A/NLhL2fBwcu39vbq2K2aeFrnrM8uzylxWzCSZpnTStFwwFeOg9Tu 7cGi2/JaVRf6DF4RzKzCEN1QtAeHRizCX/j6xA5k43dzDTkuw8GrDE54llMAFhHNZZJt SRlUojUPb0p2rzHKTedPgoKx7kZgdpliG1vQubm7UarkaS01ZS5KRBG6OufgqzM2IVbc fqtcdvreDc2s8gt4wIZLsGaErtTmA3l3YFs7wO7yFn8wcVvZ29ZaLCjGf/ikBvL9/Srk syMqv+f8+GKnywkEHqiivnIVmSE9A/wJDb51pn6CLupSnYjBmtd7fax50a9XvOB3tPU2 9ktQ== X-Gm-Message-State: ALoCoQlMe71N9L/ReZ5FAGMNVHMv1IiwEkx72ZS73cx9MoqaYQijgb8c9dNiwSjj3c4JXMxN16hj X-Received: by 10.112.218.67 with SMTP id pe3mr6379583lbc.53.1432305373662; Fri, 22 May 2015 07:36:13 -0700 (PDT) Received: from localhost ([195.238.92.128]) by mx.google.com with ESMTPSA id h3sm530845lbj.19.2015.05.22.07.36.13 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 22 May 2015 07:36:13 -0700 (PDT) From: Grygorii Strashko To: Linus Walleij , Alexandre Courbot , tony@atomide.com Cc: Javier Martinez Canillas , ssantosh@kernel.org, Kevin Hilman , linux-omap@vger.kernel.org, linux-gpio@vger.kernel.org, Grygorii Strashko Subject: [RFC/RFT PATCH v2 7/7] gpio: omap: ensure that runtime pm will disable unused gpio banks Date: Fri, 22 May 2015 17:35:54 +0300 Message-Id: <1432305354-5968-8-git-send-email-grygorii.strashko@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1432305354-5968-1-git-send-email-grygorii.strashko@linaro.org> References: <1432305354-5968-1-git-send-email-grygorii.strashko@linaro.org> Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Now there are some points related to Runtime PM usage: 1) bank state doesn't need to be checked in places where Rintime PM is used, bacause Runtime PM maintains its own usage counter: if (!BANK_USED(bank)) pm_runtime_get_sync(bank->dev); so, it's safe to drop such checks. 2) Such implementation is racy, because check !BANK_USED(bank) is not protected, like: CPU0 CPU1 gpio_request(bankX.A) ... gpio_free(bankX.A) gpio_request(bankX.Y) and bankX can be unpowered in the middle of processing gpio_request(bankX.Y) 3) There is a call of pm_runtime_get_sync() in omap_gpio_irq_type(), but no corresponding put. As result, GPIO devices could be powered on forever if at least one GPIO was used as IRQ. Hence, allow powering off GPIO banks by adding missed pm_runtime_put(bank->dev) at the end of omap_gpio_irq_type(). As, part of this change update omap2_gpio_xxxx_idle() functions to use pm_runtime_force_suspend()/pm_runtime_force_resume(). Signed-off-by: Grygorii Strashko --- Changes in v2: - omap2_gpio_xxxx_idle() functions switched to use pm_runtime_force_suspend()/pm_runtime_force_resume() API. v1: http://marc.info/?l=linux-gpio&m=142567003515626&w=2 drivers/gpio/gpio-omap.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f02b3fa..e26dc40 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -486,8 +486,7 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH))) return -EINVAL; - if (!BANK_USED(bank)) - pm_runtime_get_sync(bank->dev); + pm_runtime_get_sync(bank->dev); spin_lock_irqsave(&bank->lock, flags); retval = omap_set_gpio_triggering(bank, offset, type); @@ -500,11 +499,8 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) __irq_set_handler_locked(d->irq, handle_edge_irq); - return 0; - error: - if (!BANK_USED(bank)) - pm_runtime_put(bank->dev); + pm_runtime_put(bank->dev); return retval; } @@ -649,8 +645,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) * If this is the first gpio_request for the bank, * enable the bank module. */ - if (!BANK_USED(bank)) - pm_runtime_get_sync(bank->dev); + pm_runtime_get_sync(bank->dev); spin_lock_irqsave(&bank->lock, flags); omap_enable_gpio_module(bank, offset); @@ -678,8 +673,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) * If this is the last gpio to be freed in the bank, * disable the bank module. */ - if (!BANK_USED(bank)) - pm_runtime_put(bank->dev); + pm_runtime_put(bank->dev); } /* @@ -771,8 +765,7 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) unsigned long flags; unsigned offset = d->hwirq; - if (!BANK_USED(bank)) - pm_runtime_get_sync(bank->dev); + pm_runtime_get_sync(bank->dev); spin_lock_irqsave(&bank->lock, flags); @@ -789,8 +782,7 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) return 0; err: spin_unlock_irqrestore(&bank->lock, flags); - if (!BANK_USED(bank)) - pm_runtime_put(bank->dev); + pm_runtime_put(bank->dev); return -EINVAL; } @@ -814,8 +806,7 @@ static void omap_gpio_irq_shutdown(struct irq_data *d) * If this is the last IRQ to be freed in the bank, * disable the bank module. */ - if (!BANK_USED(bank)) - pm_runtime_put(bank->dev); + pm_runtime_put(bank->dev); } static void omap_gpio_ack_irq(struct irq_data *d) @@ -1419,12 +1410,12 @@ void omap2_gpio_prepare_for_idle(int pwr_mode) struct gpio_bank *bank; list_for_each_entry(bank, &omap_gpio_list, node) { - if (!BANK_USED(bank) || !bank->loses_context) + if (!bank->loses_context) continue; bank->power_mode = pwr_mode; - pm_runtime_put_sync_suspend(bank->dev); + pm_runtime_force_suspend(bank->dev); } } @@ -1433,10 +1424,10 @@ void omap2_gpio_resume_after_idle(void) struct gpio_bank *bank; list_for_each_entry(bank, &omap_gpio_list, node) { - if (!BANK_USED(bank) || !bank->loses_context) + if (!bank->loses_context) continue; - pm_runtime_get_sync(bank->dev); + pm_runtime_force_resume(bank->dev); } }