mei: stop the stall timer worker if not needed
authorAlexander Usyskin <alexander.usyskin@intel.com>
Sun, 25 Sep 2016 10:25:31 +0000 (13:25 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 27 Sep 2016 10:33:47 +0000 (12:33 +0200)
The stall timer worker checks periodically if there is a stalled i/o
transaction. The issue with the current implementation is that the timer
is ticking also when there is no pending i/o transaction.
This patch provides a simple change that prevents rescheduling
of the delayed work when there is no pending i/o.

Cc: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/mei/amthif.c
drivers/misc/mei/client.c
drivers/misc/mei/hbm.c
drivers/misc/mei/init.c
drivers/misc/mei/interrupt.c
drivers/misc/mei/mei_dev.h
drivers/misc/mei/pci-me.c

index 082462e..7ae89b4 100644 (file)
@@ -277,6 +277,7 @@ void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
        case MEI_FOP_WRITE:
                if (!cb->status) {
                        dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
+                       mei_schedule_stall_timer(dev);
                        mei_io_cb_free(cb);
                        return;
                }
index 45a7652..6fe0235 100644 (file)
@@ -826,6 +826,7 @@ static int mei_cl_send_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb)
 
        list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
        cl->timer_count = MEI_CONNECT_TIMEOUT;
+       mei_schedule_stall_timer(dev);
 
        return 0;
 }
@@ -1011,6 +1012,7 @@ static int mei_cl_send_connect(struct mei_cl *cl, struct mei_cl_cb *cb)
 
        list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
        cl->timer_count = MEI_CONNECT_TIMEOUT;
+       mei_schedule_stall_timer(dev);
        return 0;
 }
 
index 4b9495f..dd7f15a 100644 (file)
@@ -277,6 +277,7 @@ int mei_hbm_start_req(struct mei_device *dev)
 
        dev->hbm_state = MEI_HBM_STARTING;
        dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
+       mei_schedule_stall_timer(dev);
        return 0;
 }
 
@@ -312,6 +313,7 @@ static int mei_hbm_enum_clients_req(struct mei_device *dev)
        }
        dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
        dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
+       mei_schedule_stall_timer(dev);
        return 0;
 }
 
@@ -562,6 +564,7 @@ static int mei_hbm_prop_req(struct mei_device *dev, unsigned long start_idx)
        }
 
        dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
+       mei_schedule_stall_timer(dev);
 
        return 0;
 }
index f7c8dfd..9a9c248 100644 (file)
@@ -94,7 +94,7 @@ void mei_cancel_work(struct mei_device *dev)
        cancel_work_sync(&dev->reset_work);
        cancel_work_sync(&dev->bus_rescan_work);
 
-       cancel_delayed_work(&dev->timer_work);
+       cancel_delayed_work_sync(&dev->timer_work);
 }
 EXPORT_SYMBOL_GPL(mei_cancel_work);
 
index bf745e0..5a4893c 100644 (file)
@@ -459,6 +459,19 @@ static void mei_connect_timeout(struct mei_cl *cl)
        mei_reset(dev);
 }
 
+#define MEI_STALL_TIMER_FREQ (2 * HZ)
+/**
+ * mei_schedule_stall_timer - re-arm stall_timer work
+ *
+ * Schedule stall timer
+ *
+ * @dev: the device structure
+ */
+void mei_schedule_stall_timer(struct mei_device *dev)
+{
+       schedule_delayed_work(&dev->timer_work, MEI_STALL_TIMER_FREQ);
+}
+
 /**
  * mei_timer - timer function.
  *
@@ -468,10 +481,9 @@ static void mei_connect_timeout(struct mei_cl *cl)
 void mei_timer(struct work_struct *work)
 {
        struct mei_cl *cl;
-
        struct mei_device *dev = container_of(work,
                                        struct mei_device, timer_work.work);
-
+       bool reschedule_timer = false;
 
        mutex_lock(&dev->device_lock);
 
@@ -486,6 +498,7 @@ void mei_timer(struct work_struct *work)
                                mei_reset(dev);
                                goto out;
                        }
+                       reschedule_timer = true;
                }
        }
 
@@ -500,6 +513,7 @@ void mei_timer(struct work_struct *work)
                                mei_connect_timeout(cl);
                                goto out;
                        }
+                       reschedule_timer = true;
                }
        }
 
@@ -512,11 +526,14 @@ void mei_timer(struct work_struct *work)
                        mei_reset(dev);
 
                        mei_amthif_run_next_cmd(dev);
+                       goto out;
                }
+               reschedule_timer = true;
        }
 
 out:
-       if (dev->dev_state != MEI_DEV_DISABLED)
-               schedule_delayed_work(&dev->timer_work, 2 * HZ);
+       if (dev->dev_state != MEI_DEV_DISABLED && reschedule_timer)
+               mei_schedule_stall_timer(dev);
+
        mutex_unlock(&dev->device_lock);
 }
index 397ae2b..1169fd9 100644 (file)
@@ -548,6 +548,7 @@ void mei_cancel_work(struct mei_device *dev);
  */
 
 void mei_timer(struct work_struct *work);
+void mei_schedule_stall_timer(struct mei_device *dev);
 int mei_irq_read_handler(struct mei_device *dev,
                struct mei_cl_cb *cmpl_list, s32 *slots);
 
index e85bb37..f3ffd88 100644 (file)
@@ -220,8 +220,6 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        pci_set_drvdata(pdev, dev);
 
-       schedule_delayed_work(&dev->timer_work, HZ);
-
        /*
        * For not wake-able HW runtime pm framework
        * can't be used on pci device level.