Commit 4a8efd4a authored by Tomas Winkler's avatar Tomas Winkler Committed by Greg Kroah-Hartman

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: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 8d7cc7ad
...@@ -284,6 +284,18 @@ static void mei_me_intr_disable(struct mei_device *dev) ...@@ -284,6 +284,18 @@ static void mei_me_intr_disable(struct mei_device *dev)
mei_hcsr_set(dev, hcsr); mei_hcsr_set(dev, hcsr);
} }
/**
* 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 * mei_me_hw_reset_release - release device from the reset
* *
...@@ -1238,6 +1250,7 @@ static const struct mei_hw_ops mei_me_hw_ops = { ...@@ -1238,6 +1250,7 @@ static const struct mei_hw_ops mei_me_hw_ops = {
.intr_clear = mei_me_intr_clear, .intr_clear = mei_me_intr_clear,
.intr_enable = mei_me_intr_enable, .intr_enable = mei_me_intr_enable,
.intr_disable = mei_me_intr_disable, .intr_disable = mei_me_intr_disable,
.synchronize_irq = mei_me_synchronize_irq,
.hbuf_free_slots = mei_me_hbuf_empty_slots, .hbuf_free_slots = mei_me_hbuf_empty_slots,
.hbuf_is_ready = mei_me_hbuf_is_empty, .hbuf_is_ready = mei_me_hbuf_is_empty,
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <linux/ktime.h> #include <linux/ktime.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/irqreturn.h> #include <linux/interrupt.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/mei.h> #include <linux/mei.h>
...@@ -440,6 +440,18 @@ static void mei_txe_intr_enable(struct mei_device *dev) ...@@ -440,6 +440,18 @@ static void mei_txe_intr_enable(struct mei_device *dev)
mei_txe_br_reg_write(hw, HIER_REG, HIER_INT_EN_MSK); mei_txe_br_reg_write(hw, HIER_REG, HIER_INT_EN_MSK);
} }
/**
* 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 * mei_txe_pending_interrupts - check if there are pending interrupts
* only Aliveness, Input ready, and output doorbell are of relevance * only Aliveness, Input ready, and output doorbell are of relevance
...@@ -1168,6 +1180,7 @@ static const struct mei_hw_ops mei_txe_hw_ops = { ...@@ -1168,6 +1180,7 @@ static const struct mei_hw_ops mei_txe_hw_ops = {
.intr_clear = mei_txe_intr_clear, .intr_clear = mei_txe_intr_clear,
.intr_enable = mei_txe_intr_enable, .intr_enable = mei_txe_intr_enable,
.intr_disable = mei_txe_intr_disable, .intr_disable = mei_txe_intr_disable,
.synchronize_irq = mei_txe_synchronize_irq,
.hbuf_free_slots = mei_txe_hbuf_empty_slots, .hbuf_free_slots = mei_txe_hbuf_empty_slots,
.hbuf_is_ready = mei_txe_is_input_ready, .hbuf_is_ready = mei_txe_is_input_ready,
......
...@@ -122,6 +122,10 @@ int mei_reset(struct mei_device *dev) ...@@ -122,6 +122,10 @@ int mei_reset(struct mei_device *dev)
mei_dev_state_str(state), fw_sts_str); 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 /* we're already in reset, cancel the init timer
* if the reset was called due the hbm protocol error * if the reset was called due the hbm protocol error
* we need to call it before hw start * we need to call it before hw start
...@@ -273,8 +277,6 @@ int mei_restart(struct mei_device *dev) ...@@ -273,8 +277,6 @@ int mei_restart(struct mei_device *dev)
mutex_lock(&dev->device_lock); mutex_lock(&dev->device_lock);
mei_clear_interrupts(dev);
dev->dev_state = MEI_DEV_POWER_UP; dev->dev_state = MEI_DEV_POWER_UP;
dev->reset_count = 0; dev->reset_count = 0;
......
...@@ -267,6 +267,7 @@ struct mei_cl { ...@@ -267,6 +267,7 @@ struct mei_cl {
* @intr_clear : clear pending interrupts * @intr_clear : clear pending interrupts
* @intr_enable : enable interrupts * @intr_enable : enable interrupts
* @intr_disable : disable interrupts * @intr_disable : disable interrupts
* @synchronize_irq : synchronize irqs
* *
* @hbuf_free_slots : query for write buffer empty slots * @hbuf_free_slots : query for write buffer empty slots
* @hbuf_is_ready : query if write buffer is empty * @hbuf_is_ready : query if write buffer is empty
...@@ -288,7 +289,6 @@ struct mei_hw_ops { ...@@ -288,7 +289,6 @@ struct mei_hw_ops {
int (*hw_start)(struct mei_device *dev); int (*hw_start)(struct mei_device *dev);
void (*hw_config)(struct mei_device *dev); void (*hw_config)(struct mei_device *dev);
int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts); int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts);
enum mei_pg_state (*pg_state)(struct mei_device *dev); enum mei_pg_state (*pg_state)(struct mei_device *dev);
bool (*pg_in_transition)(struct mei_device *dev); bool (*pg_in_transition)(struct mei_device *dev);
...@@ -297,6 +297,7 @@ struct mei_hw_ops { ...@@ -297,6 +297,7 @@ struct mei_hw_ops {
void (*intr_clear)(struct mei_device *dev); void (*intr_clear)(struct mei_device *dev);
void (*intr_enable)(struct mei_device *dev); void (*intr_enable)(struct mei_device *dev);
void (*intr_disable)(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); int (*hbuf_free_slots)(struct mei_device *dev);
bool (*hbuf_is_ready)(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) ...@@ -640,6 +641,11 @@ static inline void mei_disable_interrupts(struct mei_device *dev)
dev->ops->intr_disable(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) static inline bool mei_host_is_ready(struct mei_device *dev)
{ {
return dev->ops->host_is_ready(dev); return dev->ops->host_is_ready(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment