]> Pileus Git - ~andy/linux/blob - drivers/misc/mei/client.c
mei: Fix comments in drivers/misc/mei
[~andy/linux] / drivers / misc / mei / client.c
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  * @fp: 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  * @length: 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_resp_buf - allocate respose buffer
158  *
159  * @cb: io callback structure
160  * @length: 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  * @cl: host client
187  */
188 int mei_cl_flush_queues(struct mei_cl *cl)
189 {
190         if (WARN_ON(!cl || !cl->dev))
191                 return -EINVAL;
192
193         dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n");
194         mei_io_list_flush(&cl->dev->read_list, cl);
195         mei_io_list_flush(&cl->dev->write_list, cl);
196         mei_io_list_flush(&cl->dev->write_waiting_list, cl);
197         mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
198         mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
199         mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
200         mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
201         return 0;
202 }
203
204
205 /**
206  * mei_cl_init - initializes intialize cl.
207  *
208  * @cl: host client to be initialized
209  * @dev: mei device
210  */
211 void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
212 {
213         memset(cl, 0, sizeof(struct mei_cl));
214         init_waitqueue_head(&cl->wait);
215         init_waitqueue_head(&cl->rx_wait);
216         init_waitqueue_head(&cl->tx_wait);
217         INIT_LIST_HEAD(&cl->link);
218         cl->reading_state = MEI_IDLE;
219         cl->writing_state = MEI_IDLE;
220         cl->dev = dev;
221 }
222
223 /**
224  * mei_cl_allocate - allocates cl  structure and sets it up.
225  *
226  * @dev: mei device
227  * returns  The allocated file or NULL on failure
228  */
229 struct mei_cl *mei_cl_allocate(struct mei_device *dev)
230 {
231         struct mei_cl *cl;
232
233         cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
234         if (!cl)
235                 return NULL;
236
237         mei_cl_init(cl, dev);
238
239         return cl;
240 }
241
242 /**
243  * mei_cl_find_read_cb - find this cl's callback in the read list
244  *
245  * @cl: host client
246  *
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  *
266  * returns 0 on success
267  *      -EINVAL on incorrect values
268  *      -ENONET if client not found
269  */
270 int mei_cl_link(struct mei_cl *cl, int id)
271 {
272         struct mei_device *dev;
273
274         if (WARN_ON(!cl || !cl->dev))
275                 return -EINVAL;
276
277         dev = cl->dev;
278
279         /* If Id is not asigned get one*/
280         if (id == MEI_HOST_CLIENT_ID_ANY)
281                 id = find_first_zero_bit(dev->host_clients_map,
282                                         MEI_CLIENTS_MAX);
283
284         if (id >= MEI_CLIENTS_MAX) {
285                 dev_err(&dev->pdev->dev, "id exceded %d", MEI_CLIENTS_MAX) ;
286                 return -ENOENT;
287         }
288
289         dev->open_handle_count++;
290
291         cl->host_client_id = id;
292         list_add_tail(&cl->link, &dev->file_list);
293
294         set_bit(id, dev->host_clients_map);
295
296         cl->state = MEI_FILE_INITIALIZING;
297
298         dev_dbg(&dev->pdev->dev, "link cl host id = %d\n", cl->host_client_id);
299         return 0;
300 }
301
302 /**
303  * mei_cl_unlink - remove me_cl from the list
304  *
305  * @cl: host client
306  */
307 int mei_cl_unlink(struct mei_cl *cl)
308 {
309         struct mei_device *dev;
310         struct mei_cl *pos, *next;
311
312         /* don't shout on error exit path */
313         if (!cl)
314                 return 0;
315
316         /* wd and amthif might not be initialized */
317         if (!cl->dev)
318                 return 0;
319
320         dev = cl->dev;
321
322         list_for_each_entry_safe(pos, next, &dev->file_list, link) {
323                 if (cl->host_client_id == pos->host_client_id) {
324                         dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n",
325                                 pos->host_client_id, pos->me_client_id);
326                         list_del_init(&pos->link);
327                         break;
328                 }
329         }
330         return 0;
331 }
332
333
334 void mei_host_client_init(struct work_struct *work)
335 {
336         struct mei_device *dev = container_of(work,
337                                               struct mei_device, init_work);
338         struct mei_client_properties *client_props;
339         int i;
340
341         mutex_lock(&dev->device_lock);
342
343         bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
344         dev->open_handle_count = 0;
345
346         /*
347          * Reserving the first three client IDs
348          * 0: Reserved for MEI Bus Message communications
349          * 1: Reserved for Watchdog
350          * 2: Reserved for AMTHI
351          */
352         bitmap_set(dev->host_clients_map, 0, 3);
353
354         for (i = 0; i < dev->me_clients_num; i++) {
355                 client_props = &dev->me_clients[i].props;
356
357                 if (!uuid_le_cmp(client_props->protocol_name, mei_amthif_guid))
358                         mei_amthif_host_init(dev);
359                 else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
360                         mei_wd_host_init(dev);
361         }
362
363         dev->dev_state = MEI_DEV_ENABLED;
364
365         mutex_unlock(&dev->device_lock);
366 }
367
368
369 /**
370  * mei_cl_disconnect - disconnect host clinet form the me one
371  *
372  * @cl: host client
373  *
374  * Locking: called under "dev->device_lock" lock
375  *
376  * returns 0 on success, <0 on failure.
377  */
378 int mei_cl_disconnect(struct mei_cl *cl)
379 {
380         struct mei_device *dev;
381         struct mei_cl_cb *cb;
382         int rets, err;
383
384         if (WARN_ON(!cl || !cl->dev))
385                 return -ENODEV;
386
387         dev = cl->dev;
388
389         if (cl->state != MEI_FILE_DISCONNECTING)
390                 return 0;
391
392         cb = mei_io_cb_init(cl, NULL);
393         if (!cb)
394                 return -ENOMEM;
395
396         cb->fop_type = MEI_FOP_CLOSE;
397         if (dev->hbuf_is_ready) {
398                 dev->hbuf_is_ready = false;
399                 if (mei_hbm_cl_disconnect_req(dev, cl)) {
400                         rets = -ENODEV;
401                         dev_err(&dev->pdev->dev, "failed to disconnect.\n");
402                         goto free;
403                 }
404                 mdelay(10); /* Wait for hardware disconnection ready */
405                 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
406         } else {
407                 dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
408                 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
409
410         }
411         mutex_unlock(&dev->device_lock);
412
413         err = wait_event_timeout(dev->wait_recvd_msg,
414                         MEI_FILE_DISCONNECTED == cl->state,
415                         mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
416
417         mutex_lock(&dev->device_lock);
418         if (MEI_FILE_DISCONNECTED == cl->state) {
419                 rets = 0;
420                 dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n");
421         } else {
422                 rets = -ENODEV;
423                 if (MEI_FILE_DISCONNECTED != cl->state)
424                         dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n");
425
426                 if (err)
427                         dev_dbg(&dev->pdev->dev,
428                                         "wait failed disconnect err=%08x\n",
429                                         err);
430
431                 dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
432         }
433
434         mei_io_list_flush(&dev->ctrl_rd_list, cl);
435         mei_io_list_flush(&dev->ctrl_wr_list, cl);
436 free:
437         mei_io_cb_free(cb);
438         return rets;
439 }
440
441
442 /**
443  * mei_cl_is_other_connecting - checks if other
444  *    client with the same me client id is connecting
445  *
446  * @cl: private data of the file object
447  *
448  * returns ture if other client is connected, 0 - otherwise.
449  */
450 bool mei_cl_is_other_connecting(struct mei_cl *cl)
451 {
452         struct mei_device *dev;
453         struct mei_cl *pos;
454         struct mei_cl *next;
455
456         if (WARN_ON(!cl || !cl->dev))
457                 return false;
458
459         dev = cl->dev;
460
461         list_for_each_entry_safe(pos, next, &dev->file_list, link) {
462                 if ((pos->state == MEI_FILE_CONNECTING) &&
463                     (pos != cl) && cl->me_client_id == pos->me_client_id)
464                         return true;
465
466         }
467
468         return false;
469 }
470
471 /**
472  * mei_cl_connect - connect host clinet to the me one
473  *
474  * @cl: host client
475  *
476  * Locking: called under "dev->device_lock" lock
477  *
478  * returns 0 on success, <0 on failure.
479  */
480 int mei_cl_connect(struct mei_cl *cl, struct file *file)
481 {
482         struct mei_device *dev;
483         struct mei_cl_cb *cb;
484         long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT);
485         int rets;
486
487         if (WARN_ON(!cl || !cl->dev))
488                 return -ENODEV;
489
490         dev = cl->dev;
491
492         cb = mei_io_cb_init(cl, file);
493         if (!cb) {
494                 rets = -ENOMEM;
495                 goto out;
496         }
497
498         cb->fop_type = MEI_FOP_IOCTL;
499
500         if (dev->hbuf_is_ready && !mei_cl_is_other_connecting(cl)) {
501                 dev->hbuf_is_ready = false;
502
503                 if (mei_hbm_cl_connect_req(dev, cl)) {
504                         rets = -ENODEV;
505                         goto out;
506                 }
507                 cl->timer_count = MEI_CONNECT_TIMEOUT;
508                 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
509         } else {
510                 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
511         }
512
513         mutex_unlock(&dev->device_lock);
514         rets = wait_event_timeout(dev->wait_recvd_msg,
515                                  (cl->state == MEI_FILE_CONNECTED ||
516                                   cl->state == MEI_FILE_DISCONNECTED),
517                                  timeout * HZ);
518         mutex_lock(&dev->device_lock);
519
520         if (cl->state != MEI_FILE_CONNECTED) {
521                 rets = -EFAULT;
522
523                 mei_io_list_flush(&dev->ctrl_rd_list, cl);
524                 mei_io_list_flush(&dev->ctrl_wr_list, cl);
525                 goto out;
526         }
527
528         rets = cl->status;
529
530 out:
531         mei_io_cb_free(cb);
532         return rets;
533 }
534
535 /**
536  * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
537  *
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  * @cl: private data of the file object
579  *
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_read_start - 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