• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Intel Management Engine Interface (Intel MEI) Linux driver
4  * Copyright (c) 2003-2012, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  */
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/moduleparam.h>
19 #include <linux/device.h>
20 #include <linux/sched.h>
21 #include <linux/watchdog.h>
22 
23 #include <linux/mei.h>
24 
25 #include "mei_dev.h"
26 #include "hbm.h"
27 #include "client.h"
28 
29 static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
30 static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
31 
32 /*
33  * AMT Watchdog Device
34  */
35 #define INTEL_AMT_WATCHDOG_ID "INTCAMT"
36 
37 /* UUIDs for AMT F/W clients */
38 const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
39 						0x9D, 0xA9, 0x15, 0x14, 0xCB,
40 						0x32, 0xAB);
41 
mei_wd_set_start_timeout(struct mei_device * dev,u16 timeout)42 static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
43 {
44 	dev_dbg(dev->dev, "wd: set timeout=%d.\n", timeout);
45 	memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE);
46 	memcpy(dev->wd_data + MEI_WD_HDR_SIZE, &timeout, sizeof(u16));
47 }
48 
49 /**
50  * mei_wd_host_init - connect to the watchdog client
51  *
52  * @dev: the device structure
53  * @me_cl: me client
54  *
55  * Return: -ENOTTY if wd client cannot be found
56  *         -EIO if write has failed
57  *         0 on success
58  */
mei_wd_host_init(struct mei_device * dev,struct mei_me_client * me_cl)59 int mei_wd_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
60 {
61 	struct mei_cl *cl = &dev->wd_cl;
62 	int ret;
63 
64 	mei_cl_init(cl, dev);
65 
66 	dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT;
67 	dev->wd_state = MEI_WD_IDLE;
68 
69 	ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID);
70 	if (ret < 0) {
71 		dev_info(dev->dev, "wd: failed link client\n");
72 		return ret;
73 	}
74 
75 	ret = mei_cl_connect(cl, me_cl, NULL);
76 	if (ret) {
77 		dev_err(dev->dev, "wd: failed to connect = %d\n", ret);
78 		mei_cl_unlink(cl);
79 		return ret;
80 	}
81 
82 	ret = mei_watchdog_register(dev);
83 	if (ret) {
84 		mei_cl_disconnect(cl);
85 		mei_cl_unlink(cl);
86 	}
87 	return ret;
88 }
89 
90 /**
91  * mei_wd_send - sends watch dog message to fw.
92  *
93  * @dev: the device structure
94  *
95  * Return: 0 if success,
96  *	-EIO when message send fails
97  *	-EINVAL when invalid message is to be sent
98  *	-ENODEV on flow control failure
99  */
mei_wd_send(struct mei_device * dev)100 int mei_wd_send(struct mei_device *dev)
101 {
102 	struct mei_cl *cl = &dev->wd_cl;
103 	struct mei_msg_hdr hdr;
104 	int ret;
105 
106 	hdr.host_addr = cl->host_client_id;
107 	hdr.me_addr = mei_cl_me_id(cl);
108 	hdr.msg_complete = 1;
109 	hdr.reserved = 0;
110 	hdr.internal = 0;
111 
112 	if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE))
113 		hdr.length = MEI_WD_START_MSG_SIZE;
114 	else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
115 		hdr.length = MEI_WD_STOP_MSG_SIZE;
116 	else {
117 		dev_err(dev->dev, "wd: invalid message is to be sent, aborting\n");
118 		return -EINVAL;
119 	}
120 
121 	ret = mei_write_message(dev, &hdr, dev->wd_data);
122 	if (ret) {
123 		dev_err(dev->dev, "wd: write message failed\n");
124 		return ret;
125 	}
126 
127 	ret = mei_cl_flow_ctrl_reduce(cl);
128 	if (ret) {
129 		dev_err(dev->dev, "wd: flow_ctrl_reduce failed.\n");
130 		return ret;
131 	}
132 
133 	return 0;
134 }
135 
136 /**
137  * mei_wd_stop - sends watchdog stop message to fw.
138  *
139  * @dev: the device structure
140  *
141  * Return: 0 if success
142  * on error:
143  *	-EIO    when message send fails
144  *	-EINVAL when invalid message is to be sent
145  *	-ETIME  on message timeout
146  */
mei_wd_stop(struct mei_device * dev)147 int mei_wd_stop(struct mei_device *dev)
148 {
149 	struct mei_cl *cl = &dev->wd_cl;
150 	int ret;
151 
152 	if (!mei_cl_is_connected(cl) ||
153 	    dev->wd_state != MEI_WD_RUNNING)
154 		return 0;
155 
156 	memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_STOP_MSG_SIZE);
157 
158 	dev->wd_state = MEI_WD_STOPPING;
159 
160 	ret = mei_cl_flow_ctrl_creds(cl);
161 	if (ret < 0)
162 		goto err;
163 
164 	if (ret && mei_hbuf_acquire(dev)) {
165 		ret = mei_wd_send(dev);
166 		if (ret)
167 			goto err;
168 		dev->wd_pending = false;
169 	} else {
170 		dev->wd_pending = true;
171 	}
172 
173 	mutex_unlock(&dev->device_lock);
174 
175 	ret = wait_event_timeout(dev->wait_stop_wd,
176 				dev->wd_state == MEI_WD_IDLE,
177 				msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
178 	mutex_lock(&dev->device_lock);
179 	if (dev->wd_state != MEI_WD_IDLE) {
180 		/* timeout */
181 		ret = -ETIME;
182 		dev_warn(dev->dev, "wd: stop failed to complete ret=%d\n", ret);
183 		goto err;
184 	}
185 	dev_dbg(dev->dev, "wd: stop completed after %u msec\n",
186 			MEI_WD_STOP_TIMEOUT - jiffies_to_msecs(ret));
187 	return 0;
188 err:
189 	return ret;
190 }
191 
192 /**
193  * mei_wd_ops_start - wd start command from the watchdog core.
194  *
195  * @wd_dev: watchdog device struct
196  *
197  * Return: 0 if success, negative errno code for failure
198  */
mei_wd_ops_start(struct watchdog_device * wd_dev)199 static int mei_wd_ops_start(struct watchdog_device *wd_dev)
200 {
201 	struct mei_device *dev;
202 	struct mei_cl *cl;
203 	int err = -ENODEV;
204 
205 	dev = watchdog_get_drvdata(wd_dev);
206 	if (!dev)
207 		return -ENODEV;
208 
209 	cl = &dev->wd_cl;
210 
211 	mutex_lock(&dev->device_lock);
212 
213 	if (dev->dev_state != MEI_DEV_ENABLED) {
214 		dev_dbg(dev->dev, "wd: dev_state != MEI_DEV_ENABLED  dev_state = %s\n",
215 			mei_dev_state_str(dev->dev_state));
216 		goto end_unlock;
217 	}
218 
219 	if (!mei_cl_is_connected(cl)) {
220 		cl_dbg(dev, cl, "MEI Driver is not connected to Watchdog Client\n");
221 		goto end_unlock;
222 	}
223 
224 	mei_wd_set_start_timeout(dev, dev->wd_timeout);
225 
226 	err = 0;
227 end_unlock:
228 	mutex_unlock(&dev->device_lock);
229 	return err;
230 }
231 
232 /**
233  * mei_wd_ops_stop -  wd stop command from the watchdog core.
234  *
235  * @wd_dev: watchdog device struct
236  *
237  * Return: 0 if success, negative errno code for failure
238  */
mei_wd_ops_stop(struct watchdog_device * wd_dev)239 static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
240 {
241 	struct mei_device *dev;
242 
243 	dev = watchdog_get_drvdata(wd_dev);
244 	if (!dev)
245 		return -ENODEV;
246 
247 	mutex_lock(&dev->device_lock);
248 	mei_wd_stop(dev);
249 	mutex_unlock(&dev->device_lock);
250 
251 	return 0;
252 }
253 
254 /**
255  * mei_wd_ops_ping - wd ping command from the watchdog core.
256  *
257  * @wd_dev: watchdog device struct
258  *
259  * Return: 0 if success, negative errno code for failure
260  */
mei_wd_ops_ping(struct watchdog_device * wd_dev)261 static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
262 {
263 	struct mei_device *dev;
264 	struct mei_cl *cl;
265 	int ret;
266 
267 	dev = watchdog_get_drvdata(wd_dev);
268 	if (!dev)
269 		return -ENODEV;
270 
271 	cl = &dev->wd_cl;
272 
273 	mutex_lock(&dev->device_lock);
274 
275 	if (!mei_cl_is_connected(cl)) {
276 		cl_err(dev, cl, "wd: not connected.\n");
277 		ret = -ENODEV;
278 		goto end;
279 	}
280 
281 	dev->wd_state = MEI_WD_RUNNING;
282 
283 	ret = mei_cl_flow_ctrl_creds(cl);
284 	if (ret < 0)
285 		goto end;
286 
287 	/* Check if we can send the ping to HW*/
288 	if (ret && mei_hbuf_acquire(dev)) {
289 		dev_dbg(dev->dev, "wd: sending ping\n");
290 
291 		ret = mei_wd_send(dev);
292 		if (ret)
293 			goto end;
294 		dev->wd_pending = false;
295 	} else {
296 		dev->wd_pending = true;
297 	}
298 
299 end:
300 	mutex_unlock(&dev->device_lock);
301 	return ret;
302 }
303 
304 /**
305  * mei_wd_ops_set_timeout - wd set timeout command from the watchdog core.
306  *
307  * @wd_dev: watchdog device struct
308  * @timeout: timeout value to set
309  *
310  * Return: 0 if success, negative errno code for failure
311  */
mei_wd_ops_set_timeout(struct watchdog_device * wd_dev,unsigned int timeout)312 static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev,
313 		unsigned int timeout)
314 {
315 	struct mei_device *dev;
316 
317 	dev = watchdog_get_drvdata(wd_dev);
318 	if (!dev)
319 		return -ENODEV;
320 
321 	/* Check Timeout value */
322 	if (timeout < MEI_WD_MIN_TIMEOUT || timeout > MEI_WD_MAX_TIMEOUT)
323 		return -EINVAL;
324 
325 	mutex_lock(&dev->device_lock);
326 
327 	dev->wd_timeout = timeout;
328 	wd_dev->timeout = timeout;
329 	mei_wd_set_start_timeout(dev, dev->wd_timeout);
330 
331 	mutex_unlock(&dev->device_lock);
332 
333 	return 0;
334 }
335 
336 /*
337  * Watchdog Device structs
338  */
339 static const struct watchdog_ops wd_ops = {
340 		.owner = THIS_MODULE,
341 		.start = mei_wd_ops_start,
342 		.stop = mei_wd_ops_stop,
343 		.ping = mei_wd_ops_ping,
344 		.set_timeout = mei_wd_ops_set_timeout,
345 };
346 static const struct watchdog_info wd_info = {
347 		.identity = INTEL_AMT_WATCHDOG_ID,
348 		.options = WDIOF_KEEPALIVEPING |
349 			   WDIOF_SETTIMEOUT |
350 			   WDIOF_ALARMONLY,
351 };
352 
353 static struct watchdog_device amt_wd_dev = {
354 		.info = &wd_info,
355 		.ops = &wd_ops,
356 		.timeout = MEI_WD_DEFAULT_TIMEOUT,
357 		.min_timeout = MEI_WD_MIN_TIMEOUT,
358 		.max_timeout = MEI_WD_MAX_TIMEOUT,
359 };
360 
361 
mei_watchdog_register(struct mei_device * dev)362 int mei_watchdog_register(struct mei_device *dev)
363 {
364 
365 	int ret;
366 
367 	amt_wd_dev.parent = dev->dev;
368 	/* unlock to perserve correct locking order */
369 	mutex_unlock(&dev->device_lock);
370 	ret = watchdog_register_device(&amt_wd_dev);
371 	mutex_lock(&dev->device_lock);
372 	if (ret) {
373 		dev_err(dev->dev, "wd: unable to register watchdog device = %d.\n",
374 			ret);
375 		return ret;
376 	}
377 
378 	dev_dbg(dev->dev, "wd: successfully register watchdog interface.\n");
379 	watchdog_set_drvdata(&amt_wd_dev, dev);
380 	return 0;
381 }
382 
mei_watchdog_unregister(struct mei_device * dev)383 void mei_watchdog_unregister(struct mei_device *dev)
384 {
385 	if (watchdog_get_drvdata(&amt_wd_dev) == NULL)
386 		return;
387 
388 	watchdog_set_drvdata(&amt_wd_dev, NULL);
389 	watchdog_unregister_device(&amt_wd_dev);
390 }
391 
392