diff options
author | Raul E Rangel <rrangel@chromium.org> | 2021-11-02 11:51:48 -0600 |
---|---|---|
committer | Raul Rangel <rrangel@chromium.org> | 2021-11-15 16:16:54 +0000 |
commit | 964eb67de6375e0eadffe0f329e460f340217daf (patch) | |
tree | 2405c350dc79714c479d78bda0da34e18cc42199 /src/soc/amd | |
parent | a3811fe5e74575cc6173f8e2fc153c6f9884f89c (diff) |
soc/amd/common/block: Add spi_hw mutex
There are currently two users of the SPI hardware, the LPC SPI DMA
controller, and the boot_device_rw device. We need to ensure exclusivity
to the SPI hardware otherwise the SPI DMA controller can be interrupted
and it will silently skip transferring some blocks.
Depending on the SPI speed, this change might add a small delay when
clearing the elog since a DMA transaction might be in flight. I'll
continue optimizing the boot flow to avoid the delay.
BUG=b:179699789
TEST=Hack up the code to interleave SPI transactions and verify this
patch fixes the silent data corruption.
Signed-off-by: Raul E Rangel <rrangel@chromium.org>
Change-Id: I5eee812a6979c8c0fb313dd2fbccc14b73d7d741
Reviewed-on: https://review.coreboot.org/c/coreboot/+/58926
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Karthik Ramasubramanian <kramasub@google.com>
Diffstat (limited to 'src/soc/amd')
-rw-r--r-- | src/soc/amd/common/block/include/amdblocks/spi.h | 5 | ||||
-rw-r--r-- | src/soc/amd/common/block/lpc/spi_dma.c | 12 | ||||
-rw-r--r-- | src/soc/amd/common/block/spi/fch_spi_ctrl.c | 8 | ||||
-rw-r--r-- | src/soc/amd/common/block/spi/fch_spi_util.c | 3 |
4 files changed, 27 insertions, 1 deletions
diff --git a/src/soc/amd/common/block/include/amdblocks/spi.h b/src/soc/amd/common/block/include/amdblocks/spi.h index 35a3782f7a..81da5dd53f 100644 --- a/src/soc/amd/common/block/include/amdblocks/spi.h +++ b/src/soc/amd/common/block/include/amdblocks/spi.h @@ -3,6 +3,7 @@ #ifndef AMD_BLOCK_SPI_H #define AMD_BLOCK_SPI_H +#include <thread.h> #include <types.h> #define SPI_CNTRL0 0x00 @@ -118,4 +119,8 @@ void spi_write32(uint8_t reg, uint32_t val); void fch_spi_config_modes(void); void mainboard_spi_fast_speed_override(uint8_t *fast_speed); + +/* Ensure you hold the mutex when performing SPI transactions */ +extern struct thread_mutex spi_hw_mutex; + #endif /* AMD_BLOCK_SPI_H */ diff --git a/src/soc/amd/common/block/lpc/spi_dma.c b/src/soc/amd/common/block/lpc/spi_dma.c index 5c697790c8..baf1eb8036 100644 --- a/src/soc/amd/common/block/lpc/spi_dma.c +++ b/src/soc/amd/common/block/lpc/spi_dma.c @@ -122,6 +122,12 @@ static void start_spi_dma_transaction(struct spi_dma_transaction *transaction) ctrl |= LPC_ROM_DMA_CTRL_ERROR; /* Clear error */ ctrl |= LPC_ROM_DMA_CTRL_START; + /* + * Ensure we have exclusive access to the SPI controller before starting the LPC SPI DMA + * transaction. + */ + thread_mutex_lock(&spi_hw_mutex); + pci_write_config32(SOC_LPC_DEV, LPC_ROM_DMA_EC_HOST_CONTROL, ctrl); } @@ -135,6 +141,12 @@ static bool continue_spi_dma_transaction(const struct region_device *rd, if (spi_dma_is_busy()) return true; + /* + * Unlock the SPI mutex between DMA transactions to allow other users of the SPI + * controller to interleave their transactions. + */ + thread_mutex_unlock(&spi_hw_mutex); + if (spi_dma_has_error()) { printk(BIOS_ERR, "ERROR: SPI DMA failure: dest: %p, source: %#zx, size: %zu\n", diff --git a/src/soc/amd/common/block/spi/fch_spi_ctrl.c b/src/soc/amd/common/block/spi/fch_spi_ctrl.c index 565fdbe149..d95b64275b 100644 --- a/src/soc/amd/common/block/spi/fch_spi_ctrl.c +++ b/src/soc/amd/common/block/spi/fch_spi_ctrl.c @@ -142,7 +142,13 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout, static int xfer_vectors(const struct spi_slave *slave, struct spi_op vectors[], size_t count) { - return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); + int rc; + + thread_mutex_lock(&spi_hw_mutex); + rc = spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); + thread_mutex_unlock(&spi_hw_mutex); + + return rc; } static int protect_a_range(u32 value) diff --git a/src/soc/amd/common/block/spi/fch_spi_util.c b/src/soc/amd/common/block/spi/fch_spi_util.c index 5cef565baf..862962f0bd 100644 --- a/src/soc/amd/common/block/spi/fch_spi_util.c +++ b/src/soc/amd/common/block/spi/fch_spi_util.c @@ -6,6 +6,9 @@ #include <assert.h> #include <stdint.h> +/* Global SPI controller mutex */ +struct thread_mutex spi_hw_mutex; + static uintptr_t spi_base; void spi_set_base(void *base) |