staging: most: i2c: do not wait in work function
authorChristian Gromm <christian.gromm@microchip.com>
Tue, 8 May 2018 09:44:56 +0000 (11:44 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 8 May 2018 11:41:49 +0000 (13:41 +0200)
This patch removes the function wait_event_interruptible from the
work function to avoid waiting.

Signed-off-by: Christian Gromm <christian.gromm@microchip.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/most/i2c/i2c.c

index b382f09..a993e8e 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/err.h>
 
@@ -47,9 +46,9 @@ struct hdm_i2c {
        struct i2c_client *client;
        struct rx {
                struct delayed_work dwork;
-               wait_queue_head_t waitq;
                struct list_head list;
                struct mutex list_mutex;
+               bool int_disabled;
        } rx;
        char name[64];
 };
@@ -57,6 +56,7 @@ struct hdm_i2c {
 #define to_hdm(iface) container_of(iface, struct hdm_i2c, most_iface)
 
 static irqreturn_t most_irq_handler(int, void *);
+static void pending_rx_work(struct work_struct *);
 
 /**
  * configure_channel - called from MOST core to configure a channel
@@ -93,6 +93,7 @@ static int configure_channel(struct most_interface *most_iface,
                dev->polling_mode = polling_req || dev->client->irq <= 0;
                if (!dev->polling_mode) {
                        pr_info("Requesting IRQ: %d\n", dev->client->irq);
+                       dev->rx.int_disabled = false;
                        ret = request_irq(dev->client->irq, most_irq_handler, 0,
                                          dev->client->name, dev);
                        if (ret) {
@@ -104,8 +105,6 @@ static int configure_channel(struct most_interface *most_iface,
        }
        if ((channel_config->direction == MOST_CH_RX) && (dev->polling_mode)) {
                pr_info("Using polling at rate: %d times/sec\n", scan_rate);
-               schedule_delayed_work(&dev->rx.dwork,
-                                     msecs_to_jiffies(MSEC_PER_SEC / 4));
        }
        dev->is_open[ch_idx] = true;
 
@@ -134,10 +133,16 @@ static int enqueue(struct most_interface *most_iface,
 
        if (ch_idx == CH_RX) {
                /* RX */
+               if (!dev->polling_mode)
+                       disable_irq(dev->client->irq);
+               cancel_delayed_work_sync(&dev->rx.dwork);
                mutex_lock(&dev->rx.list_mutex);
                list_add_tail(&mbo->list, &dev->rx.list);
                mutex_unlock(&dev->rx.list_mutex);
-               wake_up_interruptible(&dev->rx.waitq);
+               if (dev->rx.int_disabled || dev->polling_mode)
+                       pending_rx_work(&dev->rx.dwork.work);
+               if (!dev->polling_mode)
+                       enable_irq(dev->client->irq);
        } else {
                /* TX */
                ret = i2c_master_send(dev->client, mbo->virt_address,
@@ -194,7 +199,6 @@ static int poison_channel(struct most_interface *most_iface,
                        mutex_lock(&dev->rx.list_mutex);
                }
                mutex_unlock(&dev->rx.list_mutex);
-               wake_up_interruptible(&dev->rx.waitq);
        }
 
        return 0;
@@ -204,7 +208,7 @@ static void do_rx_work(struct hdm_i2c *dev)
 {
        struct mbo *mbo;
        unsigned char msg[MAX_BUF_SIZE_CONTROL];
-       int ret, ch_idx = CH_RX;
+       int ret;
        u16 pml, data_size;
 
        /* Read PML (2 bytes) */
@@ -227,29 +231,7 @@ static void do_rx_work(struct hdm_i2c *dev)
                return;
        }
 
-       for (;;) {
-               /* Conditions to wait for: poisoned channel or free buffer
-                * available for reading
-                */
-               if (wait_event_interruptible(dev->rx.waitq,
-                                            !dev->is_open[ch_idx] ||
-                                            !list_empty(&dev->rx.list))) {
-                       pr_err("wait_event_interruptible() failed\n");
-                       return;
-               }
-
-               if (!dev->is_open[ch_idx])
-                       return;
-
-               mutex_lock(&dev->rx.list_mutex);
-
-               /* list may be empty if poison or remove is called */
-               if (!list_empty(&dev->rx.list))
-                       break;
-
-               mutex_unlock(&dev->rx.list_mutex);
-       }
-
+       mutex_lock(&dev->rx.list_mutex);
        mbo = list_first_mbo(&dev->rx.list);
        list_del(&mbo->list);
        mutex_unlock(&dev->rx.list_mutex);
@@ -269,6 +251,13 @@ static void do_rx_work(struct hdm_i2c *dev)
 static void pending_rx_work(struct work_struct *work)
 {
        struct hdm_i2c *dev = container_of(work, struct hdm_i2c, rx.dwork.work);
+       bool empty;
+
+       mutex_lock(&dev->rx.list_mutex);
+       empty = list_empty(&dev->rx.list);
+       mutex_unlock(&dev->rx.list_mutex);
+       if (empty)
+               return;
 
        do_rx_work(dev);
 
@@ -278,6 +267,7 @@ static void pending_rx_work(struct work_struct *work)
                                              msecs_to_jiffies(MSEC_PER_SEC
                                                               / scan_rate));
        } else {
+               dev->rx.int_disabled = false;
                enable_irq(dev->client->irq);
        }
 }
@@ -305,7 +295,7 @@ static irqreturn_t most_irq_handler(int irq, void *_dev)
        struct hdm_i2c *dev = _dev;
 
        disable_irq_nosync(irq);
-
+       dev->rx.int_disabled = true;
        schedule_delayed_work(&dev->rx.dwork, 0);
 
        return IRQ_HANDLED;
@@ -354,7 +344,6 @@ static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
        INIT_LIST_HEAD(&dev->rx.list);
        mutex_init(&dev->rx.list_mutex);
-       init_waitqueue_head(&dev->rx.waitq);
 
        INIT_DELAYED_WORK(&dev->rx.dwork, pending_rx_work);
 
@@ -407,7 +396,6 @@ static struct i2c_driver i2c_driver = {
 
 module_i2c_driver(i2c_driver);
 
-MODULE_AUTHOR("Jain Roy Ambi <JainRoy.Ambi@microchip.com>");
 MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
 MODULE_DESCRIPTION("I2C Hardware Dependent Module");
 MODULE_LICENSE("GPL");