xref: /openbmc/linux/drivers/misc/mei/client.c (revision 9f81abda)
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 
17 #include <linux/pci.h>
18 #include <linux/sched.h>
19 #include <linux/wait.h>
20 #include <linux/delay.h>
21 
22 #include <linux/mei.h>
23 
24 #include "mei_dev.h"
25 #include "hbm.h"
26 #include "interface.h"
27 #include "client.h"
28 
29 /**
30  * mei_me_cl_by_uuid - locate index of me client
31  *
32  * @dev: mei device
33  * returns me client index or -ENOENT if not found
34  */
35 int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
36 {
37 	int i, res = -ENOENT;
38 
39 	for (i = 0; i < dev->me_clients_num; ++i)
40 		if (uuid_le_cmp(*uuid,
41 				dev->me_clients[i].props.protocol_name) == 0) {
42 			res = i;
43 			break;
44 		}
45 
46 	return res;
47 }
48 
49 
50 /**
51  * mei_me_cl_by_id return index to me_clients for client_id
52  *
53  * @dev: the device structure
54  * @client_id: me client id
55  *
56  * Locking: called under "dev->device_lock" lock
57  *
58  * returns index on success, -ENOENT on failure.
59  */
60 
61 int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
62 {
63 	int i;
64 	for (i = 0; i < dev->me_clients_num; i++)
65 		if (dev->me_clients[i].client_id == client_id)
66 			break;
67 	if (WARN_ON(dev->me_clients[i].client_id != client_id))
68 		return -ENOENT;
69 
70 	if (i == dev->me_clients_num)
71 		return -ENOENT;
72 
73 	return i;
74 }
75 
76 
77 /**
78  * mei_io_list_flush - removes list entry belonging to cl.
79  *
80  * @list:  An instance of our list structure
81  * @cl: host client
82  */
83 void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
84 {
85 	struct mei_cl_cb *cb;
86 	struct mei_cl_cb *next;
87 
88 	list_for_each_entry_safe(cb, next, &list->list, list) {
89 		if (cb->cl && mei_cl_cmp_id(cl, cb->cl))
90 			list_del(&cb->list);
91 	}
92 }
93 
94 /**
95  * mei_io_cb_free - free mei_cb_private related memory
96  *
97  * @cb: mei callback struct
98  */
99 void mei_io_cb_free(struct mei_cl_cb *cb)
100 {
101 	if (cb == NULL)
102 		return;
103 
104 	kfree(cb->request_buffer.data);
105 	kfree(cb->response_buffer.data);
106 	kfree(cb);
107 }
108 
109 /**
110  * mei_io_cb_init - allocate and initialize io callback
111  *
112  * @cl - mei client
113  * @file: pointer to file structure
114  *
115  * returns mei_cl_cb pointer or NULL;
116  */
117 struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
118 {
119 	struct mei_cl_cb *cb;
120 
121 	cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
122 	if (!cb)
123 		return NULL;
124 
125 	mei_io_list_init(cb);
126 
127 	cb->file_object = fp;
128 	cb->cl = cl;
129 	cb->buf_idx = 0;
130 	return cb;
131 }
132 
133 /**
134  * mei_io_cb_alloc_req_buf - allocate request buffer
135  *
136  * @cb -  io callback structure
137  * @size: size of the buffer
138  *
139  * returns 0 on success
140  *         -EINVAL if cb is NULL
141  *         -ENOMEM if allocation failed
142  */
143 int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
144 {
145 	if (!cb)
146 		return -EINVAL;
147 
148 	if (length == 0)
149 		return 0;
150 
151 	cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
152 	if (!cb->request_buffer.data)
153 		return -ENOMEM;
154 	cb->request_buffer.size = length;
155 	return 0;
156 }
157 /**
158  * mei_io_cb_alloc_req_buf - allocate respose buffer
159  *
160  * @cb -  io callback structure
161  * @size: size of the buffer
162  *
163  * returns 0 on success
164  *         -EINVAL if cb is NULL
165  *         -ENOMEM if allocation failed
166  */
167 int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
168 {
169 	if (!cb)
170 		return -EINVAL;
171 
172 	if (length == 0)
173 		return 0;
174 
175 	cb->response_buffer.data = kmalloc(length, GFP_KERNEL);
176 	if (!cb->response_buffer.data)
177 		return -ENOMEM;
178 	cb->response_buffer.size = length;
179 	return 0;
180 }
181 
182 
183 
184 /**
185  * mei_cl_flush_queues - flushes queue lists belonging to cl.
186  *
187  * @dev: the device structure
188  * @cl: host client
189  */
190 int mei_cl_flush_queues(struct mei_cl *cl)
191 {
192 	if (WARN_ON(!cl || !cl->dev))
193 		return -EINVAL;
194 
195 	dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n");
196 	mei_io_list_flush(&cl->dev->read_list, cl);
197 	mei_io_list_flush(&cl->dev->write_list, cl);
198 	mei_io_list_flush(&cl->dev->write_waiting_list, cl);
199 	mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
200 	mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
201 	mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
202 	mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
203 	return 0;
204 }
205 
206 
207 /**
208  * mei_cl_init - initializes intialize cl.
209  *
210  * @cl: host client to be initialized
211  * @dev: mei device
212  */
213 void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
214 {
215 	memset(cl, 0, sizeof(struct mei_cl));
216 	init_waitqueue_head(&cl->wait);
217 	init_waitqueue_head(&cl->rx_wait);
218 	init_waitqueue_head(&cl->tx_wait);
219 	INIT_LIST_HEAD(&cl->link);
220 	cl->reading_state = MEI_IDLE;
221 	cl->writing_state = MEI_IDLE;
222 	cl->dev = dev;
223 }
224 
225 /**
226  * mei_cl_allocate - allocates cl  structure and sets it up.
227  *
228  * @dev: mei device
229  * returns  The allocated file or NULL on failure
230  */
231 struct mei_cl *mei_cl_allocate(struct mei_device *dev)
232 {
233 	struct mei_cl *cl;
234 
235 	cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
236 	if (!cl)
237 		return NULL;
238 
239 	mei_cl_init(cl, dev);
240 
241 	return cl;
242 }
243 
244 /**
245  * mei_cl_find_read_cb - find this cl's callback in the read list
246  *
247  * @dev: device structure
248  * returns cb on success, NULL on error
249  */
250 struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
251 {
252 	struct mei_device *dev = cl->dev;
253 	struct mei_cl_cb *cb = NULL;
254 	struct mei_cl_cb *next = NULL;
255 
256 	list_for_each_entry_safe(cb, next, &dev->read_list.list, list)
257 		if (mei_cl_cmp_id(cl, cb->cl))
258 			return cb;
259 	return NULL;
260 }
261 
262 
263 /**
264  * mei_me_cl_link - create link between host and me clinet and add
265  *   me_cl to the list
266  *
267  * @cl: link between me and host client assocated with opened file descriptor
268  * @uuid: uuid of ME client
269  * @client_id: id of the host client
270  *
271  * returns ME client index if ME client
272  *	-EINVAL on incorrect values
273  *	-ENONET if client not found
274  */
275 int mei_cl_link_me(struct mei_cl *cl, const uuid_le *uuid, u8 host_cl_id)
276 {
277 	struct mei_device *dev;
278 	int i;
279 
280 	if (WARN_ON(!cl || !cl->dev || !uuid))
281 		return -EINVAL;
282 
283 	dev = cl->dev;
284 
285 	/* check for valid client id */
286 	i = mei_me_cl_by_uuid(dev, uuid);
287 	if (i >= 0) {
288 		cl->me_client_id = dev->me_clients[i].client_id;
289 		cl->state = MEI_FILE_CONNECTING;
290 		cl->host_client_id = host_cl_id;
291 
292 		list_add_tail(&cl->link, &dev->file_list);
293 		return (u8)i;
294 	}
295 
296 	return -ENOENT;
297 }
298 /**
299  * mei_cl_unlink - remove me_cl from the list
300  *
301  * @dev: the device structure
302  * @host_client_id: host client id to be removed
303  */
304 int mei_cl_unlink(struct mei_cl *cl)
305 {
306 	struct mei_device *dev;
307 	struct mei_cl *pos, *next;
308 
309 	if (WARN_ON(!cl || !cl->dev))
310 		return -EINVAL;
311 
312 	dev = cl->dev;
313 
314 	list_for_each_entry_safe(pos, next, &dev->file_list, link) {
315 		if (cl->host_client_id == pos->host_client_id) {
316 			dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n",
317 				pos->host_client_id, pos->me_client_id);
318 			list_del_init(&pos->link);
319 			break;
320 		}
321 	}
322 	return 0;
323 }
324 
325 
326 void mei_host_client_init(struct work_struct *work)
327 {
328 	struct mei_device *dev = container_of(work,
329 					      struct mei_device, init_work);
330 	struct mei_client_properties *client_props;
331 	int i;
332 
333 	mutex_lock(&dev->device_lock);
334 
335 	bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
336 	dev->open_handle_count = 0;
337 
338 	/*
339 	 * Reserving the first three client IDs
340 	 * 0: Reserved for MEI Bus Message communications
341 	 * 1: Reserved for Watchdog
342 	 * 2: Reserved for AMTHI
343 	 */
344 	bitmap_set(dev->host_clients_map, 0, 3);
345 
346 	for (i = 0; i < dev->me_clients_num; i++) {
347 		client_props = &dev->me_clients[i].props;
348 
349 		if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid))
350 			mei_amthif_host_init(dev);
351 		else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
352 			mei_wd_host_init(dev);
353 	}
354 
355 	dev->dev_state = MEI_DEV_ENABLED;
356 
357 	mutex_unlock(&dev->device_lock);
358 }
359 
360 
361 /**
362  * mei_cl_disconnect - disconnect host clinet form the me one
363  *
364  * @cl: host client
365  *
366  * Locking: called under "dev->device_lock" lock
367  *
368  * returns 0 on success, <0 on failure.
369  */
370 int mei_cl_disconnect(struct mei_cl *cl)
371 {
372 	struct mei_device *dev;
373 	struct mei_cl_cb *cb;
374 	int rets, err;
375 
376 	if (WARN_ON(!cl || !cl->dev))
377 		return -ENODEV;
378 
379 	dev = cl->dev;
380 
381 	if (cl->state != MEI_FILE_DISCONNECTING)
382 		return 0;
383 
384 	cb = mei_io_cb_init(cl, NULL);
385 	if (!cb)
386 		return -ENOMEM;
387 
388 	cb->fop_type = MEI_FOP_CLOSE;
389 	if (dev->mei_host_buffer_is_empty) {
390 		dev->mei_host_buffer_is_empty = false;
391 		if (mei_hbm_cl_disconnect_req(dev, cl)) {
392 			rets = -ENODEV;
393 			dev_err(&dev->pdev->dev, "failed to disconnect.\n");
394 			goto free;
395 		}
396 		mdelay(10); /* Wait for hardware disconnection ready */
397 		list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
398 	} else {
399 		dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
400 		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
401 
402 	}
403 	mutex_unlock(&dev->device_lock);
404 
405 	err = wait_event_timeout(dev->wait_recvd_msg,
406 			MEI_FILE_DISCONNECTED == cl->state,
407 			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
408 
409 	mutex_lock(&dev->device_lock);
410 	if (MEI_FILE_DISCONNECTED == cl->state) {
411 		rets = 0;
412 		dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n");
413 	} else {
414 		rets = -ENODEV;
415 		if (MEI_FILE_DISCONNECTED != cl->state)
416 			dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n");
417 
418 		if (err)
419 			dev_dbg(&dev->pdev->dev,
420 					"wait failed disconnect err=%08x\n",
421 					err);
422 
423 		dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
424 	}
425 
426 	mei_io_list_flush(&dev->ctrl_rd_list, cl);
427 	mei_io_list_flush(&dev->ctrl_wr_list, cl);
428 free:
429 	mei_io_cb_free(cb);
430 	return rets;
431 }
432 
433 
434 /**
435  * mei_cl_is_other_connecting - checks if other
436  *    client with the same me client id is connecting
437  *
438  * @cl: private data of the file object
439  *
440  * returns ture if other client is connected, 0 - otherwise.
441  */
442 bool mei_cl_is_other_connecting(struct mei_cl *cl)
443 {
444 	struct mei_device *dev;
445 	struct mei_cl *pos;
446 	struct mei_cl *next;
447 
448 	if (WARN_ON(!cl || !cl->dev))
449 		return false;
450 
451 	dev = cl->dev;
452 
453 	list_for_each_entry_safe(pos, next, &dev->file_list, link) {
454 		if ((pos->state == MEI_FILE_CONNECTING) &&
455 		    (pos != cl) && cl->me_client_id == pos->me_client_id)
456 			return true;
457 
458 	}
459 
460 	return false;
461 }
462 
463 /**
464  * mei_cl_connect - connect host clinet to the me one
465  *
466  * @cl: host client
467  *
468  * Locking: called under "dev->device_lock" lock
469  *
470  * returns 0 on success, <0 on failure.
471  */
472 int mei_cl_connect(struct mei_cl *cl, struct file *file)
473 {
474 	struct mei_device *dev;
475 	struct mei_cl_cb *cb;
476 	long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT);
477 	int rets;
478 
479 	if (WARN_ON(!cl || !cl->dev))
480 		return -ENODEV;
481 
482 	dev = cl->dev;
483 
484 	cb = mei_io_cb_init(cl, file);
485 	if (!cb) {
486 		rets = -ENOMEM;
487 		goto out;
488 	}
489 
490 	cb->fop_type = MEI_FOP_IOCTL;
491 
492 	if (dev->mei_host_buffer_is_empty &&
493 	    !mei_cl_is_other_connecting(cl)) {
494 		dev->mei_host_buffer_is_empty = false;
495 
496 		if (mei_hbm_cl_connect_req(dev, cl)) {
497 			rets = -ENODEV;
498 			goto out;
499 		}
500 		cl->timer_count = MEI_CONNECT_TIMEOUT;
501 		list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
502 	} else {
503 		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
504 	}
505 
506 	mutex_unlock(&dev->device_lock);
507 	rets = wait_event_timeout(dev->wait_recvd_msg,
508 				 (cl->state == MEI_FILE_CONNECTED ||
509 				  cl->state == MEI_FILE_DISCONNECTED),
510 				 timeout * HZ);
511 	mutex_lock(&dev->device_lock);
512 
513 	if (cl->state != MEI_FILE_CONNECTED) {
514 		rets = -EFAULT;
515 
516 		mei_io_list_flush(&dev->ctrl_rd_list, cl);
517 		mei_io_list_flush(&dev->ctrl_wr_list, cl);
518 		goto out;
519 	}
520 
521 	rets = cl->status;
522 
523 out:
524 	mei_io_cb_free(cb);
525 	return rets;
526 }
527 
528 /**
529  * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
530  *
531  * @dev: the device structure
532  * @cl: private data of the file object
533  *
534  * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
535  *	-ENOENT if mei_cl is not present
536  *	-EINVAL if single_recv_buf == 0
537  */
538 int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
539 {
540 	struct mei_device *dev;
541 	int i;
542 
543 	if (WARN_ON(!cl || !cl->dev))
544 		return -EINVAL;
545 
546 	dev = cl->dev;
547 
548 	if (!dev->me_clients_num)
549 		return 0;
550 
551 	if (cl->mei_flow_ctrl_creds > 0)
552 		return 1;
553 
554 	for (i = 0; i < dev->me_clients_num; i++) {
555 		struct mei_me_client  *me_cl = &dev->me_clients[i];
556 		if (me_cl->client_id == cl->me_client_id) {
557 			if (me_cl->mei_flow_ctrl_creds) {
558 				if (WARN_ON(me_cl->props.single_recv_buf == 0))
559 					return -EINVAL;
560 				return 1;
561 			} else {
562 				return 0;
563 			}
564 		}
565 	}
566 	return -ENOENT;
567 }
568 
569 /**
570  * mei_cl_flow_ctrl_reduce - reduces flow_control.
571  *
572  * @dev: the device structure
573  * @cl: private data of the file object
574  * @returns
575  *	0 on success
576  *	-ENOENT when me client is not found
577  *	-EINVAL when ctrl credits are <= 0
578  */
579 int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
580 {
581 	struct mei_device *dev;
582 	int i;
583 
584 	if (WARN_ON(!cl || !cl->dev))
585 		return -EINVAL;
586 
587 	dev = cl->dev;
588 
589 	if (!dev->me_clients_num)
590 		return -ENOENT;
591 
592 	for (i = 0; i < dev->me_clients_num; i++) {
593 		struct mei_me_client  *me_cl = &dev->me_clients[i];
594 		if (me_cl->client_id == cl->me_client_id) {
595 			if (me_cl->props.single_recv_buf != 0) {
596 				if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
597 					return -EINVAL;
598 				dev->me_clients[i].mei_flow_ctrl_creds--;
599 			} else {
600 				if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
601 					return -EINVAL;
602 				cl->mei_flow_ctrl_creds--;
603 			}
604 			return 0;
605 		}
606 	}
607 	return -ENOENT;
608 }
609 
610 /**
611  * mei_cl_start_read - the start read client message function.
612  *
613  * @cl: host client
614  *
615  * returns 0 on success, <0 on failure.
616  */
617 int mei_cl_read_start(struct mei_cl *cl)
618 {
619 	struct mei_device *dev;
620 	struct mei_cl_cb *cb;
621 	int rets;
622 	int i;
623 
624 	if (WARN_ON(!cl || !cl->dev))
625 		return -ENODEV;
626 
627 	dev = cl->dev;
628 
629 	if (cl->state != MEI_FILE_CONNECTED)
630 		return -ENODEV;
631 
632 	if (dev->dev_state != MEI_DEV_ENABLED)
633 		return -ENODEV;
634 
635 	if (cl->read_pending || cl->read_cb) {
636 		dev_dbg(&dev->pdev->dev, "read is pending.\n");
637 		return -EBUSY;
638 	}
639 	i = mei_me_cl_by_id(dev, cl->me_client_id);
640 	if (i < 0) {
641 		dev_err(&dev->pdev->dev, "no such me client %d\n",
642 			cl->me_client_id);
643 		return  -ENODEV;
644 	}
645 
646 	cb = mei_io_cb_init(cl, NULL);
647 	if (!cb)
648 		return -ENOMEM;
649 
650 	rets = mei_io_cb_alloc_resp_buf(cb,
651 			dev->me_clients[i].props.max_msg_length);
652 	if (rets)
653 		goto err;
654 
655 	cb->fop_type = MEI_FOP_READ;
656 	cl->read_cb = cb;
657 	if (dev->mei_host_buffer_is_empty) {
658 		dev->mei_host_buffer_is_empty = false;
659 		if (mei_hbm_cl_flow_control_req(dev, cl)) {
660 			rets = -ENODEV;
661 			goto err;
662 		}
663 		list_add_tail(&cb->list, &dev->read_list.list);
664 	} else {
665 		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
666 	}
667 	return rets;
668 err:
669 	mei_io_cb_free(cb);
670 	return rets;
671 }
672 
673