spi: atmel: Reduce spin lock usage
The current implementation of the driver holds a spin lock for the duration of the transfer, releasing it only to enable interrupts for short periods of time. As this would prevent any interrupt from happening, this could cause system performance issues every time a SPI message is sent. Since the spi core now handles message syncronization we can reduce the amount of time the spin-lock is held to the regions where both the calling thread and the interrupt might interract. Signed-off-by: Dan Sneddon <dan.sneddon@microchip.com> Link: https://lore.kernel.org/r/20210602160816.4890-2-dan.sneddon@microchip.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
5fa5e6dec7
commit
4abd641501
|
@ -700,7 +700,6 @@ static void atmel_spi_next_xfer_pio(struct spi_master *master,
|
||||||
static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
||||||
struct spi_transfer *xfer,
|
struct spi_transfer *xfer,
|
||||||
u32 *plen)
|
u32 *plen)
|
||||||
__must_hold(&as->lock)
|
|
||||||
{
|
{
|
||||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||||
struct dma_chan *rxchan = master->dma_rx;
|
struct dma_chan *rxchan = master->dma_rx;
|
||||||
|
@ -716,8 +715,6 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
||||||
if (!rxchan || !txchan)
|
if (!rxchan || !txchan)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
/* release lock for DMA operations */
|
|
||||||
atmel_spi_unlock(as);
|
|
||||||
|
|
||||||
*plen = xfer->len;
|
*plen = xfer->len;
|
||||||
|
|
||||||
|
@ -786,15 +783,12 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
||||||
rxchan->device->device_issue_pending(rxchan);
|
rxchan->device->device_issue_pending(rxchan);
|
||||||
txchan->device->device_issue_pending(txchan);
|
txchan->device->device_issue_pending(txchan);
|
||||||
|
|
||||||
/* take back lock */
|
|
||||||
atmel_spi_lock(as);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_dma:
|
err_dma:
|
||||||
spi_writel(as, IDR, SPI_BIT(OVRES));
|
spi_writel(as, IDR, SPI_BIT(OVRES));
|
||||||
atmel_spi_stop_dma(master);
|
atmel_spi_stop_dma(master);
|
||||||
err_exit:
|
err_exit:
|
||||||
atmel_spi_lock(as);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1053,8 +1047,6 @@ atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer)
|
||||||
|
|
||||||
/* Interrupt
|
/* Interrupt
|
||||||
*
|
*
|
||||||
* No need for locking in this Interrupt handler: done_status is the
|
|
||||||
* only information modified.
|
|
||||||
*/
|
*/
|
||||||
static irqreturn_t
|
static irqreturn_t
|
||||||
atmel_spi_pio_interrupt(int irq, void *dev_id)
|
atmel_spi_pio_interrupt(int irq, void *dev_id)
|
||||||
|
@ -1302,8 +1294,6 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||||
unsigned long dma_timeout;
|
unsigned long dma_timeout;
|
||||||
|
|
||||||
as = spi_master_get_devdata(master);
|
as = spi_master_get_devdata(master);
|
||||||
/* This lock was orignally taken in atmel_spi_trasfer_one_message */
|
|
||||||
atmel_spi_lock(as);
|
|
||||||
|
|
||||||
asd = spi->controller_state;
|
asd = spi->controller_state;
|
||||||
bits = (asd->csr >> 4) & 0xf;
|
bits = (asd->csr >> 4) & 0xf;
|
||||||
|
@ -1332,7 +1322,9 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||||
reinit_completion(&as->xfer_completion);
|
reinit_completion(&as->xfer_completion);
|
||||||
|
|
||||||
if (as->use_pdc) {
|
if (as->use_pdc) {
|
||||||
|
atmel_spi_lock(as);
|
||||||
atmel_spi_pdc_next_xfer(master, xfer);
|
atmel_spi_pdc_next_xfer(master, xfer);
|
||||||
|
atmel_spi_unlock(as);
|
||||||
} else if (atmel_spi_use_dma(as, xfer)) {
|
} else if (atmel_spi_use_dma(as, xfer)) {
|
||||||
len = as->current_remaining_bytes;
|
len = as->current_remaining_bytes;
|
||||||
ret = atmel_spi_next_xfer_dma_submit(master,
|
ret = atmel_spi_next_xfer_dma_submit(master,
|
||||||
|
@ -1348,14 +1340,13 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||||
as->current_remaining_bytes = 0;
|
as->current_remaining_bytes = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
atmel_spi_lock(as);
|
||||||
atmel_spi_next_xfer_pio(master, xfer);
|
atmel_spi_next_xfer_pio(master, xfer);
|
||||||
|
atmel_spi_unlock(as);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* interrupts are disabled, so free the lock for schedule */
|
|
||||||
atmel_spi_unlock(as);
|
|
||||||
dma_timeout = wait_for_completion_timeout(&as->xfer_completion,
|
dma_timeout = wait_for_completion_timeout(&as->xfer_completion,
|
||||||
SPI_DMA_TIMEOUT);
|
SPI_DMA_TIMEOUT);
|
||||||
atmel_spi_lock(as);
|
|
||||||
if (WARN_ON(dma_timeout == 0)) {
|
if (WARN_ON(dma_timeout == 0)) {
|
||||||
dev_err(&spi->dev, "spi transfer timeout\n");
|
dev_err(&spi->dev, "spi transfer timeout\n");
|
||||||
as->done_status = -EIO;
|
as->done_status = -EIO;
|
||||||
|
@ -1403,8 +1394,6 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||||
if (as->use_pdc)
|
if (as->use_pdc)
|
||||||
atmel_spi_disable_pdc_transfer(as);
|
atmel_spi_disable_pdc_transfer(as);
|
||||||
|
|
||||||
atmel_spi_unlock(as);
|
|
||||||
|
|
||||||
return as->done_status;
|
return as->done_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue