aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mei
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2014-01-14 16:10:10 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-02-07 18:09:35 -0500
commit7d93e58d5374aef9cd895a7bb1a8903ffdb7c4b4 (patch)
tree95a0de52db3c458df48cb8690de6ed4ae7090648 /drivers/misc/mei
parent92ab513072e73d74fee78062c9935f119339e4de (diff)
mei: allow multiple retries if the hw reset has failed
In some rare case mei hw reset may take long time to settle. Instead of blocking resume flow we span another driver reset flow in separate work context This allows as to shorten hw reset timeout to something more acceptable by DPM_WATCHDOG_TIMEOUT Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/mei')
-rw-r--r--drivers/misc/mei/hbm.c2
-rw-r--r--drivers/misc/mei/hw-me.c2
-rw-r--r--drivers/misc/mei/hw.h4
-rw-r--r--drivers/misc/mei/init.c40
4 files changed, 34 insertions, 14 deletions
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 28cd74c073b9..0aaf2c515ab7 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -147,7 +147,7 @@ int mei_hbm_start_wait(struct mei_device *dev)
147 ret = wait_event_interruptible_timeout(dev->wait_recvd_msg, 147 ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
148 dev->hbm_state == MEI_HBM_IDLE || 148 dev->hbm_state == MEI_HBM_IDLE ||
149 dev->hbm_state >= MEI_HBM_STARTED, 149 dev->hbm_state >= MEI_HBM_STARTED,
150 mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT)); 150 mei_secs_to_jiffies(MEI_HBM_TIMEOUT));
151 mutex_lock(&dev->device_lock); 151 mutex_lock(&dev->device_lock);
152 152
153 if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) { 153 if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 6f656c053b14..54286f304939 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -240,7 +240,7 @@ static int mei_me_hw_ready_wait(struct mei_device *dev)
240 mutex_unlock(&dev->device_lock); 240 mutex_unlock(&dev->device_lock);
241 err = wait_event_interruptible_timeout(dev->wait_hw_ready, 241 err = wait_event_interruptible_timeout(dev->wait_hw_ready,
242 dev->recvd_hw_ready, 242 dev->recvd_hw_ready,
243 mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT)); 243 mei_secs_to_jiffies(MEI_HW_READY_TIMEOUT));
244 mutex_lock(&dev->device_lock); 244 mutex_lock(&dev->device_lock);
245 if (!err && !dev->recvd_hw_ready) { 245 if (!err && !dev->recvd_hw_ready) {
246 if (!err) 246 if (!err)
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index dd44e33ad2b6..e06779d4413e 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -22,7 +22,7 @@
22/* 22/*
23 * Timeouts in Seconds 23 * Timeouts in Seconds
24 */ 24 */
25#define MEI_INTEROP_TIMEOUT 7 /* Timeout on ready message */ 25#define MEI_HW_READY_TIMEOUT 2 /* Timeout on ready message */
26#define MEI_CONNECT_TIMEOUT 3 /* HPS: at least 2 seconds */ 26#define MEI_CONNECT_TIMEOUT 3 /* HPS: at least 2 seconds */
27 27
28#define MEI_CL_CONNECT_TIMEOUT 15 /* HPS: Client Connect Timeout */ 28#define MEI_CL_CONNECT_TIMEOUT 15 /* HPS: Client Connect Timeout */
@@ -31,13 +31,13 @@
31#define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */ 31#define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */
32#define MEI_IAMTHIF_READ_TIMER 10 /* HPS */ 32#define MEI_IAMTHIF_READ_TIMER 10 /* HPS */
33 33
34#define MEI_HBM_TIMEOUT 1 /* 1 second */
34 35
35/* 36/*
36 * MEI Version 37 * MEI Version
37 */ 38 */
38#define HBM_MINOR_VERSION 0 39#define HBM_MINOR_VERSION 0
39#define HBM_MAJOR_VERSION 1 40#define HBM_MAJOR_VERSION 1
40#define HBM_TIMEOUT 1 /* 1 second */
41 41
42/* Host bus message command opcode */ 42/* Host bus message command opcode */
43#define MEI_HBM_CMD_OP_MSK 0x7f 43#define MEI_HBM_CMD_OP_MSK 0x7f
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index cdd31c2a2a2b..95a7180c75ea 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -126,7 +126,6 @@ int mei_reset(struct mei_device *dev)
126 126
127 if (ret) { 127 if (ret) {
128 dev_err(&dev->pdev->dev, "hw_reset failed ret = %d\n", ret); 128 dev_err(&dev->pdev->dev, "hw_reset failed ret = %d\n", ret);
129 dev->dev_state = MEI_DEV_DISABLED;
130 return ret; 129 return ret;
131 } 130 }
132 131
@@ -139,7 +138,6 @@ int mei_reset(struct mei_device *dev)
139 ret = mei_hw_start(dev); 138 ret = mei_hw_start(dev);
140 if (ret) { 139 if (ret) {
141 dev_err(&dev->pdev->dev, "hw_start failed ret = %d\n", ret); 140 dev_err(&dev->pdev->dev, "hw_start failed ret = %d\n", ret);
142 dev->dev_state = MEI_DEV_DISABLED;
143 return ret; 141 return ret;
144 } 142 }
145 143
@@ -149,7 +147,7 @@ int mei_reset(struct mei_device *dev)
149 ret = mei_hbm_start_req(dev); 147 ret = mei_hbm_start_req(dev);
150 if (ret) { 148 if (ret) {
151 dev_err(&dev->pdev->dev, "hbm_start failed ret = %d\n", ret); 149 dev_err(&dev->pdev->dev, "hbm_start failed ret = %d\n", ret);
152 dev->dev_state = MEI_DEV_DISABLED; 150 dev->dev_state = MEI_DEV_RESETTING;
153 return ret; 151 return ret;
154 } 152 }
155 153
@@ -166,6 +164,7 @@ EXPORT_SYMBOL_GPL(mei_reset);
166 */ 164 */
167int mei_start(struct mei_device *dev) 165int mei_start(struct mei_device *dev)
168{ 166{
167 int ret;
169 mutex_lock(&dev->device_lock); 168 mutex_lock(&dev->device_lock);
170 169
171 /* acknowledge interrupt and stop interrupts */ 170 /* acknowledge interrupt and stop interrupts */
@@ -175,10 +174,18 @@ int mei_start(struct mei_device *dev)
175 174
176 dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n"); 175 dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
177 176
178 dev->dev_state = MEI_DEV_INITIALIZING;
179 dev->reset_count = 0; 177 dev->reset_count = 0;
180 mei_reset(dev); 178 do {
179 dev->dev_state = MEI_DEV_INITIALIZING;
180 ret = mei_reset(dev);
181
182 if (ret == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
183 dev_err(&dev->pdev->dev, "reset failed ret = %d", ret);
184 goto err;
185 }
186 } while (ret);
181 187
188 /* we cannot start the device w/o hbm start message completed */
182 if (dev->dev_state == MEI_DEV_DISABLED) { 189 if (dev->dev_state == MEI_DEV_DISABLED) {
183 dev_err(&dev->pdev->dev, "reset failed"); 190 dev_err(&dev->pdev->dev, "reset failed");
184 goto err; 191 goto err;
@@ -238,27 +245,40 @@ int mei_restart(struct mei_device *dev)
238 245
239 mutex_unlock(&dev->device_lock); 246 mutex_unlock(&dev->device_lock);
240 247
241 if (err || dev->dev_state == MEI_DEV_DISABLED) 248 if (err == -ENODEV || dev->dev_state == MEI_DEV_DISABLED) {
249 dev_err(&dev->pdev->dev, "device disabled = %d\n", err);
242 return -ENODEV; 250 return -ENODEV;
251 }
252
253 /* try to start again */
254 if (err)
255 schedule_work(&dev->reset_work);
256
243 257
244 return 0; 258 return 0;
245} 259}
246EXPORT_SYMBOL_GPL(mei_restart); 260EXPORT_SYMBOL_GPL(mei_restart);
247 261
248
249static void mei_reset_work(struct work_struct *work) 262static void mei_reset_work(struct work_struct *work)
250{ 263{
251 struct mei_device *dev = 264 struct mei_device *dev =
252 container_of(work, struct mei_device, reset_work); 265 container_of(work, struct mei_device, reset_work);
266 int ret;
253 267
254 mutex_lock(&dev->device_lock); 268 mutex_lock(&dev->device_lock);
255 269
256 mei_reset(dev); 270 ret = mei_reset(dev);
257 271
258 mutex_unlock(&dev->device_lock); 272 mutex_unlock(&dev->device_lock);
259 273
260 if (dev->dev_state == MEI_DEV_DISABLED) 274 if (dev->dev_state == MEI_DEV_DISABLED) {
261 dev_err(&dev->pdev->dev, "reset failed"); 275 dev_err(&dev->pdev->dev, "device disabled = %d\n", ret);
276 return;
277 }
278
279 /* retry reset in case of failure */
280 if (ret)
281 schedule_work(&dev->reset_work);
262} 282}
263 283
264void mei_stop(struct mei_device *dev) 284void mei_stop(struct mei_device *dev)