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 BA15E607412C for ; Fri, 13 Nov 2026 13:50:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=NWiqT3Tt; dkim=pass (2048-bit key) header.d=sntech.de header.i=@sntech.de header.a=rsa-sha256 header.s=gloria202408 header.b=yPBrE/cx 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=EU1GCdpoYv3dyUkCvBVaDJg/AzeUUA6cITm/SbRGh4s=; b=NWiqT3Tt4QUbQH U1/JhNgZ7uAFPVVDn3hsoDQmtl3w4GmHvtyi9IOY4Z9Nu2lnNj6X2KfSZRM1dqLg0DVL6w86yR5UB RF84VHfh0yphXt+KQDRBC94E6lzxZKsupvEjWFE3j4Z81UZgM1dxcp9Hgm+FfM3gpK4vsMSIKgTWd oH3IgdcZitGuWNsj2xPaPzBH1hCCxQ1NrtyfXMwFFDgKOKQJZQkMBupJ3aw2EcNoAvKIMUvjmOY7e CqiR/G/rcQkBW3rJyPh8rgFdsu/HnNysoXza0sUWrY4pR0hTyKsoriCpIHlyzARLClgaE/dHKEGB3 3zBL7xVk2S2tnPVxBnVA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.100.1 #2 (Red Hat Linux)) id 1xRrfq-0000000D1c0-0ssY; Fri, 13 Nov 2026 13:50:38 +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 1xRrfh-0000000D1VD-2RHn; Fri, 13 Nov 2026 13:50:32 +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=EU1GCdpoYv3dyUkCvBVaDJg/AzeUUA6cITm/SbRGh4s=; b=yPBrE/cxOmaPn/pOqmmwPPqvza G70yDWL0F1Q73RqiJKS+X4pGUflB5D15KUbGCy5l6nxChQVVIQKt0yg6h1o6QmzRbdGvXxt0o8MwT kyzzOlDxh3ZgUV52yTaP3iNgy2rP+GFS+dEkqARLvJpysGVzUjAHJ9MLyuGklMLnBBQTb/ANj1sgh 8Y9+DZFug4sXQbyPytpnzioGsCGs73mY5o5GHiCQ5T0z5idGPg8guhqGr6TT3JkX8wJGK+3Mou5eh f9oIxjMTwHTMu0pvPQf5afZMvHMmbvFBYYc/HN3VV1SIWkLA4gjeo4BriXR3laPZEIB3v6Z7CS6pS VFzillXQ==; 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 v2 3/6] spi: Add infrastructure for atomic sync transfers Date: Fri, 13 Nov 2026 14:50:14 +0100 Message-ID: <20261113135017.1047959-4-heiko@sntech.de> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261113135017.1047959-1-heiko@sntech.de> References: <20261113135017.1047959-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-20261113_055029_638832_0237F366 X-CRM114-Status: GOOD ( 25.27 ) 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 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. For drivers without a transfer_atomic callback defined, the previous behaviour is kept for backwards compatiblity. spi_async() does not require a sleeping context for itself, so while it could in theory also be included, its caller waiting for the completion can sleep, so would still cause the splat about it. Signed-off-by: Heiko Stuebner --- drivers/spi/spi.c | 58 ++++++++++++++++++++++++++++++++++++++--- include/linux/spi/spi.h | 11 ++++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b268357e933c..0b1e07d87562 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -5027,6 +5027,37 @@ 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; + } + + /* Not using spi_maybe_optimize_message, so just validate */ + status = __spi_validate(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); + + if (status == 0) + status = message->status; + + return status; +} + /** * spi_sync - blocking/synchronous SPI data transfers * @spi: device with which data will be exchanged @@ -5037,6 +5068,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, @@ -5050,11 +5085,17 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message) */ int spi_sync(struct spi_device *spi, struct spi_message *message) { + struct spi_controller *ctlr = spi->controller; int ret; - mutex_lock(&spi->controller->bus_lock_mutex); - ret = __spi_sync(spi, message); - mutex_unlock(&spi->controller->bus_lock_mutex); + /* Keep old behaviour for clients that tolerate the warnings */ + if (spi_in_atomic_mode() && ctlr->transfer_atomic) { + 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; } @@ -5070,6 +5111,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. @@ -5078,7 +5123,12 @@ EXPORT_SYMBOL_GPL(spi_sync); */ int spi_sync_locked(struct spi_device *spi, struct spi_message *message) { - return __spi_sync(spi, message); + struct spi_controller *ctlr = spi->controller; + + if (spi_in_atomic_mode() && ctlr->transfer_atomic) + 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 0bf31776c54c..f62b21af5d75 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -461,6 +461,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 @@ -721,6 +723,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.53.0