From patchwork Tue Apr 4 06:16:55 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Amit Pundir X-Patchwork-Id: 96669 Delivered-To: patch@linaro.org Received: by 10.140.89.233 with SMTP id v96csp47936qgd; Mon, 3 Apr 2017 23:17:09 -0700 (PDT) X-Received: by 10.99.149.16 with SMTP id p16mr21764688pgd.112.1491286629161; Mon, 03 Apr 2017 23:17:09 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m188si16434436pfc.145.2017.04.03.23.17.09; Mon, 03 Apr 2017 23:17:09 -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 S1752447AbdDDGRI (ORCPT + 6 others); Tue, 4 Apr 2017 02:17:08 -0400 Received: from mail-pg0-f45.google.com ([74.125.83.45]:32843 "EHLO mail-pg0-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752416AbdDDGRI (ORCPT ); Tue, 4 Apr 2017 02:17:08 -0400 Received: by mail-pg0-f45.google.com with SMTP id x125so142533343pgb.0 for ; Mon, 03 Apr 2017 23:17:07 -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=ByDKsvkHV7N6esL8WIliiuDZba+hR9hPqAf5033FCKyAv7nrwdvy8ARCYDqhyir5M5 oGnBgD1A/L4sQoJJFuYk2KUeEdgpZPJbEVFnjoPkqWTvImFXRi6pJrPeNORhyuv724y2 Uucs6MV12lDmKg2DIKMLR8q2DFlHukYzGOq6M= 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=Rg8Lx/UTG8Y+exlIoXNfWT2a4SgcvbGJBufTw29r4wyJgorhKDsG5gTjqjpZcl9CXD bHTcduoaXHkISkvox7DVJT35HRU05iNroqkOphPQwEs8Key/oLUdtNyBjwEfBrNSqa4S BzSqldEDu+SzQg5lAL69XP6e768v2jnbo9ltGOX7P9atzRXn/4e7pZEW2ReOqYReP1OI wdzPVUuiHHIO3qKynM7GGCFqf97vb6rM5y4PJl/22e5e/2W9R+Y8eKE6d+mchMINAMbt vx5AUEXeBCyijcwXVw/FJWEyfCasg4im50VxOEibZpCRcldU0Hq+h10BXHHKJk1MA5E+ l5dQ== X-Gm-Message-State: AFeK/H3Q0JDw5MMA0z6WogmH7ZleRMnBTAnIIBASF/wE1o2dY6yzY8H9TqkhIw790qDcbpjd X-Received: by 10.98.59.139 with SMTP id w11mr1176560pfj.230.1491286627150; Mon, 03 Apr 2017 23:17:07 -0700 (PDT) Received: from localhost.localdomain ([106.51.240.246]) by smtp.gmail.com with ESMTPSA id f81sm29247068pfe.61.2017.04.03.23.17.05 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 03 Apr 2017 23:17:06 -0700 (PDT) From: Amit Pundir To: gregkh@linuxfoundation.org Cc: stable@vger.kernel.org, =?utf-8?q?Noralf_Tr=C3=B8nnes?= , Wolfram Sang Subject: [PATCH 07/33] i2c: bcm2835: Protect against unexpected TXW/RXR interrupts Date: Tue, 4 Apr 2017 11:46:55 +0530 Message-Id: <1491286617-31131-4-git-send-email-amit.pundir@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1491286617-31131-1-git-send-email-amit.pundir@linaro.org> References: <1491286617-31131-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; }