If the controller driver receives I/O from SPI core while in
runtime-PM suspend it must autonomously resume but if it is
called from a non-sleepable context it may return EBUSY until
fully resumed. Testing has shown the trasklet is rescheduled a large
number of times waiting the resume processing to complete.

We've added a retry delay timer (1ms) in case spi_async returns EBUSY.

Signed-off-by: Russ Gorby <[email protected]>
---
 drivers/serial/ifx6x60.c |   51 +++++++++++++++++++++++++++++++++++++++------
 drivers/serial/ifx6x60.h |    3 ++
 2 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/drivers/serial/ifx6x60.c b/drivers/serial/ifx6x60.c
index 79b108b..bb85be2 100644
--- a/drivers/serial/ifx6x60.c
+++ b/drivers/serial/ifx6x60.c
@@ -936,6 +936,19 @@ static void ifx_spi_insert_flip_string(struct 
ifx_spi_serial *ifx_ser,
 }
 
 /**
+ * ifx_spi_retry_timer_fn - Timer function for ifx_spi_complete()
+ * @data: Device pointer passed by ifx_spi_complete().
+ *
+ * The delay timer has expired so reschedule the tasklet
+ */
+static void ifx_spi_retry_timer_fn(unsigned long data)
+{
+       struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)data;
+
+       tasklet_schedule(&ifx_dev->io_work_tasklet);
+}
+
+/**
  *     ifx_spi_complete        -       SPI transfer completed
  *     @ctx: our SPI device
  *
@@ -1011,6 +1024,10 @@ complete_exit:
        }
 
        clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &(ifx_dev->flags));
+       clear_bit(IFX_SPI_STATE_IO_RETRY, &ifx_dev->flags);
+       WARN_ON(timer_pending(&ifx_dev->spi_retry_timer));
+       del_timer(&ifx_dev->spi_retry_timer);
+
 
        queue_length = (port_data == NULL) ? 0 : kfifo_len(&port_data->tx_fifo);
        srdy = gpio_get_value(ifx_dev->gpio.srdy);
@@ -1074,6 +1091,21 @@ complete_exit:
 }
 
 /**
+ * ifx_spi_retry       - start or extend the I/O retry delay timer
+ */
+static void
+ifx_spi_retry(struct ifx_spi_device *ifx_dev)
+{
+       unsigned long expires;
+
+       if (!test_and_set_bit(IFX_SPI_STATE_IO_RETRY, &ifx_dev->flags))
+               setup_timer(&ifx_dev->spi_retry_timer, ifx_spi_retry_timer_fn,
+                           (unsigned long)ifx_dev);
+       expires = jiffies + IFX_RETRY_TIMEOUT;
+       mod_timer(&ifx_dev->spi_retry_timer, expires);
+}
+
+/**
  *     ifx_spio_io             -       I/O tasklet
  *     @data: our SPI device
  *
@@ -1145,13 +1177,17 @@ static void ifx_spi_io(unsigned long data)
                if (retval) {
                        if (retval != -EBUSY)
                                ifx_spi_complete((void *)ifx_dev);
-                       else {
-                               dev_dbg(&ifx_dev->spi_dev->dev,
-                                       "spi_async failed (%d)", retval);
-                               clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS,
-                                         &ifx_dev->flags);
-                               tasklet_schedule(&ifx_dev->io_work_tasklet);
-                       }
+                       else
+                               ifx_spi_retry(ifx_dev);
+                       return;
+               }
+       } else if (test_bit(IFX_SPI_STATE_IO_RETRY, &ifx_dev->flags)) {
+               retval = spi_async(ifx_dev->spi_dev, &ifx_dev->spi_msg);
+               if (retval) {
+                       if (retval != -EBUSY)
+                               ifx_spi_complete((void *)ifx_dev);
+                       else
+                               ifx_spi_retry(ifx_dev);
                        return;
                }
        } else {
@@ -1460,6 +1496,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
        spin_lock_init(&ifx_dev->power_lock);
        ifx_dev->power_status = 0;
        init_timer(&ifx_dev->spi_timer);
+       init_timer(&ifx_dev->spi_retry_timer);
        ifx_dev->spi_timer.function = ifx_spi_timeout;
        ifx_dev->spi_timer.data = (unsigned long)ifx_dev;
 
diff --git a/drivers/serial/ifx6x60.h b/drivers/serial/ifx6x60.h
index c4d11fe..da1efc6 100644
--- a/drivers/serial/ifx6x60.h
+++ b/drivers/serial/ifx6x60.h
@@ -38,12 +38,14 @@
 #define IFX_SPI_FIFO_SIZE              4096
 
 #define IFX_SPI_HEADER_OVERHEAD                4
+#define IFX_RETRY_TIMEOUT              msecs_to_jiffies(1)
 #define IFX_RESET_TIMEOUT              msecs_to_jiffies(50)
 
 /* device state bit offsets */
 enum ifx_spi_state {
        IFX_SPI_STATE_PRESENT,
        IFX_SPI_STATE_IO_IN_PROGRESS,
+       IFX_SPI_STATE_IO_RETRY,
        IFX_SPI_STATE_IO_READY,
        IFX_SPI_STATE_TIMER_PENDING,
 };
@@ -103,6 +105,7 @@ struct ifx_spi_device {
        unsigned char spi_slave_cts;
 
        struct timer_list spi_timer;
+       struct timer_list spi_retry_timer;
 
        struct spi_message spi_msg;
        struct spi_transfer spi_xfer;
-- 
1.6.0.6

_______________________________________________
MeeGo-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel

Reply via email to