Skip to content

Commit

Permalink
Merge series "spi: bcm2835: Interrupt-handling optimisations" from Ro…
Browse files Browse the repository at this point in the history
…bin Murphy <robin.murphy@arm.com>:

Hi all,

Although Florian was concerned about a trivial inline check to deal with
shared IRQs adding overhead, the reality is that it would be so small as
to not be worth even thinking about unless the driver was already tuned
to squeeze out every last cycle. And a brief look over the code shows
that that clearly isn't the case.

This is an example of some of the easy low-hanging fruit that jumps out
just from code inspection. Based on disassembly and ARM1176 cycle
timings, patch #2 should save the equivalent of 2-3 shared interrupt
checks off the critical path in all cases, and patch #3 possibly up to
about 100x more. I don't have any means to test these patches, let alone
measure performance, so they're only backed by the principle that less
code - and in particular fewer memory accesses - is almost always
better.

There is almost certainly a *lot* more to be had from careful use of
relaxed I/O accessors, not doing a read-modify-write of CS at every
reset, tweaking the loops further to avoid unnecessary writebacks to
variables, and so on. However since I'm not invested in this personally
I'm not going to pursue it any further; I'm throwing these patches out
as more of a demonstration to back up my original drive-by review
comments, so if anyone want to pick them up and run with them then
please do so.

Robin.

Robin Murphy (3):
  spi: bcm3835: Tidy up bcm2835_spi_reset_hw()
  spi: bcm2835: Micro-optimise IRQ handler
  spi: bcm2835: Micro-optimise FIFO loops

 drivers/spi/spi-bcm2835.c | 45 +++++++++++++++++++--------------------
 1 file changed, 22 insertions(+), 23 deletions(-)

--
2.23.0.dirty

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
  • Loading branch information
Mark Brown committed Jul 1, 2020
2 parents 95f2fd2 + 26751de commit f2d4f10
Showing 1 changed file with 22 additions and 23 deletions.
45 changes: 22 additions & 23 deletions drivers/spi/spi-bcm2835.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ MODULE_PARM_DESC(polling_limit_us,
* @clk: core clock, divided to calculate serial clock
* @irq: interrupt, signals TX FIFO empty or RX FIFO ¾ full
* @tfr: SPI transfer currently processed
* @ctlr: SPI controller reverse lookup
* @tx_buf: pointer whence next transmitted byte is read
* @rx_buf: pointer where next received byte is written
* @tx_len: remaining bytes to transmit
Expand Down Expand Up @@ -125,6 +126,7 @@ struct bcm2835_spi {
struct clk *clk;
int irq;
struct spi_transfer *tfr;
struct spi_controller *ctlr;
const u8 *tx_buf;
u8 *rx_buf;
int tx_len;
Expand Down Expand Up @@ -243,13 +245,13 @@ static inline void bcm2835_rd_fifo_count(struct bcm2835_spi *bs, int count)

bs->rx_len -= count;

while (count > 0) {
do {
val = bcm2835_rd(bs, BCM2835_SPI_FIFO);
len = min(count, 4);
memcpy(bs->rx_buf, &val, len);
bs->rx_buf += len;
count -= 4;
}
} while (count > 0);
}

/**
Expand All @@ -269,7 +271,7 @@ static inline void bcm2835_wr_fifo_count(struct bcm2835_spi *bs, int count)

bs->tx_len -= count;

while (count > 0) {
do {
if (bs->tx_buf) {
len = min(count, 4);
memcpy(&val, bs->tx_buf, len);
Expand All @@ -279,7 +281,7 @@ static inline void bcm2835_wr_fifo_count(struct bcm2835_spi *bs, int count)
}
bcm2835_wr(bs, BCM2835_SPI_FIFO, val);
count -= 4;
}
} while (count > 0);
}

/**
Expand Down Expand Up @@ -308,12 +310,11 @@ static inline void bcm2835_rd_fifo_blind(struct bcm2835_spi *bs, int count)
count = min(count, bs->rx_len);
bs->rx_len -= count;

while (count) {
do {
val = bcm2835_rd(bs, BCM2835_SPI_FIFO);
if (bs->rx_buf)
*bs->rx_buf++ = val;
count--;
}
} while (--count);
}

/**
Expand All @@ -328,16 +329,14 @@ static inline void bcm2835_wr_fifo_blind(struct bcm2835_spi *bs, int count)
count = min(count, bs->tx_len);
bs->tx_len -= count;

while (count) {
do {
val = bs->tx_buf ? *bs->tx_buf++ : 0;
bcm2835_wr(bs, BCM2835_SPI_FIFO, val);
count--;
}
} while (--count);
}

static void bcm2835_spi_reset_hw(struct spi_controller *ctlr)
static void bcm2835_spi_reset_hw(struct bcm2835_spi *bs)
{
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);

/* Disable SPI interrupts and transfer */
Expand All @@ -363,8 +362,7 @@ static void bcm2835_spi_reset_hw(struct spi_controller *ctlr)

static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
{
struct spi_controller *ctlr = dev_id;
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
struct bcm2835_spi *bs = dev_id;
u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);

/*
Expand All @@ -386,9 +384,9 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)

if (!bs->rx_len) {
/* Transfer complete - reset SPI HW */
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);
/* wake up the framework */
complete(&ctlr->xfer_completion);
complete(&bs->ctlr->xfer_completion);
}

return IRQ_HANDLED;
Expand Down Expand Up @@ -607,7 +605,7 @@ static void bcm2835_spi_dma_rx_done(void *data)
bcm2835_spi_undo_prologue(bs);

/* reset fifo and HW */
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);

/* and mark as completed */;
complete(&ctlr->xfer_completion);
Expand Down Expand Up @@ -641,7 +639,7 @@ static void bcm2835_spi_dma_tx_done(void *data)
dmaengine_terminate_async(ctlr->dma_rx);

bcm2835_spi_undo_prologue(bs);
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);
complete(&ctlr->xfer_completion);
}

Expand Down Expand Up @@ -825,14 +823,14 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
if (!bs->rx_buf && !bs->tx_dma_active &&
cmpxchg(&bs->rx_dma_active, true, false)) {
dmaengine_terminate_async(ctlr->dma_rx);
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);
}

/* wait for wakeup in framework */
return 1;

err_reset_hw:
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);
bcm2835_spi_undo_prologue(bs);
return ret;
}
Expand Down Expand Up @@ -1074,7 +1072,7 @@ static int bcm2835_spi_transfer_one_poll(struct spi_controller *ctlr,
}

/* Transfer complete - reset SPI HW */
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);
/* and return without waiting for completion */
return 0;
}
Expand Down Expand Up @@ -1182,7 +1180,7 @@ static void bcm2835_spi_handle_err(struct spi_controller *ctlr,
bcm2835_spi_undo_prologue(bs);

/* and reset */
bcm2835_spi_reset_hw(ctlr);
bcm2835_spi_reset_hw(bs);
}

static int chip_match_name(struct gpio_chip *chip, void *data)
Expand Down Expand Up @@ -1311,6 +1309,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
ctlr->dev.of_node = pdev->dev.of_node;

bs = spi_controller_get_devdata(ctlr);
bs->ctlr = ctlr;

bs->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(bs->regs)) {
Expand Down Expand Up @@ -1345,7 +1344,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);

err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
dev_name(&pdev->dev), ctlr);
dev_name(&pdev->dev), bs);
if (err) {
dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
goto out_dma_release;
Expand Down

0 comments on commit f2d4f10

Please sign in to comment.