aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDasaratharaman Chandramouli <dasaratharaman.chandramouli@intel.com>2013-10-03 21:06:23 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-05 21:01:42 -0400
commitaf190494f9b2e1fb6e1c039e9626c3c334717da1 (patch)
tree3c6b5168cd9e3bd9455380ca5360a4a250820ab0
parent12b3af3096cdfb0613da374021167868c6abc9ce (diff)
misc: mic: Enable OSPM suspend and resume support.
This patch enables support for OSPM suspend and resume in the MIC driver. During a host suspend event, the driver performs an orderly shutdown of the cards if they are online. Upon resume, any cards that were previously online before suspend are rebooted. The driver performs an orderly shutdown of the card primarily to ensure that applications in the card are terminated and mounted devices are safely un-mounted before the card is powered down in the event of an OSPM suspend. The driver makes use of the MIC daemon to accomplish OSPM suspend and resume. The driver registers a PM notifier per MIC device. The devices get notified synchronously during PM_SUSPEND_PREPARE and PM_POST_SUSPEND phases. During the PM_SUSPEND_PREPARE phase, the driver performs one of the following three tasks. 1) If the card is 'offline', the driver sets the card to a 'suspended' state and returns. 2) If the card is 'online', the driver initiates card shutdown by setting the card state to suspending. This notifies the MIC daemon which invokes shutdown and sets card state to 'suspended'. The driver returns after the shutdown is complete. 3) If the card is already being shutdown, possibly by a host user space application, the driver sets the card state to 'suspended' and returns after the shutdown is complete. During the PM_POST_SUSPEND phase, the driver simply notifies the daemon and returns. The daemon boots those cards that were previously online during the suspend phase. Signed-off-by: Ashutosh Dixit <ashutosh.dixit@intel.com> Signed-off-by: Nikhil Rao <nikhil.rao@intel.com> Signed-off-by: Harshavardhan R Kharche <harshavardhan.r.kharche@intel.com> Signed-off-by: Sudeep Dutt <sudeep.dutt@intel.com> Signed-off-by: Dasaratharaman Chandramouli <dasaratharaman.chandramouli@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/ABI/testing/sysfs-class-mic.txt60
-rw-r--r--Documentation/mic/mic_overview.txt4
-rw-r--r--Documentation/mic/mpssd/mpssd.c27
-rw-r--r--Documentation/mic/mpssd/mpssd.h1
-rw-r--r--drivers/misc/mic/host/mic_boot.c120
-rw-r--r--drivers/misc/mic/host/mic_device.h8
-rw-r--r--drivers/misc/mic/host/mic_main.c63
-rw-r--r--drivers/misc/mic/host/mic_sysfs.c7
-rw-r--r--include/uapi/linux/mic_common.h2
9 files changed, 257 insertions, 35 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-mic.txt b/Documentation/ABI/testing/sysfs-class-mic.txt
index 82cdad3b614a..13f48afc534f 100644
--- a/Documentation/ABI/testing/sysfs-class-mic.txt
+++ b/Documentation/ABI/testing/sysfs-class-mic.txt
@@ -1,6 +1,6 @@
1What: /sys/class/mic/ 1What: /sys/class/mic/
2Date: August 2013 2Date: October 2013
3KernelVersion: 3.11 3KernelVersion: 3.13
4Contact: Sudeep Dutt <sudeep.dutt@intel.com> 4Contact: Sudeep Dutt <sudeep.dutt@intel.com>
5Description: 5Description:
6 The mic class directory belongs to Intel MIC devices and 6 The mic class directory belongs to Intel MIC devices and
@@ -9,8 +9,8 @@ Description:
9 Integrated Core (MIC) architecture that runs a Linux OS. 9 Integrated Core (MIC) architecture that runs a Linux OS.
10 10
11What: /sys/class/mic/mic(x) 11What: /sys/class/mic/mic(x)
12Date: August 2013 12Date: October 2013
13KernelVersion: 3.11 13KernelVersion: 3.13
14Contact: Sudeep Dutt <sudeep.dutt@intel.com> 14Contact: Sudeep Dutt <sudeep.dutt@intel.com>
15Description: 15Description:
16 The directories /sys/class/mic/mic0, /sys/class/mic/mic1 etc., 16 The directories /sys/class/mic/mic0, /sys/class/mic/mic1 etc.,
@@ -18,33 +18,41 @@ Description:
18 information specific to that MIC device. 18 information specific to that MIC device.
19 19
20What: /sys/class/mic/mic(x)/family 20What: /sys/class/mic/mic(x)/family
21Date: August 2013 21Date: October 2013
22KernelVersion: 3.11 22KernelVersion: 3.13
23Contact: Sudeep Dutt <sudeep.dutt@intel.com> 23Contact: Sudeep Dutt <sudeep.dutt@intel.com>
24Description: 24Description:
25 Provides information about the Coprocessor family for an Intel 25 Provides information about the Coprocessor family for an Intel
26 MIC device. For example - "x100" 26 MIC device. For example - "x100"
27 27
28What: /sys/class/mic/mic(x)/stepping 28What: /sys/class/mic/mic(x)/stepping
29Date: August 2013 29Date: October 2013
30KernelVersion: 3.11 30KernelVersion: 3.13
31Contact: Sudeep Dutt <sudeep.dutt@intel.com> 31Contact: Sudeep Dutt <sudeep.dutt@intel.com>
32Description: 32Description:
33 Provides information about the silicon stepping for an Intel 33 Provides information about the silicon stepping for an Intel
34 MIC device. For example - "A0" or "B0" 34 MIC device. For example - "A0" or "B0"
35 35
36What: /sys/class/mic/mic(x)/state 36What: /sys/class/mic/mic(x)/state
37Date: August 2013 37Date: October 2013
38KernelVersion: 3.11 38KernelVersion: 3.13
39Contact: Sudeep Dutt <sudeep.dutt@intel.com> 39Contact: Sudeep Dutt <sudeep.dutt@intel.com>
40Description: 40Description:
41 When read, this entry provides the current state of an Intel 41 When read, this entry provides the current state of an Intel
42 MIC device in the context of the card OS. Possible values that 42 MIC device in the context of the card OS. Possible values that
43 will be read are: 43 will be read are:
44 "offline" - The MIC device is ready to boot the card OS. 44 "offline" - The MIC device is ready to boot the card OS. On
45 reading this entry after an OSPM resume, a "boot" has to be
46 written to this entry if the card was previously shutdown
47 during OSPM suspend.
45 "online" - The MIC device has initiated booting a card OS. 48 "online" - The MIC device has initiated booting a card OS.
46 "shutting_down" - The card OS is shutting down. 49 "shutting_down" - The card OS is shutting down.
47 "reset_failed" - The MIC device has failed to reset. 50 "reset_failed" - The MIC device has failed to reset.
51 "suspending" - The MIC device is currently being prepared for
52 suspend. On reading this entry, a "suspend" has to be written
53 to the state sysfs entry to ensure the card is shutdown during
54 OSPM suspend.
55 "suspended" - The MIC device has been suspended.
48 56
49 When written, this sysfs entry triggers different state change 57 When written, this sysfs entry triggers different state change
50 operations depending upon the current state of the card OS. 58 operations depending upon the current state of the card OS.
@@ -54,10 +62,12 @@ Description:
54 sysfs entries. 62 sysfs entries.
55 "reset" - Initiates device reset. 63 "reset" - Initiates device reset.
56 "shutdown" - Initiates card OS shutdown. 64 "shutdown" - Initiates card OS shutdown.
65 "suspend" - Initiates card OS shutdown and also marks the card
66 as suspended.
57 67
58What: /sys/class/mic/mic(x)/shutdown_status 68What: /sys/class/mic/mic(x)/shutdown_status
59Date: August 2013 69Date: October 2013
60KernelVersion: 3.11 70KernelVersion: 3.13
61Contact: Sudeep Dutt <sudeep.dutt@intel.com> 71Contact: Sudeep Dutt <sudeep.dutt@intel.com>
62Description: 72Description:
63 An Intel MIC device runs a Linux OS during its operation. This 73 An Intel MIC device runs a Linux OS during its operation. This
@@ -72,8 +82,8 @@ Description:
72 "restart" - Shutdown because of a restart command. 82 "restart" - Shutdown because of a restart command.
73 83
74What: /sys/class/mic/mic(x)/cmdline 84What: /sys/class/mic/mic(x)/cmdline
75Date: August 2013 85Date: October 2013
76KernelVersion: 3.11 86KernelVersion: 3.13
77Contact: Sudeep Dutt <sudeep.dutt@intel.com> 87Contact: Sudeep Dutt <sudeep.dutt@intel.com>
78Description: 88Description:
79 An Intel MIC device runs a Linux OS during its operation. Before 89 An Intel MIC device runs a Linux OS during its operation. Before
@@ -88,8 +98,8 @@ Description:
88 line back to this entry. 98 line back to this entry.
89 99
90What: /sys/class/mic/mic(x)/firmware 100What: /sys/class/mic/mic(x)/firmware
91Date: August 2013 101Date: October 2013
92KernelVersion: 3.11 102KernelVersion: 3.13
93Contact: Sudeep Dutt <sudeep.dutt@intel.com> 103Contact: Sudeep Dutt <sudeep.dutt@intel.com>
94Description: 104Description:
95 When read, this sysfs entry provides the path name under 105 When read, this sysfs entry provides the path name under
@@ -98,8 +108,8 @@ Description:
98 firmware image location under /lib/firmware/. 108 firmware image location under /lib/firmware/.
99 109
100What: /sys/class/mic/mic(x)/ramdisk 110What: /sys/class/mic/mic(x)/ramdisk
101Date: August 2013 111Date: October 2013
102KernelVersion: 3.11 112KernelVersion: 3.13
103Contact: Sudeep Dutt <sudeep.dutt@intel.com> 113Contact: Sudeep Dutt <sudeep.dutt@intel.com>
104Description: 114Description:
105 When read, this sysfs entry provides the path name under 115 When read, this sysfs entry provides the path name under
@@ -108,8 +118,8 @@ Description:
108 the ramdisk image location under /lib/firmware/. 118 the ramdisk image location under /lib/firmware/.
109 119
110What: /sys/class/mic/mic(x)/bootmode 120What: /sys/class/mic/mic(x)/bootmode
111Date: August 2013 121Date: October 2013
112KernelVersion: 3.11 122KernelVersion: 3.13
113Contact: Sudeep Dutt <sudeep.dutt@intel.com> 123Contact: Sudeep Dutt <sudeep.dutt@intel.com>
114Description: 124Description:
115 When read, this sysfs entry provides the current bootmode for 125 When read, this sysfs entry provides the current bootmode for
@@ -119,8 +129,8 @@ Description:
119 b) elf - Boot an elf image for flash updates. 129 b) elf - Boot an elf image for flash updates.
120 130
121What: /sys/class/mic/mic(x)/log_buf_addr 131What: /sys/class/mic/mic(x)/log_buf_addr
122Date: August 2013 132Date: October 2013
123KernelVersion: 3.11 133KernelVersion: 3.13
124Contact: Sudeep Dutt <sudeep.dutt@intel.com> 134Contact: Sudeep Dutt <sudeep.dutt@intel.com>
125Description: 135Description:
126 An Intel MIC device runs a Linux OS during its operation. For 136 An Intel MIC device runs a Linux OS during its operation. For
@@ -133,8 +143,8 @@ Description:
133 file of the card OS. 143 file of the card OS.
134 144
135What: /sys/class/mic/mic(x)/log_buf_len 145What: /sys/class/mic/mic(x)/log_buf_len
136Date: August 2013 146Date: October 2013
137KernelVersion: 3.11 147KernelVersion: 3.13
138Contact: Sudeep Dutt <sudeep.dutt@intel.com> 148Contact: Sudeep Dutt <sudeep.dutt@intel.com>
139Description: 149Description:
140 An Intel MIC device runs a Linux OS during its operation. For 150 An Intel MIC device runs a Linux OS during its operation. For
diff --git a/Documentation/mic/mic_overview.txt b/Documentation/mic/mic_overview.txt
index c4424ed1b746..b41929224804 100644
--- a/Documentation/mic/mic_overview.txt
+++ b/Documentation/mic/mic_overview.txt
@@ -4,7 +4,9 @@ that runs a Linux OS. It is a PCIe endpoint in a platform and therefore
4implements the three required standard address spaces i.e. configuration, 4implements the three required standard address spaces i.e. configuration,
5memory and I/O. The host OS loads a device driver as is typical for 5memory and I/O. The host OS loads a device driver as is typical for
6PCIe devices. The card itself runs a bootstrap after reset that 6PCIe devices. The card itself runs a bootstrap after reset that
7transfers control to the card OS downloaded from the host driver. 7transfers control to the card OS downloaded from the host driver. The
8host driver supports OSPM suspend and resume operations. It shuts down
9the card during suspend and reboots the card OS during resume.
8The card OS as shipped by Intel is a Linux kernel with modifications 10The card OS as shipped by Intel is a Linux kernel with modifications
9for the X100 devices. 11for the X100 devices.
10 12
diff --git a/Documentation/mic/mpssd/mpssd.c b/Documentation/mic/mpssd/mpssd.c
index 82c6bc2e3cb6..0c980ad40b17 100644
--- a/Documentation/mic/mpssd/mpssd.c
+++ b/Documentation/mic/mpssd/mpssd.c
@@ -1295,7 +1295,13 @@ reset(struct mic_info *mic)
1295 goto retry; 1295 goto retry;
1296 mpsslog("%s: %s %d state %s\n", 1296 mpsslog("%s: %s %d state %s\n",
1297 mic->name, __func__, __LINE__, state); 1297 mic->name, __func__, __LINE__, state);
1298 if ((!strcmp(state, "offline"))) { 1298
1299 /*
1300 * If the shutdown was initiated by OSPM, the state stays
1301 * in "suspended" which is also a valid condition for reset.
1302 */
1303 if ((!strcmp(state, "offline")) ||
1304 (!strcmp(state, "suspended"))) {
1299 free(state); 1305 free(state);
1300 break; 1306 break;
1301 } 1307 }
@@ -1334,6 +1340,10 @@ static int get_mic_state(struct mic_info *mic, char *state)
1334 return MIC_SHUTTING_DOWN; 1340 return MIC_SHUTTING_DOWN;
1335 if (!strcmp(state, "reset_failed")) 1341 if (!strcmp(state, "reset_failed"))
1336 return MIC_RESET_FAILED; 1342 return MIC_RESET_FAILED;
1343 if (!strcmp(state, "suspending"))
1344 return MIC_SUSPENDING;
1345 if (!strcmp(state, "suspended"))
1346 return MIC_SUSPENDED;
1337 mpsslog("%s: BUG invalid state %s\n", mic->name, state); 1347 mpsslog("%s: BUG invalid state %s\n", mic->name, state);
1338 /* Invalid state */ 1348 /* Invalid state */
1339 assert(0); 1349 assert(0);
@@ -1418,6 +1428,17 @@ retry:
1418 case MIC_SHUTTING_DOWN: 1428 case MIC_SHUTTING_DOWN:
1419 mic_handle_shutdown(mic); 1429 mic_handle_shutdown(mic);
1420 goto close_error; 1430 goto close_error;
1431 case MIC_SUSPENDING:
1432 mic->boot_on_resume = 1;
1433 setsysfs(mic->name, "state", "suspend");
1434 mic_handle_shutdown(mic);
1435 goto close_error;
1436 case MIC_OFFLINE:
1437 if (mic->boot_on_resume) {
1438 setsysfs(mic->name, "state", "boot");
1439 mic->boot_on_resume = 0;
1440 }
1441 break;
1421 default: 1442 default:
1422 break; 1443 break;
1423 } 1444 }
@@ -1621,11 +1642,9 @@ init_mic_list(void)
1621 1642
1622 while ((file = readdir(dp)) != NULL) { 1643 while ((file = readdir(dp)) != NULL) {
1623 if (!strncmp(file->d_name, "mic", 3)) { 1644 if (!strncmp(file->d_name, "mic", 3)) {
1624 mic->next = malloc(sizeof(struct mic_info)); 1645 mic->next = calloc(1, sizeof(struct mic_info));
1625 if (mic->next) { 1646 if (mic->next) {
1626 mic = mic->next; 1647 mic = mic->next;
1627 mic->next = NULL;
1628 memset(mic, 0, sizeof(struct mic_info));
1629 mic->id = atoi(&file->d_name[3]); 1648 mic->id = atoi(&file->d_name[3]);
1630 mic->name = malloc(strlen(file->d_name) + 16); 1649 mic->name = malloc(strlen(file->d_name) + 16);
1631 if (mic->name) 1650 if (mic->name)
diff --git a/Documentation/mic/mpssd/mpssd.h b/Documentation/mic/mpssd/mpssd.h
index ccd589ff9146..f5f18b15d9a0 100644
--- a/Documentation/mic/mpssd/mpssd.h
+++ b/Documentation/mic/mpssd/mpssd.h
@@ -91,6 +91,7 @@ struct mic_info {
91 struct mic_net_info mic_net; 91 struct mic_net_info mic_net;
92 struct mic_virtblk_info mic_virtblk; 92 struct mic_virtblk_info mic_virtblk;
93 int restart; 93 int restart;
94 int boot_on_resume;
94 struct mic_info *next; 95 struct mic_info *next;
95}; 96};
96 97
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)
37 37
38#define MIC_RESET_TO (45) 38#define MIC_RESET_TO (45)
39 39
40 INIT_COMPLETION(mdev->reset_wait);
40 mdev->ops->reset_fw_ready(mdev); 41 mdev->ops->reset_fw_ready(mdev);
41 mdev->ops->reset(mdev); 42 mdev->ops->reset(mdev);
42 43
43 for (i = 0; i < MIC_RESET_TO; i++) { 44 for (i = 0; i < MIC_RESET_TO; i++) {
44 if (mdev->ops->is_fw_ready(mdev)) 45 if (mdev->ops->is_fw_ready(mdev))
45 return; 46 goto done;
46 /* 47 /*
47 * Resets typically take 10s of seconds to complete. 48 * Resets typically take 10s of seconds to complete.
48 * Since an MMIO read is required to check if the 49 * Since an MMIO read is required to check if the
@@ -51,6 +52,8 @@ static void mic_reset(struct mic_device *mdev)
51 msleep(1000); 52 msleep(1000);
52 } 53 }
53 mic_set_state(mdev, MIC_RESET_FAILED); 54 mic_set_state(mdev, MIC_RESET_FAILED);
55done:
56 complete_all(&mdev->reset_wait);
54} 57}
55 58
56/* Initialize the MIC bootparams */ 59/* Initialize the MIC bootparams */
@@ -123,7 +126,8 @@ void mic_stop(struct mic_device *mdev, bool force)
123 if (MIC_RESET_FAILED == mdev->state) 126 if (MIC_RESET_FAILED == mdev->state)
124 goto unlock; 127 goto unlock;
125 mic_set_shutdown_status(mdev, MIC_NOP); 128 mic_set_shutdown_status(mdev, MIC_NOP);
126 mic_set_state(mdev, MIC_OFFLINE); 129 if (MIC_SUSPENDED != mdev->state)
130 mic_set_state(mdev, MIC_OFFLINE);
127 } 131 }
128unlock: 132unlock:
129 mutex_unlock(&mdev->mic_mutex); 133 mutex_unlock(&mdev->mic_mutex);
@@ -165,7 +169,14 @@ void mic_shutdown_work(struct work_struct *work)
165 mutex_lock(&mdev->mic_mutex); 169 mutex_lock(&mdev->mic_mutex);
166 mic_set_shutdown_status(mdev, bootparam->shutdown_status); 170 mic_set_shutdown_status(mdev, bootparam->shutdown_status);
167 bootparam->shutdown_status = 0; 171 bootparam->shutdown_status = 0;
168 if (MIC_SHUTTING_DOWN != mdev->state) 172
173 /*
174 * if state is MIC_SUSPENDED, OSPM suspend is in progress. We do not
175 * change the state here so as to prevent users from booting the card
176 * during and after the suspend operation.
177 */
178 if (MIC_SHUTTING_DOWN != mdev->state &&
179 MIC_SUSPENDED != mdev->state)
169 mic_set_state(mdev, MIC_SHUTTING_DOWN); 180 mic_set_state(mdev, MIC_SHUTTING_DOWN);
170 mutex_unlock(&mdev->mic_mutex); 181 mutex_unlock(&mdev->mic_mutex);
171} 182}
@@ -183,3 +194,106 @@ void mic_reset_trigger_work(struct work_struct *work)
183 194
184 mic_stop(mdev, false); 195 mic_stop(mdev, false);
185} 196}
197
198/**
199 * mic_complete_resume - Complete MIC Resume after an OSPM suspend/hibernate
200 * event.
201 * @mdev: pointer to mic_device instance
202 *
203 * RETURNS: None.
204 */
205void mic_complete_resume(struct mic_device *mdev)
206{
207 if (mdev->state != MIC_SUSPENDED) {
208 dev_warn(mdev->sdev->parent, "state %d should be %d\n",
209 mdev->state, MIC_SUSPENDED);
210 return;
211 }
212
213 /* Make sure firmware is ready */
214 if (!mdev->ops->is_fw_ready(mdev))
215 mic_stop(mdev, true);
216
217 mutex_lock(&mdev->mic_mutex);
218 mic_set_state(mdev, MIC_OFFLINE);
219 mutex_unlock(&mdev->mic_mutex);
220}
221
222/**
223 * mic_prepare_suspend - Handle suspend notification for the MIC device.
224 * @mdev: pointer to mic_device instance
225 *
226 * RETURNS: None.
227 */
228void mic_prepare_suspend(struct mic_device *mdev)
229{
230 int rc;
231
232#define MIC_SUSPEND_TIMEOUT (60 * HZ)
233
234 mutex_lock(&mdev->mic_mutex);
235 switch (mdev->state) {
236 case MIC_OFFLINE:
237 /*
238 * Card is already offline. Set state to MIC_SUSPENDED
239 * to prevent users from booting the card.
240 */
241 mic_set_state(mdev, MIC_SUSPENDED);
242 mutex_unlock(&mdev->mic_mutex);
243 break;
244 case MIC_ONLINE:
245 /*
246 * Card is online. Set state to MIC_SUSPENDING and notify
247 * MIC user space daemon which will issue card
248 * shutdown and reset.
249 */
250 mic_set_state(mdev, MIC_SUSPENDING);
251 mutex_unlock(&mdev->mic_mutex);
252 rc = wait_for_completion_timeout(&mdev->reset_wait,
253 MIC_SUSPEND_TIMEOUT);
254 /* Force reset the card if the shutdown completion timed out */
255 if (!rc) {
256 mutex_lock(&mdev->mic_mutex);
257 mic_set_state(mdev, MIC_SUSPENDED);
258 mutex_unlock(&mdev->mic_mutex);
259 mic_stop(mdev, true);
260 }
261 break;
262 case MIC_SHUTTING_DOWN:
263 /*
264 * Card is shutting down. Set state to MIC_SUSPENDED
265 * to prevent further boot of the card.
266 */
267 mic_set_state(mdev, MIC_SUSPENDED);
268 mutex_unlock(&mdev->mic_mutex);
269 rc = wait_for_completion_timeout(&mdev->reset_wait,
270 MIC_SUSPEND_TIMEOUT);
271 /* Force reset the card if the shutdown completion timed out */
272 if (!rc)
273 mic_stop(mdev, true);
274 break;
275 default:
276 mutex_unlock(&mdev->mic_mutex);
277 break;
278 }
279}
280
281/**
282 * mic_suspend - Initiate MIC suspend. Suspend merely issues card shutdown.
283 * @mdev: pointer to mic_device instance
284 *
285 * RETURNS: None.
286 */
287void mic_suspend(struct mic_device *mdev)
288{
289 struct mic_bootparam *bootparam = mdev->dp;
290 s8 db = bootparam->h2c_shutdown_db;
291
292 mutex_lock(&mdev->mic_mutex);
293 if (MIC_SUSPENDING == mdev->state && db != -1) {
294 bootparam->shutdown_card = 1;
295 mdev->ops->send_intr(mdev, db);
296 mic_set_state(mdev, MIC_SUSPENDED);
297 }
298 mutex_unlock(&mdev->mic_mutex);
299}
diff --git a/drivers/misc/mic/host/mic_device.h b/drivers/misc/mic/host/mic_device.h
index dcba2a59e77f..3574cc375bb9 100644
--- a/drivers/misc/mic/host/mic_device.h
+++ b/drivers/misc/mic/host/mic_device.h
@@ -23,6 +23,7 @@
23 23
24#include <linux/cdev.h> 24#include <linux/cdev.h>
25#include <linux/idr.h> 25#include <linux/idr.h>
26#include <linux/notifier.h>
26 27
27#include "mic_intr.h" 28#include "mic_intr.h"
28 29
@@ -75,6 +76,7 @@ enum mic_stepping {
75 * @state: MIC state. 76 * @state: MIC state.
76 * @shutdown_status: MIC status reported by card for shutdown/crashes. 77 * @shutdown_status: MIC status reported by card for shutdown/crashes.
77 * @state_sysfs: Sysfs dirent for notifying ring 3 about MIC state changes. 78 * @state_sysfs: Sysfs dirent for notifying ring 3 about MIC state changes.
79 * @reset_wait: Waitqueue for sleeping while reset completes.
78 * @log_buf_addr: Log buffer address for MIC. 80 * @log_buf_addr: Log buffer address for MIC.
79 * @log_buf_len: Log buffer length address for MIC. 81 * @log_buf_len: Log buffer length address for MIC.
80 * @dp: virtio device page 82 * @dp: virtio device page
@@ -83,6 +85,7 @@ enum mic_stepping {
83 * @shutdown_cookie: shutdown cookie. 85 * @shutdown_cookie: shutdown cookie.
84 * @cdev: Character device for MIC. 86 * @cdev: Character device for MIC.
85 * @vdev_list: list of virtio devices. 87 * @vdev_list: list of virtio devices.
88 * @pm_notifier: Handles PM notifications from the OS.
86 */ 89 */
87struct mic_device { 90struct mic_device {
88 struct mic_mw mmio; 91 struct mic_mw mmio;
@@ -110,6 +113,7 @@ struct mic_device {
110 u8 state; 113 u8 state;
111 u8 shutdown_status; 114 u8 shutdown_status;
112 struct sysfs_dirent *state_sysfs; 115 struct sysfs_dirent *state_sysfs;
116 struct completion reset_wait;
113 void *log_buf_addr; 117 void *log_buf_addr;
114 int *log_buf_len; 118 int *log_buf_len;
115 void *dp; 119 void *dp;
@@ -118,6 +122,7 @@ struct mic_device {
118 struct mic_irq *shutdown_cookie; 122 struct mic_irq *shutdown_cookie;
119 struct cdev cdev; 123 struct cdev cdev;
120 struct list_head vdev_list; 124 struct list_head vdev_list;
125 struct notifier_block pm_notifier;
121}; 126};
122 127
123/** 128/**
@@ -192,4 +197,7 @@ void mic_create_debug_dir(struct mic_device *dev);
192void mic_delete_debug_dir(struct mic_device *dev); 197void mic_delete_debug_dir(struct mic_device *dev);
193void __init mic_init_debugfs(void); 198void __init mic_init_debugfs(void);
194void mic_exit_debugfs(void); 199void mic_exit_debugfs(void);
200void mic_prepare_suspend(struct mic_device *mdev);
201void mic_complete_resume(struct mic_device *mdev);
202void mic_suspend(struct mic_device *mdev);
195#endif 203#endif
diff --git a/drivers/misc/mic/host/mic_main.c b/drivers/misc/mic/host/mic_main.c
index ca06aa9b7114..b3520859abd3 100644
--- a/drivers/misc/mic/host/mic_main.c
+++ b/drivers/misc/mic/host/mic_main.c
@@ -26,6 +26,7 @@
26#include <linux/module.h> 26#include <linux/module.h>
27#include <linux/pci.h> 27#include <linux/pci.h>
28#include <linux/poll.h> 28#include <linux/poll.h>
29#include <linux/suspend.h>
29 30
30#include <linux/mic_common.h> 31#include <linux/mic_common.h>
31#include "../common/mic_dev.h" 32#include "../common/mic_dev.h"
@@ -187,6 +188,43 @@ static enum mic_hw_family mic_get_family(struct pci_dev *pdev)
187} 188}
188 189
189/** 190/**
191* mic_pm_notifier: Notifier callback function that handles
192* PM notifications.
193*
194* @notifier_block: The notifier structure.
195* @pm_event: The event for which the driver was notified.
196* @unused: Meaningless. Always NULL.
197*
198* returns NOTIFY_DONE
199*/
200static int mic_pm_notifier(struct notifier_block *notifier,
201 unsigned long pm_event, void *unused)
202{
203 struct mic_device *mdev = container_of(notifier,
204 struct mic_device, pm_notifier);
205
206 switch (pm_event) {
207 case PM_HIBERNATION_PREPARE:
208 /* Fall through */
209 case PM_SUSPEND_PREPARE:
210 mic_prepare_suspend(mdev);
211 break;
212 case PM_POST_HIBERNATION:
213 /* Fall through */
214 case PM_POST_SUSPEND:
215 /* Fall through */
216 case PM_POST_RESTORE:
217 mic_complete_resume(mdev);
218 break;
219 case PM_RESTORE_PREPARE:
220 break;
221 default:
222 break;
223 }
224 return NOTIFY_DONE;
225}
226
227/**
190 * mic_device_init - Allocates and initializes the MIC device structure 228 * mic_device_init - Allocates and initializes the MIC device structure
191 * 229 *
192 * @mdev: pointer to mic_device instance 230 * @mdev: pointer to mic_device instance
@@ -194,9 +232,11 @@ static enum mic_hw_family mic_get_family(struct pci_dev *pdev)
194 * 232 *
195 * returns none. 233 * returns none.
196 */ 234 */
197static void 235static int
198mic_device_init(struct mic_device *mdev, struct pci_dev *pdev) 236mic_device_init(struct mic_device *mdev, struct pci_dev *pdev)
199{ 237{
238 int rc;
239
200 mdev->family = mic_get_family(pdev); 240 mdev->family = mic_get_family(pdev);
201 mdev->stepping = pdev->revision; 241 mdev->stepping = pdev->revision;
202 mic_ops_init(mdev); 242 mic_ops_init(mdev);
@@ -205,7 +245,20 @@ mic_device_init(struct mic_device *mdev, struct pci_dev *pdev)
205 mdev->irq_info.next_avail_src = 0; 245 mdev->irq_info.next_avail_src = 0;
206 INIT_WORK(&mdev->reset_trigger_work, mic_reset_trigger_work); 246 INIT_WORK(&mdev->reset_trigger_work, mic_reset_trigger_work);
207 INIT_WORK(&mdev->shutdown_work, mic_shutdown_work); 247 INIT_WORK(&mdev->shutdown_work, mic_shutdown_work);
248 init_completion(&mdev->reset_wait);
208 INIT_LIST_HEAD(&mdev->vdev_list); 249 INIT_LIST_HEAD(&mdev->vdev_list);
250 mdev->pm_notifier.notifier_call = mic_pm_notifier;
251 rc = register_pm_notifier(&mdev->pm_notifier);
252 if (rc) {
253 dev_err(&pdev->dev, "register_pm_notifier failed rc %d\n",
254 rc);
255 goto register_pm_notifier_fail;
256 }
257 return 0;
258register_pm_notifier_fail:
259 flush_work(&mdev->shutdown_work);
260 flush_work(&mdev->reset_trigger_work);
261 return rc;
209} 262}
210 263
211/** 264/**
@@ -224,6 +277,7 @@ static void mic_device_uninit(struct mic_device *mdev)
224 kfree(mdev->bootmode); 277 kfree(mdev->bootmode);
225 flush_work(&mdev->reset_trigger_work); 278 flush_work(&mdev->reset_trigger_work);
226 flush_work(&mdev->shutdown_work); 279 flush_work(&mdev->shutdown_work);
280 unregister_pm_notifier(&mdev->pm_notifier);
227} 281}
228 282
229/** 283/**
@@ -253,7 +307,11 @@ static int mic_probe(struct pci_dev *pdev,
253 goto ida_fail; 307 goto ida_fail;
254 } 308 }
255 309
256 mic_device_init(mdev, pdev); 310 rc = mic_device_init(mdev, pdev);
311 if (rc) {
312 dev_err(&pdev->dev, "mic_device_init failed rc %d\n", rc);
313 goto device_init_fail;
314 }
257 315
258 rc = pci_enable_device(pdev); 316 rc = pci_enable_device(pdev);
259 if (rc) { 317 if (rc) {
@@ -376,6 +434,7 @@ disable_device:
376 pci_disable_device(pdev); 434 pci_disable_device(pdev);
377uninit_device: 435uninit_device:
378 mic_device_uninit(mdev); 436 mic_device_uninit(mdev);
437device_init_fail:
379 ida_simple_remove(&g_mic_ida, mdev->id); 438 ida_simple_remove(&g_mic_ida, mdev->id);
380ida_fail: 439ida_fail:
381 kfree(mdev); 440 kfree(mdev);
diff --git a/drivers/misc/mic/host/mic_sysfs.c b/drivers/misc/mic/host/mic_sysfs.c
index 75746adfb155..6dd864e4a617 100644
--- a/drivers/misc/mic/host/mic_sysfs.c
+++ b/drivers/misc/mic/host/mic_sysfs.c
@@ -33,6 +33,8 @@ static const char * const mic_state_string[] = {
33 [MIC_ONLINE] = "online", 33 [MIC_ONLINE] = "online",
34 [MIC_SHUTTING_DOWN] = "shutting_down", 34 [MIC_SHUTTING_DOWN] = "shutting_down",
35 [MIC_RESET_FAILED] = "reset_failed", 35 [MIC_RESET_FAILED] = "reset_failed",
36 [MIC_SUSPENDING] = "suspending",
37 [MIC_SUSPENDED] = "suspended",
36}; 38};
37 39
38/* 40/*
@@ -156,6 +158,11 @@ state_store(struct device *dev, struct device_attribute *attr,
156 goto done; 158 goto done;
157 } 159 }
158 160
161 if (sysfs_streq(buf, "suspend")) {
162 mic_suspend(mdev);
163 goto done;
164 }
165
159 count = -EINVAL; 166 count = -EINVAL;
160done: 167done:
161 return count; 168 return count;
diff --git a/include/uapi/linux/mic_common.h b/include/uapi/linux/mic_common.h
index 364ac751bd04..17e7d95e4f53 100644
--- a/include/uapi/linux/mic_common.h
+++ b/include/uapi/linux/mic_common.h
@@ -219,6 +219,8 @@ enum mic_states {
219 MIC_ONLINE, 219 MIC_ONLINE,
220 MIC_SHUTTING_DOWN, 220 MIC_SHUTTING_DOWN,
221 MIC_RESET_FAILED, 221 MIC_RESET_FAILED,
222 MIC_SUSPENDING,
223 MIC_SUSPENDED,
222 MIC_LAST 224 MIC_LAST
223}; 225};
224 226