aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2016-12-04 08:22:58 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-12-06 05:03:22 -0500
commit4a8efd4a1a9593a11c808da94e6609f6d4ee7276 (patch)
treeeab8e4f71db36b5d70e480f09d1e90acf6119a27
parent8d7cc7adcec55bfeb28cc2dc58b996c95f180337 (diff)
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>
-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)
285} 285}
286 286
287/** 287/**
288 * mei_me_synchronize_irq - wait for pending IRQ handlers
289 *
290 * @dev: the device structure
291 */
292static void mei_me_synchronize_irq(struct mei_device *dev)
293{
294 struct pci_dev *pdev = to_pci_dev(dev->dev);
295
296 synchronize_irq(pdev->irq);
297}
298
299/**
288 * mei_me_hw_reset_release - release device from the reset 300 * mei_me_hw_reset_release - release device from the reset
289 * 301 *
290 * @dev: the device structure 302 * @dev: the device structure
@@ -1238,6 +1250,7 @@ static const struct mei_hw_ops mei_me_hw_ops = {
1238 .intr_clear = mei_me_intr_clear, 1250 .intr_clear = mei_me_intr_clear,
1239 .intr_enable = mei_me_intr_enable, 1251 .intr_enable = mei_me_intr_enable,
1240 .intr_disable = mei_me_intr_disable, 1252 .intr_disable = mei_me_intr_disable,
1253 .synchronize_irq = mei_me_synchronize_irq,
1241 1254
1242 .hbuf_free_slots = mei_me_hbuf_empty_slots, 1255 .hbuf_free_slots = mei_me_hbuf_empty_slots,
1243 .hbuf_is_ready = mei_me_hbuf_is_empty, 1256 .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 @@
19#include <linux/ktime.h> 19#include <linux/ktime.h>
20#include <linux/delay.h> 20#include <linux/delay.h>
21#include <linux/kthread.h> 21#include <linux/kthread.h>
22#include <linux/irqreturn.h> 22#include <linux/interrupt.h>
23#include <linux/pm_runtime.h> 23#include <linux/pm_runtime.h>
24 24
25#include <linux/mei.h> 25#include <linux/mei.h>
@@ -441,6 +441,18 @@ static void mei_txe_intr_enable(struct mei_device *dev)
441} 441}
442 442
443/** 443/**
444 * mei_txe_synchronize_irq - wait for pending IRQ handlers
445 *
446 * @dev: the device structure
447 */
448static void mei_txe_synchronize_irq(struct mei_device *dev)
449{
450 struct pci_dev *pdev = to_pci_dev(dev->dev);
451
452 synchronize_irq(pdev->irq);
453}
454
455/**
444 * mei_txe_pending_interrupts - check if there are pending interrupts 456 * mei_txe_pending_interrupts - check if there are pending interrupts
445 * only Aliveness, Input ready, and output doorbell are of relevance 457 * only Aliveness, Input ready, and output doorbell are of relevance
446 * 458 *
@@ -1168,6 +1180,7 @@ static const struct mei_hw_ops mei_txe_hw_ops = {
1168 .intr_clear = mei_txe_intr_clear, 1180 .intr_clear = mei_txe_intr_clear,
1169 .intr_enable = mei_txe_intr_enable, 1181 .intr_enable = mei_txe_intr_enable,
1170 .intr_disable = mei_txe_intr_disable, 1182 .intr_disable = mei_txe_intr_disable,
1183 .synchronize_irq = mei_txe_synchronize_irq,
1171 1184
1172 .hbuf_free_slots = mei_txe_hbuf_empty_slots, 1185 .hbuf_free_slots = mei_txe_hbuf_empty_slots,
1173 .hbuf_is_ready = mei_txe_is_input_ready, 1186 .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)
122 mei_dev_state_str(state), fw_sts_str); 122 mei_dev_state_str(state), fw_sts_str);
123 } 123 }
124 124
125 mei_clear_interrupts(dev);
126
127 mei_synchronize_irq(dev);
128
125 /* we're already in reset, cancel the init timer 129 /* we're already in reset, cancel the init timer
126 * if the reset was called due the hbm protocol error 130 * if the reset was called due the hbm protocol error
127 * we need to call it before hw start 131 * we need to call it before hw start
@@ -273,8 +277,6 @@ int mei_restart(struct mei_device *dev)
273 277
274 mutex_lock(&dev->device_lock); 278 mutex_lock(&dev->device_lock);
275 279
276 mei_clear_interrupts(dev);
277
278 dev->dev_state = MEI_DEV_POWER_UP; 280 dev->dev_state = MEI_DEV_POWER_UP;
279 dev->reset_count = 0; 281 dev->reset_count = 0;
280 282
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 {
267 * @intr_clear : clear pending interrupts 267 * @intr_clear : clear pending interrupts
268 * @intr_enable : enable interrupts 268 * @intr_enable : enable interrupts
269 * @intr_disable : disable interrupts 269 * @intr_disable : disable interrupts
270 * @synchronize_irq : synchronize irqs
270 * 271 *
271 * @hbuf_free_slots : query for write buffer empty slots 272 * @hbuf_free_slots : query for write buffer empty slots
272 * @hbuf_is_ready : query if write buffer is empty 273 * @hbuf_is_ready : query if write buffer is empty
@@ -288,7 +289,6 @@ struct mei_hw_ops {
288 int (*hw_start)(struct mei_device *dev); 289 int (*hw_start)(struct mei_device *dev);
289 void (*hw_config)(struct mei_device *dev); 290 void (*hw_config)(struct mei_device *dev);
290 291
291
292 int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts); 292 int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts);
293 enum mei_pg_state (*pg_state)(struct mei_device *dev); 293 enum mei_pg_state (*pg_state)(struct mei_device *dev);
294 bool (*pg_in_transition)(struct mei_device *dev); 294 bool (*pg_in_transition)(struct mei_device *dev);
@@ -297,6 +297,7 @@ struct mei_hw_ops {
297 void (*intr_clear)(struct mei_device *dev); 297 void (*intr_clear)(struct mei_device *dev);
298 void (*intr_enable)(struct mei_device *dev); 298 void (*intr_enable)(struct mei_device *dev);
299 void (*intr_disable)(struct mei_device *dev); 299 void (*intr_disable)(struct mei_device *dev);
300 void (*synchronize_irq)(struct mei_device *dev);
300 301
301 int (*hbuf_free_slots)(struct mei_device *dev); 302 int (*hbuf_free_slots)(struct mei_device *dev);
302 bool (*hbuf_is_ready)(struct mei_device *dev); 303 bool (*hbuf_is_ready)(struct mei_device *dev);
@@ -640,6 +641,11 @@ static inline void mei_disable_interrupts(struct mei_device *dev)
640 dev->ops->intr_disable(dev); 641 dev->ops->intr_disable(dev);
641} 642}
642 643
644static inline void mei_synchronize_irq(struct mei_device *dev)
645{
646 dev->ops->synchronize_irq(dev);
647}
648
643static inline bool mei_host_is_ready(struct mei_device *dev) 649static inline bool mei_host_is_ready(struct mei_device *dev)
644{ 650{
645 return dev->ops->host_is_ready(dev); 651 return dev->ops->host_is_ready(dev);