From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7EFBC606A326 for ; Fri, 6 Nov 2026 18:18:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=A7x1vDeE; dkim=pass (2048-bit key, unprotected) header.d=sntech.de header.i=@sntech.de header.a=rsa-sha256 header.s=gloria202408 header.b=wOJ45EzP 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: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Unsubscribe-Post: List-Owner; bh=4qu676T13y6RrHMwRJER4rARZi5IpEx76wQQl48H/Lg=; b=A7x1vDeEOiBzx1 ak/yNXwBVzvbIOtLpYkSQN+YLsecjRcnSx0pYqJd4h8YUCC6719HNo+aV1s2ZMJPJ2+OJMGNO8OCa 67s8oEwvuTzH1KbH/fpmZU1voy7Dg7Ty7ApU/M1yWoaUOgu6QKn6cbRqIDGGKuKpvCOBSlpmFTUCW htn/Qd7imL4DwafPpDqcJa11kcCf1zWwQD5iEmI/O+EecPInkafoJhPuWDjcKSrbc/BvWDh2V0Zyh oGOJo7TemqM7nL+XbLPEWNlhRStdtllBkz0Sjv5IfUKwQwJy1JRU9uaPFbUO6lJC3oPTps40+RyiZ oJW5pYzAOZKzt7XGEzCg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.100.1 #2 (Red Hat Linux)) id 1xPOWJ-0000000DNgW-3XZn; Fri, 06 Nov 2026 18:18:35 +0000 Received: from gloria.sntech.de ([185.11.138.130]) by bombadil.infradead.org with esmtps (Exim 4.100.1 #2 (Red Hat Linux)) id 1xPOWE-0000000DNd1-3Bcd; Fri, 06 Nov 2026 18:18:33 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sntech.de; s=gloria202408; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-Type; bh=4qu676T13y6RrHMwRJER4rARZi5IpEx76wQQl48H/Lg=; b=wOJ45EzPH4TKBuxbrG2SxMVfBZ HuraQyMYRtefiK+Y/kxaWLtSVhOtbYr070C4XU+gAK71isBez48dFuc3btrNQKR3S6SknVSetTthU DgLw4v0BzyD+JjnFtkyDRSrItWcYohw6wWnbYciZV7Qd35qc0Vvi0ZypFrE343PYZNDMTUp5Tf0fk O1TE3acBrA5K+pOzU8kJswcpEEYDGOgExjb1ZGLJF216LwKkDsMBB50L1JH342iOOx3wq1TRx2ksv OtQf0DgN8wpfmzWFkUH2wjVjrpb5fK14ILUVU4pH+0nB1XJF+dHkTacI5z6hWJS5LdOr1wQtIAZZz sCWbhAoQ==; From: Heiko Stuebner To: broonie@kernel.org Cc: Heiko Stuebner , linux-spi@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, quentin.schulz@cherry.de, Lee Jones , Sebastian Reichel , Heiko Stuebner Subject: [PATCH 1/2] spi: Add infrastructure for atomic sync transfers Date: Fri, 6 Nov 2026 19:18:22 +0100 Message-ID: <20261106181824.1361235-2-heiko@sntech.de> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20261106181824.1361235-1-heiko@sntech.de> References: <20261106181824.1361235-1-heiko@sntech.de> X-Archived-By: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.9.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20261106_101830_889664_0A9CE772 X-CRM114-Status: GOOD ( 25.10 ) X-Spam-Score: -2.1 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" X-Spam-Status: No, score=-18.9 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=4.0.1 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on aws-us-west-2-korg-listserv-alma10-1 From: Heiko Stuebner There are cases where SPI transfers are needed during times without interrupts like shutdown when a PMIC should turn off the system. I2C already has atomic transfers for exactly that case, so introduce a similar concept for SPI. Similar to I2C, this is and should stay a corner-case, so is only allowed during the shutdown stages of the kernel, when interrupts are already turned off. So add a in-atomic check stolen from I2C and an optional transfer_atomic callback drivers can implement to do immediate uninterrupted transfers and let spi_sync() determine if the state is late enough to use it. spi_async() does not require a sleeping context for itself, so while it could in theory also be included, its called waiting for the completion can sleep, so would still cause the splat about it. Signed-off-by: Heiko Stuebner --- drivers/spi/spi.c | 66 ++++++++++++++++++++++++++++++++++++++--- include/linux/spi/spi.h | 11 +++++++ 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 40cda0037ea5..b85ac20e63f6 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -5016,6 +5016,49 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message) return status; } +static int __spi_sync_atomic(struct spi_device *spi, struct spi_message *message) +{ + struct spi_controller *ctlr = spi->controller; + unsigned long flags; + int status; + + if (!ctlr->transfer_atomic) { + dev_err(&ctlr->dev, "No atomic transfer handler defined\n"); + return -EOPNOTSUPP; + } + + if (__spi_check_suspended(ctlr)) { + dev_warn_once(&spi->dev, "Attempted to sync while suspend\n"); + return -ESHUTDOWN; + } + + status = spi_maybe_optimize_message(spi, message); + if (status) + return status; + + spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags); + status = ctlr->transfer_atomic(spi, message); + spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags); + + spi_maybe_unoptimize_message(message); + + if (status == 0) + status = message->status; + + return status; +} + +/* + * We only allow atomic transfers for very late communication, e.g. to access a + * PMIC when powering down. Atomic transfers are a corner case and not for + * generic use! + */ +static inline bool spi_in_atomic_sync_mode(void) +{ + return system_state > SYSTEM_RUNNING && + (IS_ENABLED(CONFIG_PREEMPT_COUNT) ? !preemptible() : irqs_disabled()); +} + /** * spi_sync - blocking/synchronous SPI data transfers * @spi: device with which data will be exchanged @@ -5026,6 +5069,10 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message) * is non-interruptible, and has no timeout. Low-overhead controller * drivers may DMA directly into and out of the message buffers. * + * During the time when the system is being shutdown and a transfer_atomic + * function is set, this call may also be used from a context that does + * not allow sleeping, i.e. with disabled interrupts. + * * Note that the SPI device's chip select is active during the message, * and then is normally disabled between messages. Drivers for some * frequently-used devices may want to minimize costs of selecting a chip, @@ -5041,9 +5088,13 @@ int spi_sync(struct spi_device *spi, struct spi_message *message) { int ret; - mutex_lock(&spi->controller->bus_lock_mutex); - ret = __spi_sync(spi, message); - mutex_unlock(&spi->controller->bus_lock_mutex); + if (spi_in_atomic_sync_mode()) { + ret = __spi_sync_atomic(spi, message); + } else { + mutex_lock(&spi->controller->bus_lock_mutex); + ret = __spi_sync(spi, message); + mutex_unlock(&spi->controller->bus_lock_mutex); + } return ret; } @@ -5059,6 +5110,10 @@ EXPORT_SYMBOL_GPL(spi_sync); * is non-interruptible, and has no timeout. Low-overhead controller * drivers may DMA directly into and out of the message buffers. * + * During the time when the system is being shutdown and a transfer_atomic + * function is set, this call may also be used from a context that does + * not allow sleeping, i.e. with disabled interrupts. + * * This call should be used by drivers that require exclusive access to the * SPI bus. It has to be preceded by a spi_bus_lock call. The SPI bus must * be released by a spi_bus_unlock call when the exclusive access is over. @@ -5067,7 +5122,10 @@ EXPORT_SYMBOL_GPL(spi_sync); */ int spi_sync_locked(struct spi_device *spi, struct spi_message *message) { - return __spi_sync(spi, message); + if (spi_in_atomic_sync_mode()) + return __spi_sync_atomic(spi, message); + else + return __spi_sync(spi, message); } EXPORT_SYMBOL_GPL(spi_sync_locked); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index fb4baa0d3398..2b179b5d598c 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -459,6 +459,8 @@ extern struct spi_device *devm_spi_new_ancillary_device(struct spi_device *spi, * controller for configuring specific CS setup time, hold time and inactive * delay in terms of clock counts * @transfer: adds a message to the controller's transfer queue. + * @transfer_atomic: transfer a message immediately from a late-stage + * synchronous transfer * @cleanup: frees controller-specific state * @can_dma: determine whether this controller supports DMA * @dma_map_dev: device which can be used for DMA mapping @@ -719,6 +721,15 @@ struct spi_controller { int (*transfer)(struct spi_device *spi, struct spi_message *mesg); + /* + * Bidirectional bulk atomic transfers + * + * Special function that allows transfers in contexts where + * no interrupts nor DMA are available. + */ + int (*transfer_atomic)(struct spi_device *spi, + struct spi_message *mesg); + /* Called on deregistration to free memory provided by spi_controller */ void (*cleanup)(struct spi_device *spi); -- 2.47.3