]> Pileus Git - ~andy/linux/blob - drivers/misc/mei/client.c
Merge tag 'extcon-for-3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo...
[~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  * @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         INIT_LIST_HEAD(&cl->device_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 /** mei_cl_link: allocte host id in the host map
263  *
264  * @cl - host client
265  * @id - fixed host id or -1 for genereting one
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  * @dev: the device structure
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  * @dev: the device structure
539  * @cl: private data of the file object
540  *
541  * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
542  *      -ENOENT if mei_cl is not present
543  *      -EINVAL if single_recv_buf == 0
544  */
545 int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
546 {
547         struct mei_device *dev;
548         int i;
549
550         if (WARN_ON(!cl || !cl->dev))
551                 return -EINVAL;
552
553         dev = cl->dev;
554
555         if (!dev->me_clients_num)
556                 return 0;
557
558         if (cl->mei_flow_ctrl_creds > 0)
559                 return 1;
560
561         for (i = 0; i < dev->me_clients_num; i++) {
562                 struct mei_me_client  *me_cl = &dev->me_clients[i];
563                 if (me_cl->client_id == cl->me_client_id) {
564                         if (me_cl->mei_flow_ctrl_creds) {
565                                 if (WARN_ON(me_cl->props.single_recv_buf == 0))
566                                         return -EINVAL;
567                                 return 1;
568                         } else {
569                                 return 0;
570                         }
571                 }
572         }
573         return -ENOENT;
574 }
575
576 /**
577  * mei_cl_flow_ctrl_reduce - reduces flow_control.
578  *
579  * @dev: the device structure
580  * @cl: private data of the file object
581  * @returns
582  *      0 on success
583  *      -ENOENT when me client is not found
584  *      -EINVAL when ctrl credits are <= 0
585  */
586 int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
587 {
588         struct mei_device *dev;
589         int i;
590
591         if (WARN_ON(!cl || !cl->dev))
592                 return -EINVAL;
593
594         dev = cl->dev;
595
596         if (!dev->me_clients_num)
597                 return -ENOENT;
598
599         for (i = 0; i < dev->me_clients_num; i++) {
600                 struct mei_me_client  *me_cl = &dev->me_clients[i];
601                 if (me_cl->client_id == cl->me_client_id) {
602                         if (me_cl->props.single_recv_buf != 0) {
603                                 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
604                                         return -EINVAL;
605                                 dev->me_clients[i].mei_flow_ctrl_creds--;
606                         } else {
607                                 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
608                                         return -EINVAL;
609                                 cl->mei_flow_ctrl_creds--;
610                         }
611                         return 0;
612                 }
613         }
614         return -ENOENT;
615 }
616
617 /**
618  * mei_cl_start_read - the start read client message function.
619  *
620  * @cl: host client
621  *
622  * returns 0 on success, <0 on failure.
623  */
624 int mei_cl_read_start(struct mei_cl *cl)
625 {
626         struct mei_device *dev;
627         struct mei_cl_cb *cb;
628         int rets;
629         int i;
630
631         if (WARN_ON(!cl || !cl->dev))
632                 return -ENODEV;
633
634         dev = cl->dev;
635
636         if (cl->state != MEI_FILE_CONNECTED)
637                 return -ENODEV;
638
639         if (dev->dev_state != MEI_DEV_ENABLED)
640                 return -ENODEV;
641
642         if (cl->read_cb) {
643                 dev_dbg(&dev->pdev->dev, "read is pending.\n");
644                 return -EBUSY;
645         }
646         i = mei_me_cl_by_id(dev, cl->me_client_id);
647         if (i < 0) {
648                 dev_err(&dev->pdev->dev, "no such me client %d\n",
649                         cl->me_client_id);
650                 return  -ENODEV;
651         }
652
653         cb = mei_io_cb_init(cl, NULL);
654         if (!cb)
655                 return -ENOMEM;
656
657         rets = mei_io_cb_alloc_resp_buf(cb,
658                         dev->me_clients[i].props.max_msg_length);
659         if (rets)
660                 goto err;
661
662         cb->fop_type = MEI_FOP_READ;
663         cl->read_cb = cb;
664         if (dev->hbuf_is_ready) {
665                 dev->hbuf_is_ready = false;
666                 if (mei_hbm_cl_flow_control_req(dev, cl)) {
667                         rets = -ENODEV;
668                         goto err;
669                 }
670                 list_add_tail(&cb->list, &dev->read_list.list);
671         } else {
672                 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
673         }
674         return rets;
675 err:
676         mei_io_cb_free(cb);
677         return rets;
678 }
679
680 /**
681  * mei_cl_all_disconnect - disconnect forcefully all connected clients
682  *
683  * @dev - mei device
684  */
685
686 void mei_cl_all_disconnect(struct mei_device *dev)
687 {
688         struct mei_cl *cl, *next;
689
690         list_for_each_entry_safe(cl, next, &dev->file_list, link) {
691                 cl->state = MEI_FILE_DISCONNECTED;
692                 cl->mei_flow_ctrl_creds = 0;
693                 cl->read_cb = NULL;
694                 cl->timer_count = 0;
695         }
696 }
697
698
699 /**
700  * mei_cl_all_read_wakeup  - wake up all readings so they can be interrupted
701  *
702  * @dev  - mei device
703  */
704 void mei_cl_all_read_wakeup(struct mei_device *dev)
705 {
706         struct mei_cl *cl, *next;
707         list_for_each_entry_safe(cl, next, &dev->file_list, link) {
708                 if (waitqueue_active(&cl->rx_wait)) {
709                         dev_dbg(&dev->pdev->dev, "Waking up client!\n");
710                         wake_up_interruptible(&cl->rx_wait);
711                 }
712         }
713 }
714
715 /**
716  * mei_cl_all_write_clear - clear all pending writes
717
718  * @dev - mei device
719  */
720 void mei_cl_all_write_clear(struct mei_device *dev)
721 {
722         struct mei_cl_cb *cb, *next;
723
724         list_for_each_entry_safe(cb, next, &dev->write_list.list, list) {
725                 list_del(&cb->list);
726                 mei_io_cb_free(cb);
727         }
728 }
729
730