From patchwork Wed Apr 5 10:31:58 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Amit Pundir X-Patchwork-Id: 96808 Delivered-To: patch@linaro.org Received: by 10.140.89.233 with SMTP id v96csp195796qgd; Wed, 5 Apr 2017 03:32:50 -0700 (PDT) X-Received: by 10.98.138.80 with SMTP id y77mr7437085pfd.183.1491388370870; Wed, 05 Apr 2017 03:32:50 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i62si20247750pli.318.2017.04.05.03.32.50; Wed, 05 Apr 2017 03:32:50 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=stable-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933238AbdDEKct (ORCPT + 6 others); Wed, 5 Apr 2017 06:32:49 -0400 Received: from mail-pg0-f49.google.com ([74.125.83.49]:36259 "EHLO mail-pg0-f49.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933419AbdDEKcm (ORCPT ); Wed, 5 Apr 2017 06:32:42 -0400 Received: by mail-pg0-f49.google.com with SMTP id g2so5932136pge.3 for ; Wed, 05 Apr 2017 03:32:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=yI/p3Ge8PF7RcWpNL9syTFN8sRMSFRYur/RDSmIFjwY=; b=LFXlsXbve2Z7XP1rQxT7484JDqEJWNtAAZgH/Hc3iFyq99fTD0f8cWf8i3ox7RRt+n 5HXR8BGCxrGmil43hhy0WZnoDPzepdgXH1bYSykztI3P869BiaqkuUMUYkeMC1s3dhSQ Tfb+X/6Ftmr+Psu2UR7lqJ/1cntKHa+C5EmWs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=yI/p3Ge8PF7RcWpNL9syTFN8sRMSFRYur/RDSmIFjwY=; b=NnaPT3LQi0CXP/DGfAcbBi8QTbNFXYx5erkHvYnymWcvA3gvEFGsCu376Dqs4vcagP br3/Sa1KeCQLVROfezS6GqynKHwYWcnMWLWDnH1AaFjvusCiC/Eb0cEqm4+H+Bmndq+L gK/1Kh8fDe+Krjo6ycqhERhQr0tVPIx2oyNlVxQkuUSAfu1nouoNL8Zg25pROVHAl7Kh R8zCR78/aPk2gV/pLatcloJrZq+3uTt7RvjcHv+jexHeT/mARnRPMmNNQdl/k4htdEp6 vknOssR83+O8so80re3z/6ecyfyj/fhBL1/CEeyVAbonHJk13efdarMIb4U0riehFQRK WoRw== X-Gm-Message-State: AFeK/H2qr8WCYgnE1kjPoE7SMp9kRg50uFAE9x5stBWLVcJmOMzVhzQf5MAXhwG+SB9ZRbEG X-Received: by 10.98.72.199 with SMTP id q68mr28671731pfi.152.1491388361140; Wed, 05 Apr 2017 03:32:41 -0700 (PDT) Received: from localhost.localdomain ([106.51.240.246]) by smtp.gmail.com with ESMTPSA id a62sm36732075pgc.60.2017.04.05.03.32.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 05 Apr 2017 03:32:40 -0700 (PDT) From: Amit Pundir To: stable@vger.kernel.org Cc: gregkh@linuxfoundation.org, =?utf-8?q?Noralf_Tr=C3=B8nnes?= , Wolfram Sang Subject: [PATCH v2 for-4.9 06/32] i2c: bcm2835: Protect against unexpected TXW/RXR interrupts Date: Wed, 5 Apr 2017 16:01:58 +0530 Message-Id: <1491388344-13521-7-git-send-email-amit.pundir@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1491388344-13521-1-git-send-email-amit.pundir@linaro.org> References: <1491388344-13521-1-git-send-email-amit.pundir@linaro.org> MIME-Version: 1.0 Sender: stable-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org From: Noralf Trønnes If an unexpected TXW or RXR interrupt occurs (msg_buf_remaining == 0), the driver has no way to fill/drain the FIFO to stop the interrupts. In this case the controller has to be disabled and the transfer completed to avoid hang. (CLKT | ERR) and DONE interrupts are completed in their own paths, and the controller is disabled in the transfer function after completion. Unite the code paths and do disabling inside the interrupt routine. Clear interrupt status bits in the united completion path instead of trying to do it on every interrupt which isn't necessary. Only CLKT, ERR and DONE can be cleared that way. Add the status value to the error value in case of TXW/RXR errors to distinguish them from the other S_LEN error. Signed-off-by: Noralf Trønnes Reviewed-by: Eric Anholt Signed-off-by: Wolfram Sang (cherry picked from commit d4030d75c7cbb434b2a3e5f6af5065879d2615a5) Signed-off-by: Amit Pundir --- drivers/i2c/busses/i2c-bcm2835.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) -- 2.7.4 diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index f283b71..d2ba1a4 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -50,8 +50,6 @@ #define BCM2835_I2C_S_CLKT BIT(9) #define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error reporting */ -#define BCM2835_I2C_BITMSK_S 0x03FF - #define BCM2835_I2C_CDIV_MIN 0x0002 #define BCM2835_I2C_CDIV_MAX 0xFFFE @@ -111,20 +109,26 @@ static void bcm2835_drain_rxfifo(struct bcm2835_i2c_dev *i2c_dev) } } +/* + * Note about I2C_C_CLEAR on error: + * The I2C_C_CLEAR on errors will take some time to resolve -- if you were in + * non-idle state and I2C_C_READ, it sets an abort_rx flag and runs through + * the state machine to send a NACK and a STOP. Since we're setting CLEAR + * without I2CEN, that NACK will be hanging around queued up for next time + * we start the engine. + */ + static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) { struct bcm2835_i2c_dev *i2c_dev = data; u32 val, err; val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); - val &= BCM2835_I2C_BITMSK_S; - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, val); err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR); if (err) { i2c_dev->msg_err = err; - complete(&i2c_dev->completion); - return IRQ_HANDLED; + goto complete; } if (val & BCM2835_I2C_S_DONE) { @@ -137,21 +141,38 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) i2c_dev->msg_err = BCM2835_I2C_S_LEN; else i2c_dev->msg_err = 0; - complete(&i2c_dev->completion); - return IRQ_HANDLED; + goto complete; } if (val & BCM2835_I2C_S_TXW) { + if (!i2c_dev->msg_buf_remaining) { + i2c_dev->msg_err = val | BCM2835_I2C_S_LEN; + goto complete; + } + bcm2835_fill_txfifo(i2c_dev); return IRQ_HANDLED; } if (val & BCM2835_I2C_S_RXR) { + if (!i2c_dev->msg_buf_remaining) { + i2c_dev->msg_err = val | BCM2835_I2C_S_LEN; + goto complete; + } + bcm2835_drain_rxfifo(i2c_dev); return IRQ_HANDLED; } return IRQ_NONE; + +complete: + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, BCM2835_I2C_S_CLKT | + BCM2835_I2C_S_ERR | BCM2835_I2C_S_DONE); + complete(&i2c_dev->completion); + + return IRQ_HANDLED; } static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, @@ -181,8 +202,9 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, time_left = wait_for_completion_timeout(&i2c_dev->completion, BCM2835_I2C_TIMEOUT); - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); if (!time_left) { + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, + BCM2835_I2C_C_CLEAR); dev_err(i2c_dev->dev, "i2c transfer timed out\n"); return -ETIMEDOUT; }