aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2016-12-04 15:22:58 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-12-06 11:03:22 +0100
commit4a8efd4a1a9593a11c808da94e6609f6d4ee7276 (patch)
treeeab8e4f71db36b5d70e480f09d1e90acf6119a27 /drivers/misc
parentVME: Remove shutdown entry from vme_driver (diff)
downloadlinux-dev-4a8efd4a1a9593a11c808da94e6609f6d4ee7276.tar.xz
linux-dev-4a8efd4a1a9593a11c808da94e6609f6d4ee7276.zip
mei: synchronize irq before initiating a reset.
We need to synchronize irqs before issuing reset to make sure that the clients communication is concluded and doesn't leak to the reset flow and confusing the state machine. This issue is happening during suspend/resume stress testing. Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/mei/hw-me.c13
-rw-r--r--drivers/misc/mei/hw-txe.c15
-rw-r--r--drivers/misc/mei/init.c6
-rw-r--r--drivers/misc/mei/mei_dev.h8
4 files changed, 38 insertions, 4 deletions
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 998f7fc0e920..e2b56e8cf745 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -285,6 +285,18 @@ static void mei_me_intr_disable(struct mei_device *dev)
}
/**
+ * mei_me_synchronize_irq - wait for pending IRQ handlers
+ *
+ * @dev: the device structure
+ */
+static void mei_me_synchronize_irq(struct mei_device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+
+ synchronize_irq(pdev->irq);
+}
+
+/**
* mei_me_hw_reset_release - release device from the reset
*
* @dev: the device structure
@@ -1238,6 +1250,7 @@ static const struct mei_hw_ops mei_me_hw_ops = {
.intr_clear = mei_me_intr_clear,
.intr_enable = mei_me_intr_enable,
.intr_disable = mei_me_intr_disable,
+ .synchronize_irq = mei_me_synchronize_irq,
.hbuf_free_slots = mei_me_hbuf_empty_slots,
.hbuf_is_ready = mei_me_hbuf_is_empty,
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c
index b7a2f622f23c..e9f8c0aeec13 100644
--- a/drivers/misc/mei/hw-txe.c
+++ b/drivers/misc/mei/hw-txe.c
@@ -19,7 +19,7 @@
#include <linux/ktime.h>
#include <linux/delay.h>
#include <linux/kthread.h>
-#include <linux/irqreturn.h>
+#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/mei.h>
@@ -441,6 +441,18 @@ static void mei_txe_intr_enable(struct mei_device *dev)
}
/**
+ * mei_txe_synchronize_irq - wait for pending IRQ handlers
+ *
+ * @dev: the device structure
+ */
+static void mei_txe_synchronize_irq(struct mei_device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+
+ synchronize_irq(pdev->irq);
+}
+
+/**
* mei_txe_pending_interrupts - check if there are pending interrupts
* only Aliveness, Input ready, and output doorbell are of relevance
*
@@ -1168,6 +1180,7 @@ static const struct mei_hw_ops mei_txe_hw_ops = {
.intr_clear = mei_txe_intr_clear,
.intr_enable = mei_txe_intr_enable,
.intr_disable = mei_txe_intr_disable,
+ .synchronize_irq = mei_txe_synchronize_irq,
.hbuf_free_slots = mei_txe_hbuf_empty_slots,
.hbuf_is_ready = mei_txe_is_input_ready,
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 9a9c2484d107..41e5760a6886 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -122,6 +122,10 @@ int mei_reset(struct mei_device *dev)
mei_dev_state_str(state), fw_sts_str);
}
+ mei_clear_interrupts(dev);
+
+ mei_synchronize_irq(dev);
+
/* we're already in reset, cancel the init timer
* if the reset was called due the hbm protocol error
* we need to call it before hw start
@@ -273,8 +277,6 @@ int mei_restart(struct mei_device *dev)
mutex_lock(&dev->device_lock);
- mei_clear_interrupts(dev);
-
dev->dev_state = MEI_DEV_POWER_UP;
dev->reset_count = 0;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 82e69a00b7a1..0e94df517410 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -267,6 +267,7 @@ struct mei_cl {
* @intr_clear : clear pending interrupts
* @intr_enable : enable interrupts
* @intr_disable : disable interrupts
+ * @synchronize_irq : synchronize irqs
*
* @hbuf_free_slots : query for write buffer empty slots
* @hbuf_is_ready : query if write buffer is empty
@@ -288,7 +289,6 @@ struct mei_hw_ops {
int (*hw_start)(struct mei_device *dev);
void (*hw_config)(struct mei_device *dev);
-
int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts);
enum mei_pg_state (*pg_state)(struct mei_device *dev);
bool (*pg_in_transition)(struct mei_device *dev);
@@ -297,6 +297,7 @@ struct mei_hw_ops {
void (*intr_clear)(struct mei_device *dev);
void (*intr_enable)(struct mei_device *dev);
void (*intr_disable)(struct mei_device *dev);
+ void (*synchronize_irq)(struct mei_device *dev);
int (*hbuf_free_slots)(struct mei_device *dev);
bool (*hbuf_is_ready)(struct mei_device *dev);
@@ -640,6 +641,11 @@ static inline void mei_disable_interrupts(struct mei_device *dev)
dev->ops->intr_disable(dev);
}
+static inline void mei_synchronize_irq(struct mei_device *dev)
+{
+ dev->ops->synchronize_irq(dev);
+}
+
static inline bool mei_host_is_ready(struct mei_device *dev)
{
return dev->ops->host_is_ready(dev);