summaryrefslogtreecommitdiffstats
path: root/drivers/misc/mic/host/mic_boot.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/mic/host/mic_boot.c')
-rw-r--r--drivers/misc/mic/host/mic_boot.c120
1 files changed, 117 insertions, 3 deletions
diff --git a/drivers/misc/mic/host/mic_boot.c b/drivers/misc/mic/host/mic_boot.c
index 60c54d5c43c2..d56b8bf4eaf6 100644
--- a/drivers/misc/mic/host/mic_boot.c
+++ b/drivers/misc/mic/host/mic_boot.c
@@ -37,12 +37,13 @@ static void mic_reset(struct mic_device *mdev)
#define MIC_RESET_TO (45)
+ INIT_COMPLETION(mdev->reset_wait);
mdev->ops->reset_fw_ready(mdev);
mdev->ops->reset(mdev);
for (i = 0; i < MIC_RESET_TO; i++) {
if (mdev->ops->is_fw_ready(mdev))
- return;
+ goto done;
/*
* Resets typically take 10s of seconds to complete.
* Since an MMIO read is required to check if the
@@ -51,6 +52,8 @@ static void mic_reset(struct mic_device *mdev)
msleep(1000);
}
mic_set_state(mdev, MIC_RESET_FAILED);
+done:
+ complete_all(&mdev->reset_wait);
}
/* Initialize the MIC bootparams */
@@ -123,7 +126,8 @@ void mic_stop(struct mic_device *mdev, bool force)
if (MIC_RESET_FAILED == mdev->state)
goto unlock;
mic_set_shutdown_status(mdev, MIC_NOP);
- mic_set_state(mdev, MIC_OFFLINE);
+ if (MIC_SUSPENDED != mdev->state)
+ mic_set_state(mdev, MIC_OFFLINE);
}
unlock:
mutex_unlock(&mdev->mic_mutex);
@@ -165,7 +169,14 @@ void mic_shutdown_work(struct work_struct *work)
mutex_lock(&mdev->mic_mutex);
mic_set_shutdown_status(mdev, bootparam->shutdown_status);
bootparam->shutdown_status = 0;
- if (MIC_SHUTTING_DOWN != mdev->state)
+
+ /*
+ * if state is MIC_SUSPENDED, OSPM suspend is in progress. We do not
+ * change the state here so as to prevent users from booting the card
+ * during and after the suspend operation.
+ */
+ if (MIC_SHUTTING_DOWN != mdev->state &&
+ MIC_SUSPENDED != mdev->state)
mic_set_state(mdev, MIC_SHUTTING_DOWN);
mutex_unlock(&mdev->mic_mutex);
}
@@ -183,3 +194,106 @@ void mic_reset_trigger_work(struct work_struct *work)
mic_stop(mdev, false);
}
+
+/**
+ * mic_complete_resume - Complete MIC Resume after an OSPM suspend/hibernate
+ * event.
+ * @mdev: pointer to mic_device instance
+ *
+ * RETURNS: None.
+ */
+void mic_complete_resume(struct mic_device *mdev)
+{
+ if (mdev->state != MIC_SUSPENDED) {
+ dev_warn(mdev->sdev->parent, "state %d should be %d\n",
+ mdev->state, MIC_SUSPENDED);
+ return;
+ }
+
+ /* Make sure firmware is ready */
+ if (!mdev->ops->is_fw_ready(mdev))
+ mic_stop(mdev, true);
+
+ mutex_lock(&mdev->mic_mutex);
+ mic_set_state(mdev, MIC_OFFLINE);
+ mutex_unlock(&mdev->mic_mutex);
+}
+
+/**
+ * mic_prepare_suspend - Handle suspend notification for the MIC device.
+ * @mdev: pointer to mic_device instance
+ *
+ * RETURNS: None.
+ */
+void mic_prepare_suspend(struct mic_device *mdev)
+{
+ int rc;
+
+#define MIC_SUSPEND_TIMEOUT (60 * HZ)
+
+ mutex_lock(&mdev->mic_mutex);
+ switch (mdev->state) {
+ case MIC_OFFLINE:
+ /*
+ * Card is already offline. Set state to MIC_SUSPENDED
+ * to prevent users from booting the card.
+ */
+ mic_set_state(mdev, MIC_SUSPENDED);
+ mutex_unlock(&mdev->mic_mutex);
+ break;
+ case MIC_ONLINE:
+ /*
+ * Card is online. Set state to MIC_SUSPENDING and notify
+ * MIC user space daemon which will issue card
+ * shutdown and reset.
+ */
+ mic_set_state(mdev, MIC_SUSPENDING);
+ mutex_unlock(&mdev->mic_mutex);
+ rc = wait_for_completion_timeout(&mdev->reset_wait,
+ MIC_SUSPEND_TIMEOUT);
+ /* Force reset the card if the shutdown completion timed out */
+ if (!rc) {
+ mutex_lock(&mdev->mic_mutex);
+ mic_set_state(mdev, MIC_SUSPENDED);
+ mutex_unlock(&mdev->mic_mutex);
+ mic_stop(mdev, true);
+ }
+ break;
+ case MIC_SHUTTING_DOWN:
+ /*
+ * Card is shutting down. Set state to MIC_SUSPENDED
+ * to prevent further boot of the card.
+ */
+ mic_set_state(mdev, MIC_SUSPENDED);
+ mutex_unlock(&mdev->mic_mutex);
+ rc = wait_for_completion_timeout(&mdev->reset_wait,
+ MIC_SUSPEND_TIMEOUT);
+ /* Force reset the card if the shutdown completion timed out */
+ if (!rc)
+ mic_stop(mdev, true);
+ break;
+ default:
+ mutex_unlock(&mdev->mic_mutex);
+ break;
+ }
+}
+
+/**
+ * mic_suspend - Initiate MIC suspend. Suspend merely issues card shutdown.
+ * @mdev: pointer to mic_device instance
+ *
+ * RETURNS: None.
+ */
+void mic_suspend(struct mic_device *mdev)
+{
+ struct mic_bootparam *bootparam = mdev->dp;
+ s8 db = bootparam->h2c_shutdown_db;
+
+ mutex_lock(&mdev->mic_mutex);
+ if (MIC_SUSPENDING == mdev->state && db != -1) {
+ bootparam->shutdown_card = 1;
+ mdev->ops->send_intr(mdev, db);
+ mic_set_state(mdev, MIC_SUSPENDED);
+ }
+ mutex_unlock(&mdev->mic_mutex);
+}