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