From 5034f8629f646f713528a30353f96b83bd4b2a3e Mon Sep 17 00:00:00 2001 From: Matt DeVillier Date: Sat, 29 Nov 2025 15:03:34 -0600 Subject: [PATCH] soc/intel/common: Add spinlock protection to fast SPI flash operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add spinlock synchronization to prevent concurrent SPI flash controller access from multiple CPUs in SMP environments. The spinlock serializes access to the SPI controller hardware in exec_sync_hwseq_xfer(). If SMP is not enabled, spinlock functions are no-ops, so this change is safe for both SMP and non-SMP configurations. This resolves an issue seen on the Starlabs Starfighter MTL where multiple SPI transaction errors occurred when reading option variables stored in SMMSTORE: [ERROR] SPI Transaction Error at Flash Offset 103002a HSFSTS = 0x01016022 [ERROR] SPI Transaction Error at Flash Offset 1030004 HSFSTS = 0x01006022 [ERROR] SPI Transaction Error at Flash Offset 1030000 HSFSTS = 0x3f006022 ... Change-Id: Ic3003b0a986b587622102b6f36714bcb16c3d976 Signed-off-by: Matt DeVillier Reviewed-on: https://review.coreboot.org/c/coreboot/+/90283 Tested-by: build bot (Jenkins) Reviewed-by: Sean Rhodes Reviewed-by: Jérémy Compostella --- .../common/block/fast_spi/fast_spi_flash.c | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/soc/intel/common/block/fast_spi/fast_spi_flash.c b/src/soc/intel/common/block/fast_spi/fast_spi_flash.c index a7762711fa..89ae6d2cd3 100644 --- a/src/soc/intel/common/block/fast_spi/fast_spi_flash.c +++ b/src/soc/intel/common/block/fast_spi/fast_spi_flash.c @@ -9,6 +9,7 @@ #include #include #include +#include /* Helper to create a FAST_SPI context on API entry. */ #define BOILERPLATE_CREATE_CTX(ctx) \ @@ -32,6 +33,9 @@ struct fast_spi_flash_ctx { uintptr_t mmio_base; }; +/* Spinlock to protect concurrent SPI flash controller access from multiple CPUs */ +DECLARE_SPIN_LOCK(fast_spi_lock); + static void _fast_spi_flash_get_ctx(struct fast_spi_flash_ctx *ctx) { ctx->mmio_base = (uintptr_t)fast_spi_get_bar(); @@ -160,15 +164,28 @@ static int exec_sync_hwseq_xfer(struct fast_spi_flash_ctx *ctx, uint32_t hsfsts_cycle, uint32_t flash_addr, size_t len) { + int ret; + + /* Protect SPI flash controller from concurrent access by multiple CPUs. + * The spinlock serializes access to the SPI controller hardware. + * If SMP is not enabled, spinlock functions are no-ops. + */ + spin_lock(&fast_spi_lock); + if (wait_for_hwseq_spi_cycle_complete(ctx) != SUCCESS) { printk(BIOS_ERR, "SPI Transaction Timeout (Exceeded %d ms) due to prior" " operation at Flash Offset %x\n", SPIBAR_HWSEQ_XFER_TIMEOUT_MS, flash_addr); - return E_TIMEOUT; + ret = E_TIMEOUT; + goto unlock; } start_hwseq_xfer(ctx, hsfsts_cycle, flash_addr, len); - return wait_for_hwseq_xfer(ctx, flash_addr); + ret = wait_for_hwseq_xfer(ctx, flash_addr); + +unlock: + spin_unlock(&fast_spi_lock); + return ret; } int fast_spi_cycle_in_progress(void)