From patchwork Tue Aug 22 13:58:24 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Volkov X-Patchwork-Id: 804473 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3xcBz22ldJz9sRq for ; Wed, 23 Aug 2017 00:00:30 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932851AbdHVOAM (ORCPT ); Tue, 22 Aug 2017 10:00:12 -0400 Received: from bran.ispras.ru ([83.149.199.196]:32350 "EHLO smtp.ispras.ru" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S932849AbdHVN7C (ORCPT ); Tue, 22 Aug 2017 09:59:02 -0400 Received: from berg.intra.ispras.ru (berg.intra.ispras.ru [10.10.2.208]) by smtp.ispras.ru (Postfix) with ESMTP id 3EC875FB48; Tue, 22 Aug 2017 16:59:01 +0300 (MSK) From: Anton Volkov To: ldewangan@nvidia.com, thierry.reding@gmail.com, broonie@kernel.org Cc: jonathanh@nvidia.com, linux-spi@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, ldv-project@linuxtesting.org, khoroshilov@ispras.ru, Anton Volkov Subject: [PATCH] tegra114: fix to a race condition due to early registration of interrupt handler Date: Tue, 22 Aug 2017 16:58:24 +0300 Message-Id: <1503410304-8083-1-git-send-email-avolkov@ispras.ru> X-Mailer: git-send-email 2.7.4 In-Reply-To: <20170731104105.GF26667@ulmo> References: <20170731104105.GF26667@ulmo> Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org The early registration of interrupt handler made possible a race condition leading to the usage of an incorrect physical address obtained by reading uninitialized tspi->tx_dma_phys. This patch moves the registration of an interrupt handler further down the code of tegra_spi_probe to make the race infeasible. Found by by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Anton Volkov --- drivers/spi/spi-tegra114.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 08012ae..9a88dca 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1065,29 +1065,18 @@ static int tegra_spi_probe(struct platform_device *pdev) } tspi->phys = r->start; - spi_irq = platform_get_irq(pdev, 0); - tspi->irq = spi_irq; - ret = request_threaded_irq(tspi->irq, tegra_spi_isr, - tegra_spi_isr_thread, IRQF_ONESHOT, - dev_name(&pdev->dev), tspi); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", - tspi->irq); - goto exit_free_master; - } - tspi->clk = devm_clk_get(&pdev->dev, "spi"); if (IS_ERR(tspi->clk)) { dev_err(&pdev->dev, "can not get clock\n"); ret = PTR_ERR(tspi->clk); - goto exit_free_irq; + goto exit_free_master; } tspi->rst = devm_reset_control_get(&pdev->dev, "spi"); if (IS_ERR(tspi->rst)) { dev_err(&pdev->dev, "can not get reset\n"); ret = PTR_ERR(tspi->rst); - goto exit_free_irq; + goto exit_free_master; } tspi->max_buf_size = SPI_FIFO_DEPTH << 2; @@ -1095,7 +1084,7 @@ static int tegra_spi_probe(struct platform_device *pdev) ret = tegra_spi_init_dma_param(tspi, true); if (ret < 0) - goto exit_free_irq; + goto exit_free_master; ret = tegra_spi_init_dma_param(tspi, false); if (ret < 0) goto exit_rx_dma_free; @@ -1105,6 +1094,17 @@ static int tegra_spi_probe(struct platform_device *pdev) init_completion(&tspi->xfer_completion); + spi_irq = platform_get_irq(pdev, 0); + tspi->irq = spi_irq; + ret = request_threaded_irq(tspi->irq, tegra_spi_isr, + tegra_spi_isr_thread, IRQF_ONESHOT, + dev_name(&pdev->dev), tspi); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", + tspi->irq); + goto exit_rx_dma_free; + } + pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { ret = tegra_spi_runtime_resume(&pdev->dev); @@ -1133,11 +1133,10 @@ static int tegra_spi_probe(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) tegra_spi_runtime_suspend(&pdev->dev); + free_irq(spi_irq, tspi); tegra_spi_deinit_dma_param(tspi, false); exit_rx_dma_free: tegra_spi_deinit_dma_param(tspi, true); -exit_free_irq: - free_irq(spi_irq, tspi); exit_free_master: spi_master_put(master); return ret;