aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2012-08-16 12:39:43 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-08-16 12:51:02 -0400
commitc216fdeb2e7371554c56ba457c374cce9c77f91a (patch)
tree9d88b3170a5470844e61ac90a30fd923d50df14b /drivers/misc
parent248ffdf7c95726a8dae76e25fdb037899c5b77fa (diff)
mei: wd: decouple and revamp watchdog state machine
Before ME watchdog was exported through standard watchdog interface it was closed and started together with the mei device. The major issue is that closing ME watchdog disabled also MEI device, to fix this the watchdog state machine has to be independent from MEI state machine. Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/mei/init.c1
-rw-r--r--drivers/misc/mei/interface.h2
-rw-r--r--drivers/misc/mei/interrupt.c9
-rw-r--r--drivers/misc/mei/main.c9
-rw-r--r--drivers/misc/mei/mei_dev.h14
-rw-r--r--drivers/misc/mei/wd.c26
6 files changed, 34 insertions, 27 deletions
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index cd6a7f1ff916..98f1430e3e14 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -330,7 +330,6 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
330 330
331 dev->me_clients_num = 0; 331 dev->me_clients_num = 0;
332 dev->rd_msg_hdr = 0; 332 dev->rd_msg_hdr = 0;
333 dev->stop = false;
334 dev->wd_pending = false; 333 dev->wd_pending = false;
335 334
336 /* update the state of the registers after reset */ 335 /* update the state of the registers after reset */
diff --git a/drivers/misc/mei/interface.h b/drivers/misc/mei/interface.h
index c1988f564aa2..ec6c785a3961 100644
--- a/drivers/misc/mei/interface.h
+++ b/drivers/misc/mei/interface.h
@@ -56,7 +56,7 @@ int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl);
56 56
57 57
58int mei_wd_send(struct mei_device *dev); 58int mei_wd_send(struct mei_device *dev);
59int mei_wd_stop(struct mei_device *dev, bool preserve); 59int mei_wd_stop(struct mei_device *dev);
60int mei_wd_host_init(struct mei_device *dev); 60int mei_wd_host_init(struct mei_device *dev);
61/* 61/*
62 * mei_watchdog_register - Registering watchdog interface 62 * mei_watchdog_register - Registering watchdog interface
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 0f25cee6ab85..0900a711badd 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -1224,10 +1224,9 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
1224 } 1224 }
1225 } 1225 }
1226 1226
1227 if (dev->stop && !dev->wd_pending) { 1227 if (dev->wd_state == MEI_WD_STOPPING) {
1228 dev->wd_stopped = true; 1228 dev->wd_state = MEI_WD_IDLE;
1229 wake_up_interruptible(&dev->wait_stop_wd); 1229 wake_up_interruptible(&dev->wait_stop_wd);
1230 return 0;
1231 } 1230 }
1232 1231
1233 if (dev->extra_write_index) { 1232 if (dev->extra_write_index) {
@@ -1250,14 +1249,12 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
1250 1249
1251 dev->wd_pending = false; 1250 dev->wd_pending = false;
1252 1251
1253 if (dev->wd_timeout) 1252 if (dev->wd_state == MEI_WD_RUNNING)
1254 *slots -= mei_data2slots(MEI_WD_START_MSG_SIZE); 1253 *slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
1255 else 1254 else
1256 *slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE); 1255 *slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE);
1257 } 1256 }
1258 } 1257 }
1259 if (dev->stop)
1260 return -ENODEV;
1261 1258
1262 /* complete control write list CB */ 1259 /* complete control write list CB */
1263 dev_dbg(&dev->pdev->dev, "complete control write list cb.\n"); 1260 dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 5c557dd129d6..9a595338ae15 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -1060,7 +1060,9 @@ static void __devexit mei_remove(struct pci_dev *pdev)
1060 1060
1061 mutex_lock(&dev->device_lock); 1061 mutex_lock(&dev->device_lock);
1062 1062
1063 mei_wd_stop(dev, false); 1063 cancel_delayed_work(&dev->timer_work);
1064
1065 mei_wd_stop(dev);
1064 1066
1065 mei_device = NULL; 1067 mei_device = NULL;
1066 1068
@@ -1115,8 +1117,11 @@ static int mei_pci_suspend(struct device *device)
1115 if (!dev) 1117 if (!dev)
1116 return -ENODEV; 1118 return -ENODEV;
1117 mutex_lock(&dev->device_lock); 1119 mutex_lock(&dev->device_lock);
1120
1121 cancel_delayed_work(&dev->timer_work);
1122
1118 /* Stop watchdog if exists */ 1123 /* Stop watchdog if exists */
1119 err = mei_wd_stop(dev, true); 1124 err = mei_wd_stop(dev);
1120 /* Set new mei state */ 1125 /* Set new mei state */
1121 if (dev->dev_state == MEI_DEV_ENABLED || 1126 if (dev->dev_state == MEI_DEV_ENABLED ||
1122 dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) { 1127 dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 64a4f17893e5..c8660c0eb1c7 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -33,6 +33,8 @@
33#define MEI_WD_MIN_TIMEOUT 120 /* seconds */ 33#define MEI_WD_MIN_TIMEOUT 120 /* seconds */
34#define MEI_WD_MAX_TIMEOUT 65535 /* seconds */ 34#define MEI_WD_MAX_TIMEOUT 65535 /* seconds */
35 35
36#define MEI_WD_STOP_TIMEOUT 10 /* msecs */
37
36#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0) 38#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0)
37 39
38#define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32)) 40#define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32))
@@ -120,6 +122,12 @@ enum mei_file_transaction_states {
120 MEI_READ_COMPLETE 122 MEI_READ_COMPLETE
121}; 123};
122 124
125enum mei_wd_states {
126 MEI_WD_IDLE,
127 MEI_WD_RUNNING,
128 MEI_WD_STOPPING,
129};
130
123/* MEI CB */ 131/* MEI CB */
124enum mei_cb_major_types { 132enum mei_cb_major_types {
125 MEI_READ = 0, 133 MEI_READ = 0,
@@ -228,7 +236,6 @@ struct mei_device {
228 enum mei_dev_state dev_state; 236 enum mei_dev_state dev_state;
229 enum mei_init_clients_states init_clients_state; 237 enum mei_init_clients_states init_clients_state;
230 u16 init_clients_timer; 238 u16 init_clients_timer;
231 bool stop;
232 bool need_reset; 239 bool need_reset;
233 240
234 u32 extra_write_index; 241 u32 extra_write_index;
@@ -248,11 +255,10 @@ struct mei_device {
248 bool mei_host_buffer_is_empty; 255 bool mei_host_buffer_is_empty;
249 256
250 struct mei_cl wd_cl; 257 struct mei_cl wd_cl;
258 enum mei_wd_states wd_state;
251 bool wd_interface_reg; 259 bool wd_interface_reg;
252 bool wd_pending; 260 bool wd_pending;
253 bool wd_stopped; 261 u16 wd_timeout;
254 bool wd_bypass; /* if false, don't refresh watchdog ME client */
255 u16 wd_timeout; /* seconds ((wd_data[1] << 8) + wd_data[0]) */
256 unsigned char wd_data[MEI_WD_START_MSG_SIZE]; 262 unsigned char wd_data[MEI_WD_START_MSG_SIZE];
257 263
258 264
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index 755a58305a7e..0824166a7303 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -67,6 +67,7 @@ int mei_wd_host_init(struct mei_device *dev)
67 /* look for WD client and connect to it */ 67 /* look for WD client and connect to it */
68 dev->wd_cl.state = MEI_FILE_DISCONNECTED; 68 dev->wd_cl.state = MEI_FILE_DISCONNECTED;
69 dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT; 69 dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT;
70 dev->wd_state = MEI_WD_IDLE;
70 71
71 /* find ME WD client */ 72 /* find ME WD client */
72 mei_me_cl_update_filext(dev, &dev->wd_cl, 73 mei_me_cl_update_filext(dev, &dev->wd_cl,
@@ -128,18 +129,17 @@ int mei_wd_send(struct mei_device *dev)
128 * -EIO when message send fails 129 * -EIO when message send fails
129 * -EINVAL when invalid message is to be sent 130 * -EINVAL when invalid message is to be sent
130 */ 131 */
131int mei_wd_stop(struct mei_device *dev, bool preserve) 132int mei_wd_stop(struct mei_device *dev)
132{ 133{
133 int ret; 134 int ret;
134 u16 wd_timeout = dev->wd_timeout;
135 135
136 cancel_delayed_work(&dev->timer_work); 136 if (dev->wd_cl.state != MEI_FILE_CONNECTED ||
137 if (dev->wd_cl.state != MEI_FILE_CONNECTED || !dev->wd_timeout) 137 dev->wd_state != MEI_WD_RUNNING)
138 return 0; 138 return 0;
139 139
140 dev->wd_timeout = 0;
141 memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_STOP_MSG_SIZE); 140 memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_STOP_MSG_SIZE);
142 dev->stop = true; 141
142 dev->wd_state = MEI_WD_STOPPING;
143 143
144 ret = mei_flow_ctrl_creds(dev, &dev->wd_cl); 144 ret = mei_flow_ctrl_creds(dev, &dev->wd_cl);
145 if (ret < 0) 145 if (ret < 0)
@@ -161,13 +161,14 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
161 } else { 161 } else {
162 dev->wd_pending = true; 162 dev->wd_pending = true;
163 } 163 }
164 dev->wd_stopped = false; 164
165 mutex_unlock(&dev->device_lock); 165 mutex_unlock(&dev->device_lock);
166 166
167 ret = wait_event_interruptible_timeout(dev->wait_stop_wd, 167 ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
168 dev->wd_stopped, 10 * HZ); 168 dev->wd_state == MEI_WD_IDLE,
169 msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
169 mutex_lock(&dev->device_lock); 170 mutex_lock(&dev->device_lock);
170 if (dev->wd_stopped) { 171 if (dev->wd_state == MEI_WD_IDLE) {
171 dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret); 172 dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
172 ret = 0; 173 ret = 0;
173 } else { 174 } else {
@@ -177,9 +178,6 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
177 "wd: stop failed to complete ret=%d.\n", ret); 178 "wd: stop failed to complete ret=%d.\n", ret);
178 } 179 }
179 180
180 if (preserve)
181 dev->wd_timeout = wd_timeout;
182
183out: 181out:
184 return ret; 182 return ret;
185} 183}
@@ -239,7 +237,7 @@ static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
239 return -ENODEV; 237 return -ENODEV;
240 238
241 mutex_lock(&dev->device_lock); 239 mutex_lock(&dev->device_lock);
242 mei_wd_stop(dev, false); 240 mei_wd_stop(dev);
243 mutex_unlock(&dev->device_lock); 241 mutex_unlock(&dev->device_lock);
244 242
245 return 0; 243 return 0;
@@ -269,6 +267,8 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
269 goto end; 267 goto end;
270 } 268 }
271 269
270 dev->wd_state = MEI_WD_RUNNING;
271
272 /* Check if we can send the ping to HW*/ 272 /* Check if we can send the ping to HW*/
273 if (dev->mei_host_buffer_is_empty && 273 if (dev->mei_host_buffer_is_empty &&
274 mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) { 274 mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {