summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/misc/mei/hbm.c2
-rw-r--r--drivers/misc/mei/hw-me.c10
-rw-r--r--drivers/misc/mei/init.c209
-rw-r--r--drivers/misc/mei/interrupt.c13
-rw-r--r--drivers/misc/mei/mei_dev.h3
-rw-r--r--drivers/misc/mei/pci-me.c10
6 files changed, 143 insertions, 104 deletions
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 8520cdfa2f05..28cd74c073b9 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -763,7 +763,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
return -EPROTO;
}
- dev->dev_state = MEI_DEV_DISABLED;
+ dev->dev_state = MEI_DEV_POWER_DOWN;
dev_info(&dev->pdev->dev, "hbm: stop response: resetting.\n");
/* force the reset */
return -EPROTO;
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 6c07623704c2..6f656c053b14 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -185,7 +185,7 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
mei_me_reg_write(hw, H_CSR, hcsr);
- if (dev->dev_state == MEI_DEV_POWER_DOWN)
+ if (intr_enable == false)
mei_me_hw_reset_release(dev);
return 0;
@@ -482,11 +482,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
mei_clear_interrupts(dev);
/* check if ME wants a reset */
- if (!mei_hw_is_ready(dev) &&
- dev->dev_state != MEI_DEV_RESETTING &&
- dev->dev_state != MEI_DEV_INITIALIZING &&
- dev->dev_state != MEI_DEV_POWER_DOWN &&
- dev->dev_state != MEI_DEV_POWER_UP) {
+ if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) {
dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n");
schedule_work(&dev->reset_work);
goto end;
@@ -514,7 +510,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
break;
dev_dbg(&dev->pdev->dev, "slots to read = %08x\n", slots);
rets = mei_irq_read_handler(dev, &complete_list, &slots);
- if (rets) {
+ if (rets && dev->dev_state != MEI_DEV_RESETTING) {
schedule_work(&dev->reset_work);
goto end;
}
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index c47fa273879e..059133d8caca 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -43,62 +43,13 @@ const char *mei_dev_state_str(int state)
#undef MEI_DEV_STATE
}
-/**
- * mei_start - initializes host and fw to start work.
- *
- * @dev: the device structure
- *
- * returns 0 on success, <0 on failure.
- */
-int mei_start(struct mei_device *dev)
-{
- mutex_lock(&dev->device_lock);
-
- /* acknowledge interrupt and stop interupts */
- mei_clear_interrupts(dev);
-
- mei_hw_config(dev);
-
- dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
-
- mei_reset(dev, 1);
-
- if (mei_hbm_start_wait(dev)) {
- dev_err(&dev->pdev->dev, "HBM haven't started");
- goto err;
- }
-
- if (!mei_host_is_ready(dev)) {
- dev_err(&dev->pdev->dev, "host is not ready.\n");
- goto err;
- }
-
- if (!mei_hw_is_ready(dev)) {
- dev_err(&dev->pdev->dev, "ME is not ready.\n");
- goto err;
- }
-
- if (!mei_hbm_version_is_supported(dev)) {
- dev_dbg(&dev->pdev->dev, "MEI start failed.\n");
- goto err;
- }
-
- dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
-
- mutex_unlock(&dev->device_lock);
- return 0;
-err:
- dev_err(&dev->pdev->dev, "link layer initialization failed.\n");
- dev->dev_state = MEI_DEV_DISABLED;
- mutex_unlock(&dev->device_lock);
- return -ENODEV;
-}
-EXPORT_SYMBOL_GPL(mei_start);
/**
* mei_cancel_work. Cancel mei background jobs
*
* @dev: the device structure
+ *
+ * returns 0 on success or < 0 if the reset hasn't succeeded
*/
void mei_cancel_work(struct mei_device *dev)
{
@@ -113,21 +64,19 @@ EXPORT_SYMBOL_GPL(mei_cancel_work);
* mei_reset - resets host and fw.
*
* @dev: the device structure
- * @interrupts_enabled: if interrupt should be enabled after reset.
*/
-void mei_reset(struct mei_device *dev, int interrupts_enabled)
+int mei_reset(struct mei_device *dev)
{
- bool unexpected;
+ enum mei_dev_state state = dev->dev_state;
+ bool interrupts_enabled;
int ret;
- unexpected = (dev->dev_state != MEI_DEV_INITIALIZING &&
- dev->dev_state != MEI_DEV_DISABLED &&
- dev->dev_state != MEI_DEV_POWER_DOWN &&
- dev->dev_state != MEI_DEV_POWER_UP);
-
- if (unexpected)
+ if (state != MEI_DEV_INITIALIZING &&
+ state != MEI_DEV_DISABLED &&
+ state != MEI_DEV_POWER_DOWN &&
+ state != MEI_DEV_POWER_UP)
dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
- mei_dev_state_str(dev->dev_state));
+ mei_dev_state_str(state));
/* we're already in reset, cancel the init timer
* if the reset was called due the hbm protocol error
@@ -136,25 +85,23 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
*/
mei_hbm_idle(dev);
- ret = mei_hw_reset(dev, interrupts_enabled);
- if (ret) {
- dev_err(&dev->pdev->dev, "hw reset failed disabling the device\n");
- interrupts_enabled = false;
- }
+ /* enter reset flow */
+ interrupts_enabled = state != MEI_DEV_POWER_DOWN;
+ dev->dev_state = MEI_DEV_RESETTING;
+ ret = mei_hw_reset(dev, interrupts_enabled);
+ /* fall through and remove the sw state even if hw reset has failed */
- if (dev->dev_state != MEI_DEV_INITIALIZING &&
- dev->dev_state != MEI_DEV_POWER_UP) {
- if (dev->dev_state != MEI_DEV_DISABLED &&
- dev->dev_state != MEI_DEV_POWER_DOWN)
- dev->dev_state = MEI_DEV_RESETTING;
+ /* no need to clean up software state in case of power up */
+ if (state != MEI_DEV_INITIALIZING &&
+ state != MEI_DEV_POWER_UP) {
/* remove all waiting requests */
mei_cl_all_write_clear(dev);
mei_cl_all_disconnect(dev);
- /* wake up all readings so they can be interrupted */
+ /* wake up all readers and writers so they can be interrupted */
mei_cl_all_wakeup(dev);
/* remove entry if already in list */
@@ -170,33 +117,126 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
dev->rd_msg_hdr = 0;
dev->wd_pending = false;
- if (!interrupts_enabled) {
- dev_dbg(&dev->pdev->dev, "intr not enabled end of reset\n");
+ if (ret) {
+ dev_err(&dev->pdev->dev, "hw_reset failed ret = %d\n", ret);
dev->dev_state = MEI_DEV_DISABLED;
- return;
+ return ret;
+ }
+
+ if (state == MEI_DEV_POWER_DOWN) {
+ dev_dbg(&dev->pdev->dev, "powering down: end of reset\n");
+ dev->dev_state = MEI_DEV_DISABLED;
+ return 0;
}
ret = mei_hw_start(dev);
if (ret) {
- dev_err(&dev->pdev->dev, "hw_start failed disabling the device\n");
+ dev_err(&dev->pdev->dev, "hw_start failed ret = %d\n", ret);
dev->dev_state = MEI_DEV_DISABLED;
- return;
+ return ret;
}
dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
- /* link is established * start sending messages. */
dev->dev_state = MEI_DEV_INIT_CLIENTS;
-
ret = mei_hbm_start_req(dev);
if (ret) {
- dev_err(&dev->pdev->dev, "hbm_start failed disabling the device\n");
+ dev_err(&dev->pdev->dev, "hbm_start failed ret = %d\n", ret);
dev->dev_state = MEI_DEV_DISABLED;
- return;
+ return ret;
}
+
+ return 0;
}
EXPORT_SYMBOL_GPL(mei_reset);
+/**
+ * mei_start - initializes host and fw to start work.
+ *
+ * @dev: the device structure
+ *
+ * returns 0 on success, <0 on failure.
+ */
+int mei_start(struct mei_device *dev)
+{
+ mutex_lock(&dev->device_lock);
+
+ /* acknowledge interrupt and stop interrupts */
+ mei_clear_interrupts(dev);
+
+ mei_hw_config(dev);
+
+ dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
+
+ dev->dev_state = MEI_DEV_INITIALIZING;
+ mei_reset(dev);
+
+ if (dev->dev_state == MEI_DEV_DISABLED) {
+ dev_err(&dev->pdev->dev, "reset failed");
+ goto err;
+ }
+
+ if (mei_hbm_start_wait(dev)) {
+ dev_err(&dev->pdev->dev, "HBM haven't started");
+ goto err;
+ }
+
+ if (!mei_host_is_ready(dev)) {
+ dev_err(&dev->pdev->dev, "host is not ready.\n");
+ goto err;
+ }
+
+ if (!mei_hw_is_ready(dev)) {
+ dev_err(&dev->pdev->dev, "ME is not ready.\n");
+ goto err;
+ }
+
+ if (!mei_hbm_version_is_supported(dev)) {
+ dev_dbg(&dev->pdev->dev, "MEI start failed.\n");
+ goto err;
+ }
+
+ dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
+
+ mutex_unlock(&dev->device_lock);
+ return 0;
+err:
+ dev_err(&dev->pdev->dev, "link layer initialization failed.\n");
+ dev->dev_state = MEI_DEV_DISABLED;
+ mutex_unlock(&dev->device_lock);
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(mei_start);
+
+/**
+ * mei_restart - restart device after suspend
+ *
+ * @dev: the device structure
+ *
+ * returns 0 on success or -ENODEV if the restart hasn't succeeded
+ */
+int mei_restart(struct mei_device *dev)
+{
+ int err;
+
+ mutex_lock(&dev->device_lock);
+
+ mei_clear_interrupts(dev);
+
+ dev->dev_state = MEI_DEV_POWER_UP;
+
+ err = mei_reset(dev);
+
+ mutex_unlock(&dev->device_lock);
+
+ if (err || dev->dev_state == MEI_DEV_DISABLED)
+ return -ENODEV;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mei_restart);
+
+
static void mei_reset_work(struct work_struct *work)
{
struct mei_device *dev =
@@ -204,9 +244,12 @@ static void mei_reset_work(struct work_struct *work)
mutex_lock(&dev->device_lock);
- mei_reset(dev, true);
+ mei_reset(dev);
mutex_unlock(&dev->device_lock);
+
+ if (dev->dev_state == MEI_DEV_DISABLED)
+ dev_err(&dev->pdev->dev, "reset failed");
}
void mei_stop(struct mei_device *dev)
@@ -222,7 +265,7 @@ void mei_stop(struct mei_device *dev)
mei_wd_stop(dev);
dev->dev_state = MEI_DEV_POWER_DOWN;
- mei_reset(dev, 0);
+ mei_reset(dev);
mutex_unlock(&dev->device_lock);
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 2a7277de7ca1..f0fbb5179f80 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -560,7 +560,7 @@ void mei_timer(struct work_struct *work)
if (--dev->init_clients_timer == 0) {
dev_err(&dev->pdev->dev, "timer: init clients timeout hbm_state = %d.\n",
dev->hbm_state);
- mei_reset(dev, 1);
+ mei_reset(dev);
goto out;
}
}
@@ -573,8 +573,8 @@ void mei_timer(struct work_struct *work)
list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
if (cl_pos->timer_count) {
if (--cl_pos->timer_count == 0) {
- dev_err(&dev->pdev->dev, "reset: connect/disconnect timeout.\n");
- mei_reset(dev, 1);
+ dev_err(&dev->pdev->dev, "timer: connect/disconnect timeout.\n");
+ mei_reset(dev);
goto out;
}
}
@@ -582,8 +582,8 @@ void mei_timer(struct work_struct *work)
if (dev->iamthif_stall_timer) {
if (--dev->iamthif_stall_timer == 0) {
- dev_err(&dev->pdev->dev, "reset: amthif hanged.\n");
- mei_reset(dev, 1);
+ dev_err(&dev->pdev->dev, "timer: amthif hanged.\n");
+ mei_reset(dev);
dev->iamthif_msg_buf_size = 0;
dev->iamthif_msg_buf_index = 0;
dev->iamthif_canceled = false;
@@ -636,7 +636,8 @@ void mei_timer(struct work_struct *work)
}
}
out:
- schedule_delayed_work(&dev->timer_work, 2 * HZ);
+ if (dev->dev_state != MEI_DEV_DISABLED)
+ schedule_delayed_work(&dev->timer_work, 2 * HZ);
mutex_unlock(&dev->device_lock);
}
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 2c7692807a4a..a617c8494b70 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -472,8 +472,9 @@ static inline u32 mei_slots2data(int slots)
* mei init function prototypes
*/
void mei_device_init(struct mei_device *dev);
-void mei_reset(struct mei_device *dev, int interrupts);
+int mei_reset(struct mei_device *dev);
int mei_start(struct mei_device *dev);
+int mei_restart(struct mei_device *dev);
void mei_stop(struct mei_device *dev);
void mei_cancel_work(struct mei_device *dev);
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index 8b1deea2abf6..ddadd08956f4 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -321,16 +321,14 @@ static int mei_me_pci_resume(struct device *device)
return err;
}
- mutex_lock(&dev->device_lock);
- dev->dev_state = MEI_DEV_POWER_UP;
- mei_clear_interrupts(dev);
- mei_reset(dev, 1);
- mutex_unlock(&dev->device_lock);
+ err = mei_restart(dev);
+ if (err)
+ return err;
/* Start timer if stopped in suspend */
schedule_delayed_work(&dev->timer_work, HZ);
- return err;
+ return 0;
}
static SIMPLE_DEV_PM_OPS(mei_me_pm_ops, mei_me_pci_suspend, mei_me_pci_resume);
#define MEI_ME_PM_OPS (&mei_me_pm_ops)