[v3,2/6] spi: spi-sun4i: sun4i_spi_fill_fifo(): always apply A10 FIFO fill level workaround
| Message ID | 20260914-spi-sun4i-fixes-v3-2-9fe919d5cecf@pengutronix.de (mailing list archive) |
|---|---|
| State | New |
| Headers |
Return-Path: <linux-sunxi+bounces-25901-sunxi=pue.re@lists.linux.dev> X-Original-To: noreply@patchwork.local Delivered-To: noreply@patchwork.local Received: from tor.lore.kernel.org (tor.lore.kernel.org [172.105.105.114]) by mxe881.netcup.net (Postfix) with ESMTPS id 6AE821C347D for <noreply@patchwork.local>; Mon, 14 Sep 2026 17:47:35 +0200 (CEST) Authentication-Results: mxe881; spf=pass (sender IP is 172.105.105.114) smtp.mailfrom=linux-sunxi+bounces-25901-noreply=patchwork.local@lists.linux.dev smtp.helo=tor.lore.kernel.org Received-SPF: pass (mxe881: domain of lists.linux.dev designates 172.105.105.114 as permitted sender) client-ip=172.105.105.114; envelope-from=linux-sunxi+bounces-25901-noreply=patchwork.local@lists.linux.dev; helo=tor.lore.kernel.org; Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org [100.90.174.1]) by tor.lore.kernel.org (Postfix) with ESMTP id 9C89D162EEC for <noreply@patchwork.local>; Mon, 14 Sep 2026 15:38:13 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id BFA01488DBE; Mon, 14 Sep 2026 15:36:13 +0000 (UTC) X-Original-To: linux-sunxi@lists.linux.dev Received: from mx1.white.stw.pengutronix.de (mx1.white.stw.pengutronix.de [185.203.200.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1136547126D for <linux-sunxi@lists.linux.dev>; Mon, 14 Sep 2026 15:36:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.200.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789400173; cv=none; b=FcDzIfcWzWvVjH0rSrG85t9WhUsZAT9MZQ2znEGKLEUFo656fchLwMqfkuFDldKAupLrDxJySKdTgl2mslfaZvRtCAyE0VcUxDOJmj4iQxCOrUvX2BHSw6ZhWtd80OV3cIZYfH2NHVLKJVSE8vhGCO21bctSzt2VBNfXJ2RfHBA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789400173; c=relaxed/simple; bh=INggQxZYiVkmmrcf18hh/UbfftJVWhOUDR6qg+05XwI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KWCzYvdgnPGYlJzfrbylr/hgGSJGojfrco8HYkyvOnXT705GlyTxZEwDNwHvnwy4lDp5w6sP4umRMlBARWG8L7gEu75AgtmsnNagCju7ORAnjPMOKKz8boBbqaJsWq9quom/GezGY3LM6PvXhApTQRLK0lv60b1atP7L7aWiuWo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.200.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de X-PTX-Original-Recipient: mkl@pengutronix.de X-PTX-Original-Recipient: jre@pengutronix.de X-PTX-Original-Recipient: kernel@pengutronix.de X-PTX-Original-Recipient: o.schinagl@ultimaker.com X-PTX-Original-Recipient: wens@kernel.org X-PTX-Original-Recipient: broonie@kernel.org X-PTX-Original-Recipient: mripard@kernel.org X-PTX-Original-Recipient: linux-arm-kernel@lists.infradead.org X-PTX-Original-Recipient: linux-kernel@vger.kernel.org X-PTX-Original-Recipient: linux-spi@vger.kernel.org X-PTX-Original-Recipient: linux-sunxi@lists.linux.dev X-PTX-Original-Recipient: jernej.skrabec@gmail.com X-PTX-Original-Recipient: mr.nuke.me@gmail.com X-PTX-Original-Recipient: samuel@sholland.org Received: from drehscheibe.grey.stw.pengutronix.de (drehscheibe.grey.stw.pengutronix.de [IPv6:2a0a:edc0:0:c01:1d::a2]) (Authenticated sender: relay-from-drehscheibe.grey.stw.pengutronix.de) by mx1.white.stw.pengutronix.de (Postfix) with ESMTPSA id 2B7BA202889; Mon, 14 Sep 2026 17:36:08 +0200 (CEST) Received: from dude04.red.stw.pengutronix.de ([2a0a:edc0:0:1101:1d::ac]) by drehscheibe.grey.stw.pengutronix.de with esmtp (Exim 4.96) (envelope-from <jre@pengutronix.de>) id 1x68j2-000vXD-0H; Mon, 14 Sep 2026 17:36:08 +0200 From: Jonas Rebmann <jre@pengutronix.de> Date: Mon, 14 Sep 2026 17:35:56 +0200 Subject: [PATCH v3 2/6] spi: spi-sun4i: sun4i_spi_fill_fifo(): always apply A10 FIFO fill level workaround Precedence: bulk X-Mailing-List: linux-sunxi@lists.linux.dev List-Id: <linux-sunxi.lists.linux.dev> List-Subscribe: <mailto:linux-sunxi+subscribe@lists.linux.dev> List-Unsubscribe: <mailto:linux-sunxi+unsubscribe@lists.linux.dev> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260914-spi-sun4i-fixes-v3-2-9fe919d5cecf@pengutronix.de> References: <20260914-spi-sun4i-fixes-v3-0-9fe919d5cecf@pengutronix.de> In-Reply-To: <20260914-spi-sun4i-fixes-v3-0-9fe919d5cecf@pengutronix.de> To: Mark Brown <broonie@kernel.org>, Chen-Yu Tsai <wens@kernel.org>, Jernej Skrabec <jernej.skrabec@gmail.com>, Samuel Holland <samuel@sholland.org>, Maxime Ripard <mripard@kernel.org>, Alexandru Gagniuc <mr.nuke.me@gmail.com>, Olliver Schinagl <o.schinagl@ultimaker.com> Cc: linux-spi@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org, kernel@pengutronix.de, Marc Kleine-Budde <mkl@pengutronix.de>, Jonas Rebmann <jre@pengutronix.de> X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=2965; i=jre@pengutronix.de; h=from:subject:message-id; bh=rKlhrsReCvLLuuOh1xsyoda4LwKg4i1Q+rNz/5zEokw=; b=owGbwMvMwCV2ZcYT3onnbjcwnlZLYshaIZJapfPtPof/+33icrZsfekyvw5OeNyp4XHDo+RAx QRjv70zOkpZGMS4GGTFFFli1eQUhIz9r5tV2sXCzGFlAhnCwMUpABPpE2D4H/rpnJn4xqlT97pd VL3w72LR+fiCKne38gn2+T0KW1W8oxn+Sp7I3yDa1TdvvvQEp+3BoubigWVNccazONjUJFaZTpr JAwA= X-Developer-Key: i=jre@pengutronix.de; a=openpgp; fpr=0B7B750D5D3CD21B3B130DE8B61515E135CD49B5 X-MORS-Enabled: yes X-MORS-DOMAIN: patchwork.local X-MORS-HOSTING: hosting172546 X-MORS-USER: hosting172546 X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= |
| Series |
spi: spi-sun4i: assorted fixes
|
|
Commit Message
Jonas Rebmann
Sept. 14, 2026, 3:35 p.m. UTC
From: Marc Kleine-Budde <mkl@pengutronix.de> In commit 6d9fe44bd73d ("spi: sun4i: fix FIFO limit"), the TX FIFO is filled max to SUN4I_FIFO_DEPTH - 1 (= 63) bytes to work around timeouts observed on A10s SoCs. Commit 196737912da5 ("spi: sun4i: Allow transfers larger than FIFO size") added support for transfers larger than the FIFO size. This commit did not consider the A10 workaround (limit the TX FIFO fill size to SUN4I_FIFO_DEPTH - 1 (= 63) bytes) for refilling the TX FIFO in the IRQ handler. To apply the workaround independent from where sun4i_spi_fill_fifo() is called, remove the length argument from the function and directly take the max fill level of SUN4I_FIFO_DEPTH - 1 into account when calculating the free space in the FIFO. Due to the lack of HW this patch has not been tested on an A10 SoC, but on an A20 SoC. It was not possible to reproduce the timeout on the A20. Fixes: 196737912da5 ("spi: sun4i: Allow transfers larger than FIFO size") Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> Signed-off-by: Jonas Rebmann <jre@pengutronix.de> --- drivers/spi/spi-sun4i.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)
Comments
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: New issues: - [High] Integer underflow in `sun4i_spi_fill_fifo()` causes an infinite loop and buffer overflow when calculating available TX FIFO space. Pre-existing issues: - [High] Unbounded writes to the receive buffer in `sun4i_spi_drain_fifo` can cause a heap buffer overflow. -- commit 293e40dd169fc9a0b7d04d7abe8b6d6292a688f1 Author: Marc Kleine-Budde <mkl@pengutronix.de> spi: spi-sun4i: sun4i_spi_fill_fifo(): always apply A10 FIFO fill level workaround This commit removes the length argument from sun4i_spi_fill_fifo() and directly limits the TX FIFO fill level internally to work around timeouts on A10s SoCs. It ensures the workaround is always applied regardless of where the FIFO is refilled. > diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c > index 2e23244539053..3649bcabcc9a7 100644 > --- a/drivers/spi/spi-sun4i.c > +++ b/drivers/spi/spi-sun4i.c > @@ -142,15 +142,21 @@ static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len) > } > } [Severity: High] This is a pre-existing issue, but does sun4i_spi_drain_fifo() lack bounds checking against the allocated receive buffer size? Looking at sun4i_spi_drain_fifo(): static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len) { ... if (len > cnt) len = cnt; while (len--) { byte = readb(sspi->base_addr + SUN4I_RXDATA_REG); if (sspi->rx_buf) *sspi->rx_buf++ = byte; } } Data from the hardware is read based on what the hardware reports as available, and unconditionally written to sspi->rx_buf. It doesn't appear to track the total bytes written against the transfer length limit. If the hardware asserts spurious interrupts or reports more bytes than requested (e.g., when called from sun4i_spi_handler with SUN4I_FIFO_DEPTH), couldn't this blindly advance the pointer past the end of the allocation and cause a heap buffer overflow? > > -static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len) > +static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi) > { > u32 cnt; > + int len; > u8 byte; > > - /* See how much data we can fit */ > - cnt = SUN4I_FIFO_DEPTH - sun4i_spi_get_tx_fifo_count(sspi); > + /* > + * See how much data we can fit > + * > + * Filling the FIFO fully causes timeout for some reason > + * at least on spi2 on A10s > + */ > + cnt = SUN4I_FIFO_DEPTH - 1 - sun4i_spi_get_tx_fifo_count(sspi); > > - len = min3(len, (int)cnt, sspi->len); > + len = min_t(int, cnt, sspi->len); > > while (len--) { > byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; [Severity: High] Can this subtraction underflow if the hardware reports a full FIFO? If sun4i_spi_get_tx_fifo_count(sspi) returns 64 (the physical maximum depth), cnt will evaluate to 63 - 64 = -1. Because cnt is a u32, this underflows to 0xFFFFFFFF. The min_t() macro then compares (int)0xFFFFFFFF (which is -1) against sspi->len. Assuming sspi->len is greater than zero, min_t() returns -1. The subsequent while (len--) loop will post-decrement on the negative integer and could spin indefinitely, leading to out-of-bounds reads from sspi->tx_buf and continuous writes to the memory-mapped register. [ ... ]
Dear humans, On 14.09.2026 15:50:08, sashiko-bot@kernel.org wrote: > Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: > > New issues: > - [High] Integer underflow in `sun4i_spi_fill_fifo()` causes an infinite loop and buffer overflow when calculating available TX FIFO space. > > Pre-existing issues: > - [High] Unbounded writes to the receive buffer in `sun4i_spi_drain_fifo` can cause a heap buffer overflow. > -- > > commit 293e40dd169fc9a0b7d04d7abe8b6d6292a688f1 > Author: Marc Kleine-Budde <mkl@pengutronix.de> > > spi: spi-sun4i: sun4i_spi_fill_fifo(): always apply A10 FIFO fill level workaround > > This commit removes the length argument from sun4i_spi_fill_fifo() and > directly limits the TX FIFO fill level internally to work around timeouts > on A10s SoCs. It ensures the workaround is always applied regardless of > where the FIFO is refilled. > > > diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c > > index 2e23244539053..3649bcabcc9a7 100644 > > --- a/drivers/spi/spi-sun4i.c > > +++ b/drivers/spi/spi-sun4i.c > > @@ -142,15 +142,21 @@ static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len) > > } > > } > > [Severity: High] > This is a pre-existing issue, but does sun4i_spi_drain_fifo() lack bounds > checking against the allocated receive buffer size? > > Looking at sun4i_spi_drain_fifo(): > > static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len) > { > ... > if (len > cnt) > len = cnt; > > while (len--) { > byte = readb(sspi->base_addr + SUN4I_RXDATA_REG); > if (sspi->rx_buf) > *sspi->rx_buf++ = byte; > } > } > > Data from the hardware is read based on what the hardware reports as > available, and unconditionally written to sspi->rx_buf. It doesn't appear > to track the total bytes written against the transfer length limit. > > If the hardware asserts spurious interrupts or reports more bytes than > requested (e.g., when called from sun4i_spi_handler with SUN4I_FIFO_DEPTH), > couldn't this blindly advance the pointer past the end of the allocation > and cause a heap buffer overflow? Neither spurious interrupts nor more bytes than requested have been observed. So far we trust the hardware. > > > > -static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len) > > +static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi) > > { > > u32 cnt; > > + int len; > > u8 byte; > > > > - /* See how much data we can fit */ > > - cnt = SUN4I_FIFO_DEPTH - sun4i_spi_get_tx_fifo_count(sspi); > > + /* > > + * See how much data we can fit > > + * > > + * Filling the FIFO fully causes timeout for some reason > > + * at least on spi2 on A10s > > + */ > > + cnt = SUN4I_FIFO_DEPTH - 1 - sun4i_spi_get_tx_fifo_count(sspi); > > > > - len = min3(len, (int)cnt, sspi->len); > > + len = min_t(int, cnt, sspi->len); > > > > while (len--) { > > byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; > > [Severity: High] > Can this subtraction underflow if the hardware reports a full FIFO? With this change the hardware TX buffer is only filled up to SUN4I_FIFO_DEPTH - 1, so it will never report to be filled with SUN4I_FIFO_DEPTH. > If sun4i_spi_get_tx_fifo_count(sspi) returns 64 (the physical maximum > depth), cnt will evaluate to 63 - 64 = -1. Because cnt is a u32, this > underflows to 0xFFFFFFFF. > > The min_t() macro then compares (int)0xFFFFFFFF (which is -1) against > sspi->len. Assuming sspi->len is greater than zero, min_t() returns -1. > > The subsequent while (len--) loop will post-decrement on the negative > integer and could spin indefinitely, leading to out-of-bounds reads from > sspi->tx_buf and continuous writes to the memory-mapped register. regards, Marc -- Pengutronix e.K. | Marc Kleine-Budde | Embedded Linux | https://www.pengutronix.de | Vertretung Nürnberg | Phone: +49-5121-206917-129 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |
diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index 2e2324453905..3649bcabcc9a 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -142,15 +142,21 @@ static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len) } } -static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len) +static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi) { u32 cnt; + int len; u8 byte; - /* See how much data we can fit */ - cnt = SUN4I_FIFO_DEPTH - sun4i_spi_get_tx_fifo_count(sspi); + /* + * See how much data we can fit + * + * Filling the FIFO fully causes timeout for some reason + * at least on spi2 on A10s + */ + cnt = SUN4I_FIFO_DEPTH - 1 - sun4i_spi_get_tx_fifo_count(sspi); - len = min3(len, (int)cnt, sspi->len); + len = min_t(int, cnt, sspi->len); while (len--) { byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; @@ -311,12 +317,8 @@ static int sun4i_spi_transfer_one(struct spi_controller *host, sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len)); sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len)); - /* - * Fill the TX FIFO - * Filling the FIFO fully causes timeout for some reason - * at least on spi2 on A10s - */ - sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1); + /* Fill the TX FIFO */ + sun4i_spi_fill_fifo(sspi); /* Enable the interrupts */ sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TC | @@ -373,7 +375,7 @@ static irqreturn_t sun4i_spi_handler(int irq, void *dev_id) /* Transmit FIFO 3/4 empty */ if (status & SUN4I_INT_CTL_TF_E34) { - sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH); + sun4i_spi_fill_fifo(sspi); if (!sspi->len) /* nothing left to transmit */