From patchwork Thu Aug 24 21:23:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roman Bacik X-Patchwork-Id: 13364764 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 19C86C3DA6F for ; Thu, 24 Aug 2023 21:24:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:Content-Type: List-Subscribe:List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id: MIME-Version:Message-Id:Date:Subject:Cc:To:From:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=ea7hUB0qNwVcFuEgs8U2zvu5OK2KoO9DPqh77fX7pSA=; b=KyQ 5zFGJjluWgg1nRsH5uYRWN94oC3hLO41UAqFO8rUYXXO7PjqXxzAbEKy0WE2TFUBOm3klkPQahGW/ me9gL6pnTMAhJKsy+Gr4Xsifyg8Tj7nGmQFAZ7VLkjet7eUD6zXk26uaOaO0/Syro0BqzIkjOonrL BHdgyXDf+7J6DtsRdyaNk7rKPrQdkImkfCF1nVRKpaSTk1dXINJWgaJptSzD/Uc31wCdSHJp83iRy fiZxCvN36/jiDUJ5ztC0oO3iLDTG6QlxI+2BHClm2cdKhRQjZQ0cTfmKNAFwzYRi0jMY0X9lOHGkA 89IbaT1IkAwRBa0vO3D+rTwMgmuYdaA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1qZHoO-003pRY-2E; Thu, 24 Aug 2023 21:24:16 +0000 Received: from mail-qk1-x72d.google.com ([2607:f8b0:4864:20::72d]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1qZHoL-003pR0-0w for linux-arm-kernel@lists.infradead.org; Thu, 24 Aug 2023 21:24:15 +0000 Received: by mail-qk1-x72d.google.com with SMTP id af79cd13be357-76ef27a8e4dso18392085a.1 for ; Thu, 24 Aug 2023 14:24:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1692912248; x=1693517048; h=mime-version:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=YzAfe266yxVHtoivP8U1eBMYR7lPsjg+8YyJaE9wews=; b=St/ZOPC//k8QAd7hNG5wbClnqPtHdHh8U/Ekox+3x54RQCtZyDnLbUOkp4/kD26cZi vFXRhoGGQF0FJRsRqLCIxeNnJjyaGHpJv8YNWwd4gGqHHHgOHwEvHc7PUechfFKfRj+i tskwiTVoToBirYmMww1QyXHERbv/ZvFFTc1+Q= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1692912248; x=1693517048; h=mime-version:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=YzAfe266yxVHtoivP8U1eBMYR7lPsjg+8YyJaE9wews=; b=eWCOLpnkPaH8aKKe+8r8WGrV9KoQ5FhnjkSeIqOVOTod3HyYbm09yHdNxyYMiGDLhe /8y3OUpU6ycmk5Vv/swvDmqxDo3hD0Q2hJmq8Bmv/+BSc+2Zl+6MrqVM2AIADdRsP7dk berSxVqPv6hurK9VNZhSgIM5YzquEOMcBqLuibj/be0U25PTyasXhOCW4jZTwWokv9DJ RDbz0pLZ3hbQEOGPnPkjZqxab9BkW33JyD3nQBZ/rInQDkQ+HHbBjJjG5xB8FRTEBPNv ZGPuH9xga166zjM5TckLpkfPOgwjVkeoFVrHanmxrEYLVGnZAdiOBOtVFrr8jlR4TJmM FurA== X-Gm-Message-State: AOJu0YyVXu2/yYV6UrgIappzrI5frZYWpSmg8uXwscORmha1i0tFdTKz GVp72x8+J/SPRG3DQrW5XXhvWZB5qK7bBYvceDS9l/DBThJ9uoo7caK0uuu1wSBDypFDLV3Xhdu rp1Qmm5WDtBjDllKphjQ/OzLHzA== X-Google-Smtp-Source: AGHT+IGWCYDrAVN1oLpPDbDF+nFArybQctWBj3Hy38VvwWk0SHX6eJ20UUVcTL/OVWcTHYiAvOgdlw== X-Received: by 2002:ad4:5149:0:b0:631:f426:a4ab with SMTP id g9-20020ad45149000000b00631f426a4abmr16429962qvq.49.1692912248472; Thu, 24 Aug 2023 14:24:08 -0700 (PDT) Received: from HDYH7M3.Broadcom.net ([192.19.161.248]) by smtp.gmail.com with ESMTPSA id j15-20020a0ce00f000000b0064713c8fab7sm75769qvk.59.2023.08.24.14.24.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 24 Aug 2023 14:24:07 -0700 (PDT) From: roman.bacik@broadcom.com To: andi.shyti@kernel.org, rjui@broadcom.com, sbranden@broadcom.com Cc: bcm-kernel-feedback-list@broadcom.com, linux-i2c@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Roman Bacik Subject: [PATCH] i2c: iproc: handle invalid slave state Date: Thu, 24 Aug 2023 14:23:51 -0700 Message-Id: <20230824212351.24346-1-roman.bacik@broadcom.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230824_142413_435500_24298A11 X-CRM114-Status: GOOD ( 24.63 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Roman Bacik Add the code to handle an invalid state when both bits S_RX_EVENT (indicating a transaction) and S_START_BUSY (indicating the end of transaction - transition of START_BUSY from 1 to 0) are set in the interrupt status register during a slave read. Signed-off-by: Roman Bacik Fixes: 1ca1b4516088 ("i2c: iproc: handle Master aborted error") Acked-by: Ray Jui --- drivers/i2c/busses/i2c-bcm-iproc.c | 133 ++++++++++++++++------------- 1 file changed, 75 insertions(+), 58 deletions(-) diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 05c80680dff4..68438d4e5d73 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -316,26 +316,44 @@ static void bcm_iproc_i2c_slave_init( iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); } -static void bcm_iproc_i2c_check_slave_status( - struct bcm_iproc_i2c_dev *iproc_i2c) +static bool bcm_iproc_i2c_check_slave_status + (struct bcm_iproc_i2c_dev *iproc_i2c, u32 status) { u32 val; + bool recover = false; - val = iproc_i2c_rd_reg(iproc_i2c, S_CMD_OFFSET); - /* status is valid only when START_BUSY is cleared after it was set */ - if (val & BIT(S_CMD_START_BUSY_SHIFT)) - return; + /* check slave transmit status only if slave is transmitting */ + if (!iproc_i2c->slave_rx_only) { + val = iproc_i2c_rd_reg(iproc_i2c, S_CMD_OFFSET); + /* status is valid only when START_BUSY is cleared */ + if (!(val & BIT(S_CMD_START_BUSY_SHIFT))) { + val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK; + if (val == S_CMD_STATUS_TIMEOUT || + val == S_CMD_STATUS_MASTER_ABORT) { + dev_warn(iproc_i2c->device, + (val == S_CMD_STATUS_TIMEOUT) ? + "slave random stretch time timeout\n" : + "Master aborted read transaction\n"); + recover = true; + } + } + } + + /* RX_EVENT is not valid when START_BUSY is set */ + if ((status & BIT(IS_S_RX_EVENT_SHIFT)) && + (status & BIT(IS_S_START_BUSY_SHIFT))) { + dev_warn(iproc_i2c->device, "Slave aborted read transaction\n"); + recover = true; + } - val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK; - if (val == S_CMD_STATUS_TIMEOUT || val == S_CMD_STATUS_MASTER_ABORT) { - dev_err(iproc_i2c->device, (val == S_CMD_STATUS_TIMEOUT) ? - "slave random stretch time timeout\n" : - "Master aborted read transaction\n"); + if (recover) { /* re-initialize i2c for recovery */ bcm_iproc_i2c_enable_disable(iproc_i2c, false); bcm_iproc_i2c_slave_init(iproc_i2c, true); bcm_iproc_i2c_enable_disable(iproc_i2c, true); } + + return recover; } static void bcm_iproc_i2c_slave_read(struct bcm_iproc_i2c_dev *iproc_i2c) @@ -420,48 +438,6 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, u32 val; u8 value; - /* - * Slave events in case of master-write, master-write-read and, - * master-read - * - * Master-write : only IS_S_RX_EVENT_SHIFT event - * Master-write-read: both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT - * events - * Master-read : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT - * events or only IS_S_RD_EVENT_SHIFT - * - * iproc has a slave rx fifo size of 64 bytes. Rx fifo full interrupt - * (IS_S_RX_FIFO_FULL_SHIFT) will be generated when RX fifo becomes - * full. This can happen if Master issues write requests of more than - * 64 bytes. - */ - if (status & BIT(IS_S_RX_EVENT_SHIFT) || - status & BIT(IS_S_RD_EVENT_SHIFT) || - status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) { - /* disable slave interrupts */ - val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); - val &= ~iproc_i2c->slave_int_mask; - iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); - - if (status & BIT(IS_S_RD_EVENT_SHIFT)) - /* Master-write-read request */ - iproc_i2c->slave_rx_only = false; - else - /* Master-write request only */ - iproc_i2c->slave_rx_only = true; - - /* schedule tasklet to read data later */ - tasklet_schedule(&iproc_i2c->slave_rx_tasklet); - - /* - * clear only IS_S_RX_EVENT_SHIFT and - * IS_S_RX_FIFO_FULL_SHIFT interrupt. - */ - val = BIT(IS_S_RX_EVENT_SHIFT); - if (status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) - val |= BIT(IS_S_RX_FIFO_FULL_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, val); - } if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) { iproc_i2c->tx_underrun++; @@ -493,8 +469,9 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, * less than PKT_LENGTH bytes were output on the SMBUS */ iproc_i2c->slave_int_mask &= ~BIT(IE_S_TX_UNDERRUN_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, - iproc_i2c->slave_int_mask); + val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); + val &= ~BIT(IE_S_TX_UNDERRUN_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); /* End of SMBUS for Master Read */ val = BIT(S_TX_WR_STATUS_SHIFT); @@ -515,9 +492,49 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, BIT(IS_S_START_BUSY_SHIFT)); } - /* check slave transmit status only if slave is transmitting */ - if (!iproc_i2c->slave_rx_only) - bcm_iproc_i2c_check_slave_status(iproc_i2c); + /* if the controller has been reset, immediately return from the ISR */ + if (bcm_iproc_i2c_check_slave_status(iproc_i2c, status)) + return true; + + /* + * Slave events in case of master-write, master-write-read and, + * master-read + * + * Master-write : only IS_S_RX_EVENT_SHIFT event + * Master-write-read: both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT + * events + * Master-read : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT + * events or only IS_S_RD_EVENT_SHIFT + * + * iproc has a slave rx fifo size of 64 bytes. Rx fifo full interrupt + * (IS_S_RX_FIFO_FULL_SHIFT) will be generated when RX fifo becomes + * full. This can happen if Master issues write requests of more than + * 64 bytes. + */ + if (status & BIT(IS_S_RX_EVENT_SHIFT) || + status & BIT(IS_S_RD_EVENT_SHIFT) || + status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) { + /* disable slave interrupts */ + val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); + val &= ~iproc_i2c->slave_int_mask; + iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); + + if (status & BIT(IS_S_RD_EVENT_SHIFT)) + /* Master-write-read request */ + iproc_i2c->slave_rx_only = false; + else + /* Master-write request only */ + iproc_i2c->slave_rx_only = true; + + /* schedule tasklet to read data later */ + tasklet_schedule(&iproc_i2c->slave_rx_tasklet); + + /* clear IS_S_RX_FIFO_FULL_SHIFT interrupt */ + if (status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) { + val = BIT(IS_S_RX_FIFO_FULL_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, val); + } + } return true; }