From patchwork Wed Jul 19 19:23:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?TsOtY29sYXMgRi4gUi4gQS4gUHJhZG8=?= X-Patchwork-Id: 13319398 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 4F20BC04A94 for ; Wed, 19 Jul 2023 19:23:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: Content-Type:MIME-Version:Message-ID:Date:Subject:Cc:To:From:Reply-To: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Owner; bh=wvp7Fzom6G8eQBNnvii+v1anqp2ftWoWgCCVQB4T9M4=; b=GfzrLkVCtP+PMGa1kNMUUYoPHB 8Q61j3EKGiKJ3IpOq7Ifb/hu+oxjycmE7b9ctc1HAp4Yx9MqZbM0k8Qt1RP3iKqE/iqKz49heQg/O pq2ByCb5OH0aaND0KeEriD0ZdCiRaVUBQKclaeFaBL/6s3XJHk/ToHnjURc0MsPcEfck/7bvY9l/8 uf6JT48OXNrJ7fB2OiIbHiT+8aeJ34AglhV7vYHpMwk45/W2kYxQF5bx0GTEF+Z/r8YE0QcCzyU1L icUHNXoIv8v2EkD/5pLqZ8bu/uriN4TwlJcFVcDUJQph0D5YFCwn4agc9qp23zzSCKHkL8a5CKIXK QA/5NKAw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1qMCls-008fV5-3A; Wed, 19 Jul 2023 19:23:37 +0000 Received: from madras.collabora.co.uk ([46.235.227.172]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1qMCln-008fSX-31; Wed, 19 Jul 2023 19:23:33 +0000 Received: from notapiano.myfiosgateway.com (zone.collabora.co.uk [167.235.23.81]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: nfraprado) by madras.collabora.co.uk (Postfix) with ESMTPSA id 041DE6606F97; Wed, 19 Jul 2023 20:23:23 +0100 (BST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1689794605; bh=9RSSdAc6acLEaTRxg2Yr+1H4A/wy2mLAUFDBTbvZP5s=; h=From:To:Cc:Subject:Date:From; b=MUtWUYLgNUeuwHYSntirqooUNHyZ0BrrrcNJ5H3f6QCxJiYVa2lKNGj8wET4RhpJn dr6a6Z4WvHSF7vkOflmuI0WUqBHgEfTb2TqSkuOKEgHJJKki8kJyk617mSISwLbg13 CcN2csyNS2VTdrt8iaQX+l2/YRmUs2j9B9A/mHy5mfJgGtnpQur7plUxthwm2bU3Je i2rGg6kO4ekhiyc6UK95BdF10Dfo4kp3o0hXP5XAAnXViA+a556AeMnbGNtTAsXGg+ Hw6WlTpXYkaaFcOncKkkCNqQBdA4aYXd9o6Fos1SaO7IrWIMS3e+wrHbWDyHyb0ihX /K7HNmSy4q+NA== From: =?utf-8?b?TsOtY29sYXMgRi4gUi4gQS4gUHJhZG8=?= To: Stephen Boyd Cc: kernel@collabora.com, AngeloGioacchino Del Regno , =?utf-8?b?TsOtY29sYXMgRi4gUi4gQS4gUHJhZG8=?= , Greg Kroah-Hartman , Hsin-Hsiung Wang , James Lo , Matthias Brugger , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org Subject: [PATCH v2] spmi: mtk-pmif: Serialize PMIF status check and command submission Date: Wed, 19 Jul 2023 15:23:16 -0400 Message-ID: <20230719192319.252617-1-nfraprado@collabora.com> X-Mailer: git-send-email 2.41.0 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230719_122332_256768_1C92AFA0 X-CRM114-Status: GOOD ( 25.00 ) X-BeenThere: linux-mediatek@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-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org Before writing the read or write command to the SPMI arbiter through the PMIF interface, the current status of the channel is checked to ensure it is idle. However, since the status only changes from idle when the command is written, it is possible for two concurrent calls to determine that the channel is idle and simultaneously send their commands. At this point the PMIF interface hangs, with the status register no longer being updated, and thus causing all subsequent operations to time out. This was observed on the mt8195-cherry-tomato-r2 machine, particularly after commit 46600ab142f8 ("regulator: Set PROBE_PREFER_ASYNCHRONOUS for drivers between 5.10 and 5.15") was applied, since then the two MT6315 devices present on the SPMI bus would probe assynchronously and sometimes (during probe or at a later point) read the bus simultaneously, breaking the PMIF interface and consequently slowing down the whole system. To fix the issue at its root cause, introduce locking around the channel status check and the command write, so that both become an atomic operation, preventing race conditions between two (or more) SPMI bus read/write operations. A spinlock is used since this is a fast bus, as indicated by the usage of the atomic variant of readl_poll, and '.fast_io = true' being used in the mt6315 driver, so spinlocks are already used for the regmap access. Fixes: b45b3ccef8c0 ("spmi: mediatek: Add support for MT6873/8192") Signed-off-by: NĂ­colas F. R. A. Prado --- Changes in v2: - Added missing spin_unlocks to error paths - Moved memcpy outside spinlock region in the write_cmd function - Reworded commit message to make clear that issue can happen at any point in runtime, not only during boot drivers/spmi/spmi-mtk-pmif.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/spmi/spmi-mtk-pmif.c b/drivers/spmi/spmi-mtk-pmif.c index b3c991e1ea40..78b69e0b5c81 100644 --- a/drivers/spmi/spmi-mtk-pmif.c +++ b/drivers/spmi/spmi-mtk-pmif.c @@ -50,6 +50,7 @@ struct pmif { struct clk_bulk_data clks[PMIF_MAX_CLKS]; size_t nclks; const struct pmif_data *data; + spinlock_t lock; }; static const char * const pmif_clock_names[] = { @@ -314,6 +315,7 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, struct ch_reg *inf_reg; int ret; u32 data, cmd; + unsigned long flags; /* Check for argument validation. */ if (sid & ~0xf) { @@ -334,12 +336,14 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, else return -EINVAL; + spin_lock_irqsave(&arb->lock, flags); /* Wait for Software Interface FSM state to be IDLE. */ inf_reg = &arb->chan; ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta], data, GET_SWINF(data) == SWINF_IDLE, PMIF_DELAY_US, PMIF_TIMEOUT_US); if (ret < 0) { + spin_unlock_irqrestore(&arb->lock, flags); /* set channel ready if the data has transferred */ if (pmif_is_fsm_vldclr(arb)) pmif_writel(arb, 1, inf_reg->ch_rdy); @@ -350,6 +354,7 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, /* Send the command. */ cmd = (opc << 30) | (sid << 24) | ((len - 1) << 16) | addr; pmif_writel(arb, cmd, inf_reg->ch_send); + spin_unlock_irqrestore(&arb->lock, flags); /* * Wait for Software Interface FSM state to be WFVLDCLR, @@ -376,7 +381,8 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, struct pmif *arb = spmi_controller_get_drvdata(ctrl); struct ch_reg *inf_reg; int ret; - u32 data, cmd; + u32 data, wdata, cmd; + unsigned long flags; if (len > 4) { dev_err(&ctrl->dev, "pmif supports 1..4 bytes per trans, but:%zu requested", len); @@ -394,12 +400,17 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, else return -EINVAL; + /* Set the write data. */ + memcpy(&wdata, buf, len); + + spin_lock_irqsave(&arb->lock, flags); /* Wait for Software Interface FSM state to be IDLE. */ inf_reg = &arb->chan; ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta], data, GET_SWINF(data) == SWINF_IDLE, PMIF_DELAY_US, PMIF_TIMEOUT_US); if (ret < 0) { + spin_unlock_irqrestore(&arb->lock, flags); /* set channel ready if the data has transferred */ if (pmif_is_fsm_vldclr(arb)) pmif_writel(arb, 1, inf_reg->ch_rdy); @@ -407,13 +418,12 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, return ret; } - /* Set the write data. */ - memcpy(&data, buf, len); - pmif_writel(arb, data, inf_reg->wdata); + pmif_writel(arb, wdata, inf_reg->wdata); /* Send the command. */ cmd = (opc << 30) | BIT(29) | (sid << 24) | ((len - 1) << 16) | addr; pmif_writel(arb, cmd, inf_reg->ch_send); + spin_unlock_irqrestore(&arb->lock, flags); return 0; } @@ -488,6 +498,8 @@ static int mtk_spmi_probe(struct platform_device *pdev) arb->chan.ch_send = PMIF_SWINF_0_ACC + chan_offset; arb->chan.ch_rdy = PMIF_SWINF_0_VLD_CLR + chan_offset; + spin_lock_init(&arb->lock); + platform_set_drvdata(pdev, ctrl); err = spmi_controller_add(ctrl);