OSDN Git Service

HSI: omap_ssi: call msg->complete() from process context
authorSebastian Reichel <sre@kernel.org>
Fri, 20 May 2016 04:25:06 +0000 (06:25 +0200)
committerSebastian Reichel <sre@kernel.org>
Mon, 27 Jun 2016 22:40:00 +0000 (00:40 +0200)
msg->complete() should always be called from process context once
irq_safe runtime pm flag is no longer set for omap-ssi.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
Tested-by: Pavel Machek <pavel@ucw.cz>
drivers/hsi/controllers/omap_ssi.h
drivers/hsi/controllers/omap_ssi_core.c
drivers/hsi/controllers/omap_ssi_port.c

index 99143f4..32ced0c 100644 (file)
@@ -73,6 +73,8 @@ struct omap_ssm_ctx {
  * @txqueue: TX message queues
  * @rxqueue: RX message queues
  * @brkqueue: Queue of incoming HWBREAK requests (FRAME mode)
+ * @errqueue: Queue for failed messages
+ * @errqueue_work: Delayed Work for failed messages
  * @irq: IRQ number
  * @wake_irq: IRQ number for incoming wake line (-1 if none)
  * @wake_gpio: GPIO number for incoming wake line (-1 if none)
@@ -96,6 +98,8 @@ struct omap_ssi_port {
        struct list_head        txqueue[SSI_MAX_CHANNELS];
        struct list_head        rxqueue[SSI_MAX_CHANNELS];
        struct list_head        brkqueue;
+       struct list_head        errqueue;
+       struct delayed_work     errqueue_work;
        unsigned int            irq;
        int                     wake_irq;
        struct gpio_desc        *wake_gpio;
index 79562ce..506a9f1 100644 (file)
@@ -235,7 +235,9 @@ static void ssi_gdd_complete(struct hsi_controller *ssi, unsigned int lch)
                spin_lock(&omap_port->lock);
                list_del(&msg->link); /* Dequeue msg */
                spin_unlock(&omap_port->lock);
-               msg->complete(msg);
+
+               list_add_tail(&msg->link, &omap_port->errqueue);
+               schedule_delayed_work(&omap_port->errqueue_work, 0);
                return;
        }
        spin_lock(&omap_port->lock);
index f91c6a4..7717c76 100644 (file)
@@ -193,6 +193,21 @@ static int ssi_debug_add_port(struct omap_ssi_port *omap_port,
 }
 #endif
 
+static void ssi_process_errqueue(struct work_struct *work)
+{
+       struct omap_ssi_port *omap_port;
+       struct list_head *head, *tmp;
+       struct hsi_msg *msg;
+
+       omap_port = container_of(work, struct omap_ssi_port, errqueue_work.work);
+
+       list_for_each_safe(head, tmp, &omap_port->errqueue) {
+               msg = list_entry(head, struct hsi_msg, link);
+               msg->complete(msg);
+               list_del(head);
+       }
+}
+
 static int ssi_claim_lch(struct hsi_msg *msg)
 {
 
@@ -1170,6 +1185,7 @@ static int ssi_port_probe(struct platform_device *pd)
        omap_port->pdev = &pd->dev;
        omap_port->port_id = port_id;
 
+       INIT_DEFERRABLE_WORK(&omap_port->errqueue_work, ssi_process_errqueue);
        INIT_WORK(&omap_port->work, start_tx_work);
 
        /* initialize HSI port */
@@ -1237,6 +1253,8 @@ static int ssi_port_remove(struct platform_device *pd)
        ssi_debug_remove_port(port);
 #endif
 
+       cancel_delayed_work_sync(&omap_port->errqueue_work);
+
        hsi_port_unregister_clients(port);
 
        port->async     = hsi_dummy_msg;