• 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/pci.h>
21 #include <linux/sched.h>
22 #include <linux/watchdog.h>
23 
24 #include <linux/mei.h>
25 
26 #include "mei_dev.h"
27 #include "hbm.h"
28 #include "hw-me.h"
29 #include "client.h"
30 
31 static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
32 static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
33 
34 const u8 mei_wd_state_independence_msg[3][4] = {
35 	{0x05, 0x02, 0x51, 0x10},
36 	{0x05, 0x02, 0x52, 0x10},
37 	{0x07, 0x02, 0x01, 0x10}
38 };
39 
40 /*
41  * AMT Watchdog Device
42  */
43 #define INTEL_AMT_WATCHDOG_ID "INTCAMT"
44 
45 /* UUIDs for AMT F/W clients */
46 const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
47 						0x9D, 0xA9, 0x15, 0x14, 0xCB,
48 						0x32, 0xAB);
49 
mei_wd_set_start_timeout(struct mei_device * dev,u16 timeout)50 static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
51 {
52 	dev_dbg(&dev->pdev->dev, "wd: set timeout=%d.\n", timeout);
53 	memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE);
54 	memcpy(dev->wd_data + MEI_WD_HDR_SIZE, &timeout, sizeof(u16));
55 }
56 
57 /**
58  * mei_wd_host_init - connect to the watchdog client
59  *
60  * @dev: the device structure
61  *
62  * returns -ENENT if wd client cannot be found
63  *         -EIO if write has failed
64  *         0 on success
65  */
mei_wd_host_init(struct mei_device * dev)66 int mei_wd_host_init(struct mei_device *dev)
67 {
68 	struct mei_cl *cl = &dev->wd_cl;
69 	int i;
70 	int ret;
71 
72 	mei_cl_init(cl, dev);
73 
74 	dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT;
75 	dev->wd_state = MEI_WD_IDLE;
76 
77 
78 	/* check for valid client id */
79 	i = mei_me_cl_by_uuid(dev, &mei_wd_guid);
80 	if (i < 0) {
81 		dev_info(&dev->pdev->dev, "wd: failed to find the client\n");
82 		return -ENOENT;
83 	}
84 
85 	cl->me_client_id = dev->me_clients[i].client_id;
86 
87 	ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID);
88 
89 	if (ret < 0) {
90 		dev_info(&dev->pdev->dev, "wd: failed link client\n");
91 		return -ENOENT;
92 	}
93 
94 	cl->state = MEI_FILE_CONNECTING;
95 
96 	if (mei_hbm_cl_connect_req(dev, cl)) {
97 		dev_err(&dev->pdev->dev, "wd: failed to connect to the client\n");
98 		cl->state = MEI_FILE_DISCONNECTED;
99 		cl->host_client_id = 0;
100 		return -EIO;
101 	}
102 	cl->timer_count = MEI_CONNECT_TIMEOUT;
103 
104 	return 0;
105 }
106 
107 /**
108  * mei_wd_send - sends watch dog message to fw.
109  *
110  * @dev: the device structure
111  *
112  * returns 0 if success,
113  *	-EIO when message send fails
114  *	-EINVAL when invalid message is to be sent
115  */
mei_wd_send(struct mei_device * dev)116 int mei_wd_send(struct mei_device *dev)
117 {
118 	struct mei_msg_hdr hdr;
119 
120 	hdr.host_addr = dev->wd_cl.host_client_id;
121 	hdr.me_addr = dev->wd_cl.me_client_id;
122 	hdr.msg_complete = 1;
123 	hdr.reserved = 0;
124 
125 	if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE))
126 		hdr.length = MEI_WD_START_MSG_SIZE;
127 	else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
128 		hdr.length = MEI_WD_STOP_MSG_SIZE;
129 	else
130 		return -EINVAL;
131 
132 	return mei_write_message(dev, &hdr, dev->wd_data);
133 }
134 
135 /**
136  * mei_wd_stop - sends watchdog stop message to fw.
137  *
138  * @dev: the device structure
139  * @preserve: indicate if to keep the timeout value
140  *
141  * returns 0 if success,
142  *	-EIO when message send fails
143  *	-EINVAL when invalid message is to be sent
144  */
mei_wd_stop(struct mei_device * dev)145 int mei_wd_stop(struct mei_device *dev)
146 {
147 	int ret;
148 
149 	if (dev->wd_cl.state != MEI_FILE_CONNECTED ||
150 	    dev->wd_state != MEI_WD_RUNNING)
151 		return 0;
152 
153 	memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_STOP_MSG_SIZE);
154 
155 	dev->wd_state = MEI_WD_STOPPING;
156 
157 	ret = mei_cl_flow_ctrl_creds(&dev->wd_cl);
158 	if (ret < 0)
159 		goto out;
160 
161 	if (ret && dev->hbuf_is_ready) {
162 		ret = 0;
163 		dev->hbuf_is_ready = false;
164 
165 		if (!mei_wd_send(dev)) {
166 			ret = mei_cl_flow_ctrl_reduce(&dev->wd_cl);
167 			if (ret)
168 				goto out;
169 		} else {
170 			dev_err(&dev->pdev->dev, "wd: send stop failed\n");
171 		}
172 
173 		dev->wd_pending = false;
174 	} else {
175 		dev->wd_pending = true;
176 	}
177 
178 	mutex_unlock(&dev->device_lock);
179 
180 	ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
181 					dev->wd_state == MEI_WD_IDLE,
182 					msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
183 	mutex_lock(&dev->device_lock);
184 	if (dev->wd_state == MEI_WD_IDLE) {
185 		dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
186 		ret = 0;
187 	} else {
188 		if (!ret)
189 			ret = -ETIMEDOUT;
190 		dev_warn(&dev->pdev->dev,
191 			"wd: stop failed to complete ret=%d.\n", ret);
192 	}
193 
194 out:
195 	return ret;
196 }
197 
198 /*
199  * mei_wd_ops_start - wd start command from the watchdog core.
200  *
201  * @wd_dev - watchdog device struct
202  *
203  * returns 0 if success, negative errno code for failure
204  */
mei_wd_ops_start(struct watchdog_device * wd_dev)205 static int mei_wd_ops_start(struct watchdog_device *wd_dev)
206 {
207 	int err = -ENODEV;
208 	struct mei_device *dev;
209 
210 	dev = watchdog_get_drvdata(wd_dev);
211 	if (!dev)
212 		return -ENODEV;
213 
214 	mutex_lock(&dev->device_lock);
215 
216 	if (dev->dev_state != MEI_DEV_ENABLED) {
217 		dev_dbg(&dev->pdev->dev,
218 			"wd: dev_state != MEI_DEV_ENABLED  dev_state = %s\n",
219 			mei_dev_state_str(dev->dev_state));
220 		goto end_unlock;
221 	}
222 
223 	if (dev->wd_cl.state != MEI_FILE_CONNECTED)	{
224 		dev_dbg(&dev->pdev->dev,
225 			"MEI Driver is not connected to Watchdog Client\n");
226 		goto end_unlock;
227 	}
228 
229 	mei_wd_set_start_timeout(dev, dev->wd_timeout);
230 
231 	err = 0;
232 end_unlock:
233 	mutex_unlock(&dev->device_lock);
234 	return err;
235 }
236 
237 /*
238  * mei_wd_ops_stop -  wd stop command from the watchdog core.
239  *
240  * @wd_dev - watchdog device struct
241  *
242  * returns 0 if success, negative errno code for failure
243  */
mei_wd_ops_stop(struct watchdog_device * wd_dev)244 static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
245 {
246 	struct mei_device *dev;
247 
248 	dev = watchdog_get_drvdata(wd_dev);
249 	if (!dev)
250 		return -ENODEV;
251 
252 	mutex_lock(&dev->device_lock);
253 	mei_wd_stop(dev);
254 	mutex_unlock(&dev->device_lock);
255 
256 	return 0;
257 }
258 
259 /*
260  * mei_wd_ops_ping - wd ping command from the watchdog core.
261  *
262  * @wd_dev - watchdog device struct
263  *
264  * returns 0 if success, negative errno code for failure
265  */
mei_wd_ops_ping(struct watchdog_device * wd_dev)266 static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
267 {
268 	int ret = 0;
269 	struct mei_device *dev;
270 
271 	dev = watchdog_get_drvdata(wd_dev);
272 	if (!dev)
273 		return -ENODEV;
274 
275 	mutex_lock(&dev->device_lock);
276 
277 	if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
278 		dev_err(&dev->pdev->dev, "wd: not connected.\n");
279 		ret = -ENODEV;
280 		goto end;
281 	}
282 
283 	dev->wd_state = MEI_WD_RUNNING;
284 
285 	/* Check if we can send the ping to HW*/
286 	if (dev->hbuf_is_ready && mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
287 
288 		dev->hbuf_is_ready = false;
289 		dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
290 
291 		if (mei_wd_send(dev)) {
292 			dev_err(&dev->pdev->dev, "wd: send failed.\n");
293 			ret = -EIO;
294 			goto end;
295 		}
296 
297 		if (mei_cl_flow_ctrl_reduce(&dev->wd_cl)) {
298 			dev_err(&dev->pdev->dev,
299 				"wd: mei_cl_flow_ctrl_reduce() failed.\n");
300 			ret = -EIO;
301 			goto end;
302 		}
303 
304 	} else {
305 		dev->wd_pending = true;
306 	}
307 
308 end:
309 	mutex_unlock(&dev->device_lock);
310 	return ret;
311 }
312 
313 /*
314  * mei_wd_ops_set_timeout - wd set timeout command from the watchdog core.
315  *
316  * @wd_dev - watchdog device struct
317  * @timeout - timeout value to set
318  *
319  * returns 0 if success, negative errno code for failure
320  */
mei_wd_ops_set_timeout(struct watchdog_device * wd_dev,unsigned int timeout)321 static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev,
322 		unsigned int timeout)
323 {
324 	struct mei_device *dev;
325 
326 	dev = watchdog_get_drvdata(wd_dev);
327 	if (!dev)
328 		return -ENODEV;
329 
330 	/* Check Timeout value */
331 	if (timeout < MEI_WD_MIN_TIMEOUT || timeout > MEI_WD_MAX_TIMEOUT)
332 		return -EINVAL;
333 
334 	mutex_lock(&dev->device_lock);
335 
336 	dev->wd_timeout = timeout;
337 	wd_dev->timeout = timeout;
338 	mei_wd_set_start_timeout(dev, dev->wd_timeout);
339 
340 	mutex_unlock(&dev->device_lock);
341 
342 	return 0;
343 }
344 
345 /*
346  * Watchdog Device structs
347  */
348 static const struct watchdog_ops wd_ops = {
349 		.owner = THIS_MODULE,
350 		.start = mei_wd_ops_start,
351 		.stop = mei_wd_ops_stop,
352 		.ping = mei_wd_ops_ping,
353 		.set_timeout = mei_wd_ops_set_timeout,
354 };
355 static const struct watchdog_info wd_info = {
356 		.identity = INTEL_AMT_WATCHDOG_ID,
357 		.options = WDIOF_KEEPALIVEPING |
358 			   WDIOF_SETTIMEOUT |
359 			   WDIOF_ALARMONLY,
360 };
361 
362 static struct watchdog_device amt_wd_dev = {
363 		.info = &wd_info,
364 		.ops = &wd_ops,
365 		.timeout = MEI_WD_DEFAULT_TIMEOUT,
366 		.min_timeout = MEI_WD_MIN_TIMEOUT,
367 		.max_timeout = MEI_WD_MAX_TIMEOUT,
368 };
369 
370 
mei_watchdog_register(struct mei_device * dev)371 void mei_watchdog_register(struct mei_device *dev)
372 {
373 	if (watchdog_register_device(&amt_wd_dev)) {
374 		dev_err(&dev->pdev->dev,
375 			"wd: unable to register watchdog device.\n");
376 		return;
377 	}
378 
379 	dev_dbg(&dev->pdev->dev,
380 		"wd: successfully register watchdog interface.\n");
381 	watchdog_set_drvdata(&amt_wd_dev, dev);
382 }
383 
mei_watchdog_unregister(struct mei_device * dev)384 void mei_watchdog_unregister(struct mei_device *dev)
385 {
386 	if (watchdog_get_drvdata(&amt_wd_dev) == NULL)
387 		return;
388 
389 	watchdog_set_drvdata(&amt_wd_dev, NULL);
390 	watchdog_unregister_device(&amt_wd_dev);
391 }
392 
393