diff mbox

[08/18] spi/xilinx: Support cores with no interrupt

Message ID 1422029330-10971-9-git-send-email-ricardo.ribalda@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ricardo Ribalda Delgado Jan. 23, 2015, 4:08 p.m. UTC
The core can run in polling mode. In fact, the performance of the core
is similar (or even better), due to the fact most of the spi
transactions are just a couple of bytes and there is one irq per
transactions.

When an mtd device is connected via spi, reading 8MB of data produces
more than 80K interrupts (with irq disabling, context swith....)

Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
---
 drivers/spi/spi-xilinx.c | 33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)

Comments

Mark Brown Jan. 27, 2015, 12:04 a.m. UTC | #1
On Fri, Jan 23, 2015 at 05:08:40PM +0100, Ricardo Ribalda Delgado wrote:

> The core can run in polling mode. In fact, the performance of the core
> is similar (or even better), due to the fact most of the spi
> transactions are just a couple of bytes and there is one irq per
> transactions.

> When an mtd device is connected via spi, reading 8MB of data produces
> more than 80K interrupts (with irq disabling, context swith....)

Right, for short transfers polling tends to win every time over
interrupts - if you look at other controller drivers you'll see a lot of
them use this technique.  The best practice here is generally to use a
copy break and do very short transfers in polling mode and go back to
interrupts for larger ones.  This break is typically done at the point
where we go over a FIFO in transfer size since normally if the device is
designed to be run with DMA the FIFO will be quite small.

Obviously this isn't quite the same case since not only is there no DMA
support (yet?) but the FIFO could be any size but similar things apply
especially if someone configured the device with a large FIFO.

> -	xspi_init_hw(xspi);
> -
>  	xspi->irq = platform_get_irq(pdev, 0);
> -	if (xspi->irq < 0) {
> -		ret = xspi->irq;
> -		goto put_master;
> +	if (xspi->irq >= 0) {
> +		/* Register for SPI Interrupt */
> +		ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
> +				dev_name(&pdev->dev), xspi);
> +		if (ret)
> +			goto put_master;
>  	}
>  
> -	/* Register for SPI Interrupt */
> -	ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
> -			       dev_name(&pdev->dev), xspi);
> -	if (ret)
> -		goto put_master;
> +	/* SPI controller initializations */
> +	xspi_init_hw(xspi);

This appears to move the interrupt request before the hardware reset.
Are you sure the interrupt handler won't misbehave if it fires before we
finished initializing?  One thing the hardware reset should do is get
the device in a known good state.
Ricardo Ribalda Delgado Jan. 27, 2015, 7:05 p.m. UTC | #2
Hello Mark

> Right, for short transfers polling tends to win every time over
> interrupts - if you look at other controller drivers you'll see a lot of
> them use this technique.  The best practice here is generally to use a
> copy break and do very short transfers in polling mode and go back to
> interrupts for larger ones.  This break is typically done at the point
> where we go over a FIFO in transfer size since normally if the device is
> designed to be run with DMA the FIFO will be quite small.

Seems very reasonable. Only problem I can see is if the spi clk is
veeery slow, then a irq approach, even for transfer size bellow
buffer_size will be better.


>
> Obviously this isn't quite the same case since not only is there no DMA
> support (yet?) but the FIFO could be any size but similar things apply
> especially if someone configured the device with a large FIFO.

The hardware does not support dma (at least without making use of
another core called cdma....)

We can always argue that the system engineer can select polling by not
specifying an irq on the device tree.


>> +     xspi_init_hw(xspi);
>
> This appears to move the interrupt request before the hardware reset.
> Are you sure the interrupt handler won't misbehave if it fires before we
> finished initializing?  One thing the hardware reset should do is get
> the device in a known good state.

The hardware will be reseted and in good state by the function
find_buffer_size, so this should be good. Also the initialization is
slightly different for polling and irq mode.

So far I have fixed what you have sent and implemented a new patch for
the "heuristic" irq mode. I will try to run in on hw tomorrow and send
a new patchset with the patches that have not been merged yet.

Maybe you want to consider also this patch from Michal Simek to your
topic/xilinx branch

https://patchwork.kernel.org/patch/5648351/

Thanks!
Mark Brown Jan. 27, 2015, 7:49 p.m. UTC | #3
On Tue, Jan 27, 2015 at 08:05:57PM +0100, Ricardo Ribalda Delgado wrote:

> > Right, for short transfers polling tends to win every time over
> > interrupts - if you look at other controller drivers you'll see a lot of
> > them use this technique.  The best practice here is generally to use a
> > copy break and do very short transfers in polling mode and go back to
> > interrupts for larger ones.  This break is typically done at the point
> > where we go over a FIFO in transfer size since normally if the device is
> > designed to be run with DMA the FIFO will be quite small.

> Seems very reasonable. Only problem I can see is if the spi clk is
> veeery slow, then a irq approach, even for transfer size bellow
> buffer_size will be better.

Yeah, there's a bit of guesswork in there though practically speaking
people tend not to make SPI *that* slow since one of the reasons to use
it over I2C is performance.  You can do things like estimate how long
the transfer should be based on the clock rate and shove a msleep() in
there as well.

> > Obviously this isn't quite the same case since not only is there no DMA
> > support (yet?) but the FIFO could be any size but similar things apply
> > especially if someone configured the device with a large FIFO.

> The hardware does not support dma (at least without making use of
> another core called cdma....)

Yes, that's standard - it's very rare to see a SPI controller with
integrated DMA.  Usually the IP will bring out signals which can
handshake with a DMA controller to control flow.

> We can always argue that the system engineer can select polling by not
> specifying an irq on the device tree.

The DT should describe the hardware, performance tuning doesn't really
come into that - what if the driver gets better and can be smarter about
interrupts or the best tuning varies at runtime?

> >> +     xspi_init_hw(xspi);

> > This appears to move the interrupt request before the hardware reset.
> > Are you sure the interrupt handler won't misbehave if it fires before we
> > finished initializing?  One thing the hardware reset should do is get
> > the device in a known good state.

> The hardware will be reseted and in good state by the function
> find_buffer_size, so this should be good. Also the initialization is
> slightly different for polling and irq mode.

> So far I have fixed what you have sent and implemented a new patch for
> the "heuristic" irq mode. I will try to run in on hw tomorrow and send
> a new patchset with the patches that have not been merged yet.

OK.

> Maybe you want to consider also this patch from Michal Simek to your
> topic/xilinx branch

> https://patchwork.kernel.org/patch/5648351/

Please include plain text descriptions of things in your mails rather
than just links/numbers.
Ricardo Ribalda Delgado Jan. 27, 2015, 7:56 p.m. UTC | #4
Hello

On Tue, Jan 27, 2015 at 8:49 PM, Mark Brown <broonie@kernel.org> wrote:
>
>> https://patchwork.kernel.org/patch/5648351/
>
> Please include plain text descriptions of things in your mails rather
> than just links/numbers.

spi: xilinx: Use standard num-cs binding


Regards!
diff mbox

Patch

diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 3f8450d..8a28cab 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -173,8 +173,11 @@  static void xspi_init_hw(struct xilinx_spi *xspi)
 	xspi->write_fn(XSPI_INTR_TX_EMPTY,
 			regs_base + XIPIF_V123B_IIER_OFFSET);
 	/* Enable the global IPIF interrupt */
-	xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
-		regs_base + XIPIF_V123B_DGIER_OFFSET);
+	if (xspi->irq >= 0)
+		xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
+			regs_base + XIPIF_V123B_DGIER_OFFSET);
+	else
+		xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
 	/* Deselect the slave on the SPI bus */
 	xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET);
 	/* Disable the transmitter, enable Manual Slave Select Assertion,
@@ -264,7 +267,12 @@  static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
 							~XSPI_CR_TRANS_INHIBIT;
 		xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
 
-		wait_for_completion(&xspi->done);
+		if (xspi->irq >= 0)
+			wait_for_completion(&xspi->done);
+		else
+			while (!(xspi->read_fn(xspi->regs + XSPI_SR_OFFSET) &
+						XSPI_SR_TX_EMPTY_MASK))
+				;
 
 		/* A transmit has just completed. Process received data and
 		 * check for more data to transmit. Always inhibit the
@@ -412,20 +420,17 @@  static int xilinx_spi_probe(struct platform_device *pdev)
 
 	xspi->buffer_size = xilinx_spi_find_buffer_size(xspi);
 
-	/* SPI controller initializations */
-	xspi_init_hw(xspi);
-
 	xspi->irq = platform_get_irq(pdev, 0);
-	if (xspi->irq < 0) {
-		ret = xspi->irq;
-		goto put_master;
+	if (xspi->irq >= 0) {
+		/* Register for SPI Interrupt */
+		ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
+				dev_name(&pdev->dev), xspi);
+		if (ret)
+			goto put_master;
 	}
 
-	/* Register for SPI Interrupt */
-	ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
-			       dev_name(&pdev->dev), xspi);
-	if (ret)
-		goto put_master;
+	/* SPI controller initializations */
+	xspi_init_hw(xspi);
 
 	ret = spi_bitbang_start(&xspi->bitbang);
 	if (ret) {