]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/misc/mei/client.c
mei: normalize me host client linking routines
[karo-tx-linux.git] / 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         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         if (WARN_ON(!cl->dev))
316                 return -EINVAL;
317
318         dev = cl->dev;
319
320         list_for_each_entry_safe(pos, next, &dev->file_list, link) {
321                 if (cl->host_client_id == pos->host_client_id) {
322                         dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n",
323                                 pos->host_client_id, pos->me_client_id);
324                         list_del_init(&pos->link);
325                         break;
326                 }
327         }
328         return 0;
329 }
330
331
332 void mei_host_client_init(struct work_struct *work)
333 {
334         struct mei_device *dev = container_of(work,
335                                               struct mei_device, init_work);
336         struct mei_client_properties *client_props;
337         int i;
338
339         mutex_lock(&dev->device_lock);
340
341         bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
342         dev->open_handle_count = 0;
343
344         /*
345          * Reserving the first three client IDs
346          * 0: Reserved for MEI Bus Message communications
347          * 1: Reserved for Watchdog
348          * 2: Reserved for AMTHI
349          */
350         bitmap_set(dev->host_clients_map, 0, 3);
351
352         for (i = 0; i < dev->me_clients_num; i++) {
353                 client_props = &dev->me_clients[i].props;
354
355                 if (!uuid_le_cmp(client_props->protocol_name, mei_amthif_guid))
356                         mei_amthif_host_init(dev);
357                 else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
358                         mei_wd_host_init(dev);
359         }
360
361         dev->dev_state = MEI_DEV_ENABLED;
362
363         mutex_unlock(&dev->device_lock);
364 }
365
366
367 /**
368  * mei_cl_disconnect - disconnect host clinet form the me one
369  *
370  * @cl: host client
371  *
372  * Locking: called under "dev->device_lock" lock
373  *
374  * returns 0 on success, <0 on failure.
375  */
376 int mei_cl_disconnect(struct mei_cl *cl)
377 {
378         struct mei_device *dev;
379         struct mei_cl_cb *cb;
380         int rets, err;
381
382         if (WARN_ON(!cl || !cl->dev))
383                 return -ENODEV;
384
385         dev = cl->dev;
386
387         if (cl->state != MEI_FILE_DISCONNECTING)
388                 return 0;
389
390         cb = mei_io_cb_init(cl, NULL);
391         if (!cb)
392                 return -ENOMEM;
393
394         cb->fop_type = MEI_FOP_CLOSE;
395         if (dev->mei_host_buffer_is_empty) {
396                 dev->mei_host_buffer_is_empty = false;
397                 if (mei_hbm_cl_disconnect_req(dev, cl)) {
398                         rets = -ENODEV;
399                         dev_err(&dev->pdev->dev, "failed to disconnect.\n");
400                         goto free;
401                 }
402                 mdelay(10); /* Wait for hardware disconnection ready */
403                 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
404         } else {
405                 dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
406                 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
407
408         }
409         mutex_unlock(&dev->device_lock);
410
411         err = wait_event_timeout(dev->wait_recvd_msg,
412                         MEI_FILE_DISCONNECTED == cl->state,
413                         mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
414
415         mutex_lock(&dev->device_lock);
416         if (MEI_FILE_DISCONNECTED == cl->state) {
417                 rets = 0;
418                 dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n");
419         } else {
420                 rets = -ENODEV;
421                 if (MEI_FILE_DISCONNECTED != cl->state)
422                         dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n");
423
424                 if (err)
425                         dev_dbg(&dev->pdev->dev,
426                                         "wait failed disconnect err=%08x\n",
427                                         err);
428
429                 dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
430         }
431
432         mei_io_list_flush(&dev->ctrl_rd_list, cl);
433         mei_io_list_flush(&dev->ctrl_wr_list, cl);
434 free:
435         mei_io_cb_free(cb);
436         return rets;
437 }
438
439
440 /**
441  * mei_cl_is_other_connecting - checks if other
442  *    client with the same me client id is connecting
443  *
444  * @cl: private data of the file object
445  *
446  * returns ture if other client is connected, 0 - otherwise.
447  */
448 bool mei_cl_is_other_connecting(struct mei_cl *cl)
449 {
450         struct mei_device *dev;
451         struct mei_cl *pos;
452         struct mei_cl *next;
453
454         if (WARN_ON(!cl || !cl->dev))
455                 return false;
456
457         dev = cl->dev;
458
459         list_for_each_entry_safe(pos, next, &dev->file_list, link) {
460                 if ((pos->state == MEI_FILE_CONNECTING) &&
461                     (pos != cl) && cl->me_client_id == pos->me_client_id)
462                         return true;
463
464         }
465
466         return false;
467 }
468
469 /**
470  * mei_cl_connect - connect host clinet to the me one
471  *
472  * @cl: host client
473  *
474  * Locking: called under "dev->device_lock" lock
475  *
476  * returns 0 on success, <0 on failure.
477  */
478 int mei_cl_connect(struct mei_cl *cl, struct file *file)
479 {
480         struct mei_device *dev;
481         struct mei_cl_cb *cb;
482         long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT);
483         int rets;
484
485         if (WARN_ON(!cl || !cl->dev))
486                 return -ENODEV;
487
488         dev = cl->dev;
489
490         cb = mei_io_cb_init(cl, file);
491         if (!cb) {
492                 rets = -ENOMEM;
493                 goto out;
494         }
495
496         cb->fop_type = MEI_FOP_IOCTL;
497
498         if (dev->mei_host_buffer_is_empty &&
499             !mei_cl_is_other_connecting(cl)) {
500                 dev->mei_host_buffer_is_empty = 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->mei_host_buffer_is_empty) {
664                 dev->mei_host_buffer_is_empty = 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