Skip to content

Commit

Permalink
mpfs/mpfs_corespi: Optimize TX / RX FIFO handling
Browse files Browse the repository at this point in the history
Remove unnecessary reading of the status register when loading / unloading
the FIFOs. Reading from the IP block is slow due to BUS synchronization and
this basically makes the SPI busy loop for no reason at all, destroying the
CPU usage.

The overall benefit of these changes is approx. 25%-points, which is a
MASSIVE improvement.
  • Loading branch information
pussuw committed May 31, 2023
1 parent 88a93fe commit 2f511b8
Showing 1 changed file with 57 additions and 23 deletions.
80 changes: 57 additions & 23 deletions arch/risc-v/src/mpfs/mpfs_corespi.c
Expand Up @@ -388,6 +388,54 @@ static void mpfs_spi_rxoverflow_recover(struct mpfs_spi_priv_s *priv)
mpfs_spi_enable(priv, 1);
}

/****************************************************************************
* Name: mpfs_rx_wait_last_frame
*
* Description:
* Wait for the last frame in TXDONE interrupt. We must potentially do this
* wait because the TXDONE interrupt is asserted when the last frame is
* moved from the TXLAST register to the FIFO, thus there can be 1-2 frame
* delay before the last RX frame is available in the FIFO.
*
* Input Parameters:
* priv - Private SPI device structure
*
* Returned Value:
* None
*
****************************************************************************/

static int mpfs_rx_wait_last_frame(struct mpfs_spi_priv_s *priv)
{
uint32_t rxempty;
uint32_t rxretry;
uint32_t timeout;

rxretry = 0;

while ((rxempty = getreg32(MPFS_SPI_STATUS) & MPFS_SPI_RXEMPTY))
{
/* Last RX character not ready yet, try again (once) */

if (rxretry == 0)
{
/* Use safe type for timeout calculations */

timeout = priv->nbits;
timeout = SPI_TTOA_US(timeout << 1, priv->actual);
rxretry = 1;
up_udelay(timeout);
continue;
}

/* Nothing is coming, get out */

return -1;
}

return 0;
}

/****************************************************************************
* Name: mpfs_spi_lock
*
Expand Down Expand Up @@ -688,14 +736,12 @@ static void mpfs_spi_load_tx_fifo(struct mpfs_spi_priv_s *priv,
const void *txbuffer,
uint32_t nwords)
{
uint32_t tx_fifo_full;
uint16_t *data16;
uint8_t *data8;
int last;
int i;

DEBUGASSERT(nwords > 0);

data16 = (uint16_t *)txbuffer;
data8 = (uint8_t *)txbuffer;
last = nwords - 1;
Expand Down Expand Up @@ -740,9 +786,6 @@ static void mpfs_spi_load_tx_fifo(struct mpfs_spi_priv_s *priv,
}

priv->tx_pos++;
tx_fifo_full = getreg32(MPFS_SPI_STATUS) & MPFS_SPI_TXFULL;

DEBUGASSERT(tx_fifo_full == 0);
}
}

Expand All @@ -767,38 +810,29 @@ static void mpfs_spi_unload_rx_fifo(struct mpfs_spi_priv_s *priv,
void *rxbuffer,
uint32_t nwords)
{
uint32_t rx_fifo_empty;
uint32_t rxretry;
uint16_t *data16;
uint8_t *data8;
int last;
int i;

DEBUGASSERT(nwords > 0);

data16 = (uint16_t *)rxbuffer;
data8 = (uint8_t *)rxbuffer;
rxretry = 0;
last = nwords - 1;

for (i = 0; i < nwords; i++)
{
while ((rx_fifo_empty = getreg32(MPFS_SPI_STATUS) & MPFS_SPI_RXEMPTY))
{
/* Last RX character not ready yet, try again (once) */
/* The last character might not be available yet due to bus delays */

if (rxretry == 0)
if (i == last)
{
if (mpfs_rx_wait_last_frame(priv) < 0)
{
/* Use safe type for timeout calculations */
/* Nothing came, get out */

uint32_t timeout = priv->nbits;
timeout = SPI_TTOA_US(timeout << 1, priv->actual);
rxretry = 1;
up_udelay(timeout);
continue;
return;
}

/* Nothing is coming, get out */

return;
}

if (rxbuffer)
Expand Down Expand Up @@ -867,7 +901,7 @@ static void mpfs_spi_irq_exchange(struct mpfs_spi_priv_s *priv,
DEBUGASSERT(priv->nbits == 8 || priv->nbits == 16);

priv->fifosize = (MPFS_FIFO_SIZE_BITS / priv->nbits);
priv->fifolevel = priv->fifosize / 2;
priv->fifolevel = priv->fifosize - 2;

priv->txwords = nwords;
priv->txbuf = txbuffer;
Expand Down

0 comments on commit 2f511b8

Please sign in to comment.