From patchwork Tue Apr 3 12:40:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Worsley X-Patchwork-Id: 894590 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-i2c-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="UK4QYn6k"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40FqQK5NDrz9s4X for ; Tue, 3 Apr 2018 23:17:45 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932236AbeDCNRp (ORCPT ); Tue, 3 Apr 2018 09:17:45 -0400 Received: from mail-pl0-f65.google.com ([209.85.160.65]:44257 "EHLO mail-pl0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932162AbeDCNRo (ORCPT ); Tue, 3 Apr 2018 09:17:44 -0400 Received: by mail-pl0-f65.google.com with SMTP id b6-v6so6757620pla.11 for ; Tue, 03 Apr 2018 06:17:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:from:date:subject; bh=dCVj3YnZXekAt2yf976d9LYD4fecqeJ2ZQb5onk79TM=; b=UK4QYn6keEM/AQ/2PPAPv3lEU5nz4rtediBv99qb5QX4YMsa46LBczjMvm8TNDPV7J BoZWRRXX8UDjEcyC3eev3tIozRBT6RZHJMt2HjXfb5srf+GgODakO4y+HAKhDkzfosJo t8/ZXA3Gd1UDTFcSAt+X58z2AB9HRoe8cqYiWKtTCvJ1JyO/7ux323RZWLQi+dBzCpwP PyANE+vxNfxSHq/aKk4WejLoz14TL7Zyky2u9iOyI3bObQ7U/xpaI/5elyq5asgocOLd qDNS3GQctLhe5ZDHWTY+mNlMH1lEGLufx67EflUbpe+ibfig2iC2MAbQYqzd8xhs++w5 Hrrw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:from:date:subject; bh=dCVj3YnZXekAt2yf976d9LYD4fecqeJ2ZQb5onk79TM=; b=fM1moHBBsm2L8mSSLWmzHtxHCgcBMAWoiihg+AuhLZIhcJXQGRRM7hxtuC1LEnRe3q mRI1BuALbS89nQxKy768KHm3Aa3uO55utJGtXcobSk4/+x9vrCtFMat5LrOMiDmCRKxD jk4UK0XXa4K0R+ysvEJFpDrY8aGlzed8VrnAiHGUG2ZWJEIj6JI+7++cLC9D2fDPAt3q HoO2XGCemZmFmfzkz5+SaMVExjZNMnj7pfflPfUj7S8dRxbsUsE10NsJjIIMCRKXVLxv k38kP7hhTgn6pBnu0Q8mYjQZWMuULV1gJIpm4byCvpHCIdiWFZ5m/Wj9fYsOJ/giH3qS 1L+w== X-Gm-Message-State: AElRT7HyXeuGMpvcq/hye8td8EUZcvncxyV5mU2snojDmzZoVSbQy+D4 rXf8FTCQ6Ty+qUYcHeq8DF8= X-Google-Smtp-Source: AIpwx48CwTMjT0BqbFm6T1MaOWT3JxL/YHTkeIXi1FdM22RCpEAr1ZLQYZDr/PIkR0Fmm+Vh+tL/1g== X-Received: by 10.98.133.212 with SMTP id m81mr10596263pfk.61.1522761464151; Tue, 03 Apr 2018 06:17:44 -0700 (PDT) Received: from localhost (27-32-189-129.static.tpgi.com.au. [27.32.189.129]) by smtp.gmail.com with ESMTPSA id a81sm5559405pfc.168.2018.04.03.06.17.42 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 03 Apr 2018 06:17:43 -0700 (PDT) Message-ID: <5ac37ef7.5466620a.2f985.b195@mx.google.com> From: Andrew Worsley Date: Tue, 3 Apr 2018 22:40:01 +1000 Subject: [PATCH 2/2] I2c receive buffer overrun bugfix - clear hold bit before end. To: unlisted-recipients:; (no To-header on input) Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org The i2c-cadence driver was not clearing the hold bit before the i2c transfer finished. This caused the Zynq hardware to perform another transfer even even though the transfer register was zero. The transfer register then wraps over to something like 255 and keeps transferring more data. Before the received data checking code it would continue to copy the extra bytes past the end of the receive buffer. The fix removes the hold bit just before reading the byte that allows the last part of the transfer to completely fit into the FIFO. As soon as the last data is read the hardware will correctly release the clock and data lines signaling an i2c stop and the transfer size register will be zero. --- drivers/i2c/busses/i2c-cadence.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 81f924d4adcb..925f77dfded8 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -430,6 +430,10 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr) ((isr_status & CDNS_I2C_IXR_COMP) || (isr_status & CDNS_I2C_IXR_DATA))) { unsigned char *p = id->p_recv_buf; + int check_hold = 0; + + if ((id->recv_count <= 2*CDNS_I2C_FIFO_DEPTH) && !id->bus_hold_flag) + check_hold = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) & CDNS_I2C_CR_HOLD; /* Read data if receive data valid is set */ while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_RXDV) { @@ -438,9 +442,6 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr) * RX data left is less than FIFO depth, unless * repeated start is selected. */ - if ((id->recv_count < CDNS_I2C_FIFO_DEPTH) && - !id->bus_hold_flag) - cdns_i2c_clear_bus_hold(id); if (id->recv_count == 0) { pr_notice("%s: i2c receive buffer filled : %u aborting transfer %p - %p\n", @@ -450,6 +451,8 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr) *(id->p_recv_buf)++ = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET); + if (check_hold && id->recv_count == CDNS_I2C_FIFO_DEPTH + 1) + cdns_i2c_clear_bus_hold(id); id->recv_count--; id->curr_recv_count--;