diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2014-01-14 16:10:10 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-02-07 18:09:35 -0500 |
commit | 7d93e58d5374aef9cd895a7bb1a8903ffdb7c4b4 (patch) | |
tree | 95a0de52db3c458df48cb8690de6ed4ae7090648 /drivers/misc/mei | |
parent | 92ab513072e73d74fee78062c9935f119339e4de (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.c | 2 | ||||
-rw-r--r-- | drivers/misc/mei/hw-me.c | 2 | ||||
-rw-r--r-- | drivers/misc/mei/hw.h | 4 | ||||
-rw-r--r-- | drivers/misc/mei/init.c | 40 |
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 | */ |
167 | int mei_start(struct mei_device *dev) | 165 | int 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 | } |
246 | EXPORT_SYMBOL_GPL(mei_restart); | 260 | EXPORT_SYMBOL_GPL(mei_restart); |
247 | 261 | ||
248 | |||
249 | static void mei_reset_work(struct work_struct *work) | 262 | static 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 | ||
264 | void mei_stop(struct mei_device *dev) | 284 | void mei_stop(struct mei_device *dev) |