mei: rename remaining amthi strings to amthif
[pandora-kernel.git] / drivers / misc / mei / amthif.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/kernel.h>
18 #include <linux/fs.h>
19 #include <linux/errno.h>
20 #include <linux/types.h>
21 #include <linux/fcntl.h>
22 #include <linux/aio.h>
23 #include <linux/pci.h>
24 #include <linux/init.h>
25 #include <linux/ioctl.h>
26 #include <linux/cdev.h>
27 #include <linux/list.h>
28 #include <linux/delay.h>
29 #include <linux/sched.h>
30 #include <linux/uuid.h>
31 #include <linux/jiffies.h>
32 #include <linux/uaccess.h>
33
34 #include <linux/mei.h>
35
36 #include "mei_dev.h"
37 #include "hbm.h"
38 #include "hw-me.h"
39 #include "client.h"
40
41 const uuid_le mei_amthif_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
42                                          0xac, 0xa8, 0x46, 0xe0,
43                                          0xff, 0x65, 0x81, 0x4c);
44
45 /**
46  * mei_amthif_reset_params - initializes mei device iamthif
47  *
48  * @dev: the device structure
49  */
50 void mei_amthif_reset_params(struct mei_device *dev)
51 {
52         /* reset iamthif parameters. */
53         dev->iamthif_current_cb = NULL;
54         dev->iamthif_msg_buf_size = 0;
55         dev->iamthif_msg_buf_index = 0;
56         dev->iamthif_canceled = false;
57         dev->iamthif_ioctl = false;
58         dev->iamthif_state = MEI_IAMTHIF_IDLE;
59         dev->iamthif_timer = 0;
60 }
61
62 /**
63  * mei_amthif_host_init_ - mei initialization amthif client.
64  *
65  * @dev: the device structure
66  *
67  */
68 void mei_amthif_host_init(struct mei_device *dev)
69 {
70         int i;
71         unsigned char *msg_buf;
72
73         mei_cl_init(&dev->iamthif_cl, dev);
74         dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
75
76         /* find ME amthif client */
77         i = mei_cl_link_me(&dev->iamthif_cl,
78                             &mei_amthif_guid, MEI_IAMTHIF_HOST_CLIENT_ID);
79         if (i < 0) {
80                 dev_info(&dev->pdev->dev, "failed to find iamthif client.\n");
81                 return;
82         }
83
84         /* Assign iamthif_mtu to the value received from ME  */
85
86         dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length;
87         dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n",
88                         dev->me_clients[i].props.max_msg_length);
89
90         kfree(dev->iamthif_msg_buf);
91         dev->iamthif_msg_buf = NULL;
92
93         /* allocate storage for ME message buffer */
94         msg_buf = kcalloc(dev->iamthif_mtu,
95                         sizeof(unsigned char), GFP_KERNEL);
96         if (!msg_buf) {
97                 dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n");
98                 return;
99         }
100
101         dev->iamthif_msg_buf = msg_buf;
102
103         if (mei_hbm_cl_connect_req(dev, &dev->iamthif_cl)) {
104                 dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n");
105                 dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
106                 dev->iamthif_cl.host_client_id = 0;
107         } else {
108                 dev->iamthif_cl.timer_count = MEI_CONNECT_TIMEOUT;
109         }
110 }
111
112 /**
113  * mei_amthif_find_read_list_entry - finds a amthilist entry for current file
114  *
115  * @dev: the device structure
116  * @file: pointer to file object
117  *
118  * returns   returned a list entry on success, NULL on failure.
119  */
120 struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
121                                                 struct file *file)
122 {
123         struct mei_cl_cb *pos = NULL;
124         struct mei_cl_cb *next = NULL;
125
126         list_for_each_entry_safe(pos, next,
127                                 &dev->amthif_rd_complete_list.list, list) {
128                 if (pos->cl && pos->cl == &dev->iamthif_cl &&
129                         pos->file_object == file)
130                         return pos;
131         }
132         return NULL;
133 }
134
135
136 /**
137  * mei_amthif_read - read data from AMTHIF client
138  *
139  * @dev: the device structure
140  * @if_num:  minor number
141  * @file: pointer to file object
142  * @*ubuf: pointer to user data in user space
143  * @length: data length to read
144  * @offset: data read offset
145  *
146  * Locking: called under "dev->device_lock" lock
147  *
148  * returns
149  *  returned data length on success,
150  *  zero if no data to read,
151  *  negative on failure.
152  */
153 int mei_amthif_read(struct mei_device *dev, struct file *file,
154                char __user *ubuf, size_t length, loff_t *offset)
155 {
156         int rets;
157         int wait_ret;
158         struct mei_cl_cb *cb = NULL;
159         struct mei_cl *cl = file->private_data;
160         unsigned long timeout;
161         int i;
162
163         /* Only Posible if we are in timeout */
164         if (!cl || cl != &dev->iamthif_cl) {
165                 dev_dbg(&dev->pdev->dev, "bad file ext.\n");
166                 return -ETIMEDOUT;
167         }
168
169         i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
170
171         if (i < 0) {
172                 dev_dbg(&dev->pdev->dev, "amthif client not found.\n");
173                 return -ENODEV;
174         }
175         dev_dbg(&dev->pdev->dev, "checking amthif data\n");
176         cb = mei_amthif_find_read_list_entry(dev, file);
177
178         /* Check for if we can block or not*/
179         if (cb == NULL && file->f_flags & O_NONBLOCK)
180                 return -EAGAIN;
181
182
183         dev_dbg(&dev->pdev->dev, "waiting for amthif data\n");
184         while (cb == NULL) {
185                 /* unlock the Mutex */
186                 mutex_unlock(&dev->device_lock);
187
188                 wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
189                         (cb = mei_amthif_find_read_list_entry(dev, file)));
190
191                 if (wait_ret)
192                         return -ERESTARTSYS;
193
194                 dev_dbg(&dev->pdev->dev, "woke up from sleep\n");
195
196                 /* Locking again the Mutex */
197                 mutex_lock(&dev->device_lock);
198         }
199
200
201         dev_dbg(&dev->pdev->dev, "Got amthif data\n");
202         dev->iamthif_timer = 0;
203
204         if (cb) {
205                 timeout = cb->read_time +
206                         mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
207                 dev_dbg(&dev->pdev->dev, "amthif timeout = %lud\n",
208                                 timeout);
209
210                 if  (time_after(jiffies, timeout)) {
211                         dev_dbg(&dev->pdev->dev, "amthif Time out\n");
212                         /* 15 sec for the message has expired */
213                         list_del(&cb->list);
214                         rets = -ETIMEDOUT;
215                         goto free;
216                 }
217         }
218         /* if the whole message will fit remove it from the list */
219         if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset))
220                 list_del(&cb->list);
221         else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) {
222                 /* end of the message has been reached */
223                 list_del(&cb->list);
224                 rets = 0;
225                 goto free;
226         }
227                 /* else means that not full buffer will be read and do not
228                  * remove message from deletion list
229                  */
230
231         dev_dbg(&dev->pdev->dev, "amthif cb->response_buffer size - %d\n",
232             cb->response_buffer.size);
233         dev_dbg(&dev->pdev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
234
235         /* length is being turncated to PAGE_SIZE, however,
236          * the buf_idx may point beyond */
237         length = min_t(size_t, length, (cb->buf_idx - *offset));
238
239         if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length))
240                 rets = -EFAULT;
241         else {
242                 rets = length;
243                 if ((*offset + length) < cb->buf_idx) {
244                         *offset += length;
245                         goto out;
246                 }
247         }
248 free:
249         dev_dbg(&dev->pdev->dev, "free amthif cb memory.\n");
250         *offset = 0;
251         mei_io_cb_free(cb);
252 out:
253         return rets;
254 }
255
256 /**
257  * mei_amthif_send_cmd - send amthif command to the ME
258  *
259  * @dev: the device structure
260  * @cb: mei call back struct
261  *
262  * returns 0 on success, <0 on failure.
263  *
264  */
265 static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
266 {
267         struct mei_msg_hdr mei_hdr;
268         int ret;
269
270         if (!dev || !cb)
271                 return -ENODEV;
272
273         dev_dbg(&dev->pdev->dev, "write data to amthif client.\n");
274
275         dev->iamthif_state = MEI_IAMTHIF_WRITING;
276         dev->iamthif_current_cb = cb;
277         dev->iamthif_file_object = cb->file_object;
278         dev->iamthif_canceled = false;
279         dev->iamthif_ioctl = true;
280         dev->iamthif_msg_buf_size = cb->request_buffer.size;
281         memcpy(dev->iamthif_msg_buf, cb->request_buffer.data,
282                cb->request_buffer.size);
283
284         ret = mei_cl_flow_ctrl_creds(&dev->iamthif_cl);
285         if (ret < 0)
286                 return ret;
287
288         if (ret && dev->mei_host_buffer_is_empty) {
289                 ret = 0;
290                 dev->mei_host_buffer_is_empty = false;
291                 if (cb->request_buffer.size > mei_hbuf_max_data(dev)) {
292                         mei_hdr.length = mei_hbuf_max_data(dev);
293                         mei_hdr.msg_complete = 0;
294                 } else {
295                         mei_hdr.length = cb->request_buffer.size;
296                         mei_hdr.msg_complete = 1;
297                 }
298
299                 mei_hdr.host_addr = dev->iamthif_cl.host_client_id;
300                 mei_hdr.me_addr = dev->iamthif_cl.me_client_id;
301                 mei_hdr.reserved = 0;
302                 dev->iamthif_msg_buf_index += mei_hdr.length;
303                 if (mei_write_message(dev, &mei_hdr,
304                                         (unsigned char *)dev->iamthif_msg_buf))
305                         return -ENODEV;
306
307                 if (mei_hdr.msg_complete) {
308                         if (mei_cl_flow_ctrl_reduce(&dev->iamthif_cl))
309                                 return -ENODEV;
310                         dev->iamthif_flow_control_pending = true;
311                         dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
312                         dev_dbg(&dev->pdev->dev, "add amthif cb to write waiting list\n");
313                         dev->iamthif_current_cb = cb;
314                         dev->iamthif_file_object = cb->file_object;
315                         list_add_tail(&cb->list, &dev->write_waiting_list.list);
316                 } else {
317                         dev_dbg(&dev->pdev->dev, "message does not complete, so add amthif cb to write list.\n");
318                         list_add_tail(&cb->list, &dev->write_list.list);
319                 }
320         } else {
321                 if (!(dev->mei_host_buffer_is_empty))
322                         dev_dbg(&dev->pdev->dev, "host buffer is not empty");
323
324                 dev_dbg(&dev->pdev->dev, "No flow control credentials, so add iamthif cb to write list.\n");
325                 list_add_tail(&cb->list, &dev->write_list.list);
326         }
327         return 0;
328 }
329
330 /**
331  * mei_amthif_write - write amthif data to amthif client
332  *
333  * @dev: the device structure
334  * @cb: mei call back struct
335  *
336  * returns 0 on success, <0 on failure.
337  *
338  */
339 int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb)
340 {
341         int ret;
342
343         if (!dev || !cb)
344                 return -ENODEV;
345
346         ret = mei_io_cb_alloc_resp_buf(cb, dev->iamthif_mtu);
347         if (ret)
348                 return ret;
349
350         cb->fop_type = MEI_FOP_IOCTL;
351
352         if (!list_empty(&dev->amthif_cmd_list.list) ||
353             dev->iamthif_state != MEI_IAMTHIF_IDLE) {
354                 dev_dbg(&dev->pdev->dev,
355                         "amthif state = %d\n", dev->iamthif_state);
356                 dev_dbg(&dev->pdev->dev, "AMTHIF: add cb to the wait list\n");
357                 list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
358                 return 0;
359         }
360         return mei_amthif_send_cmd(dev, cb);
361 }
362 /**
363  * mei_amthif_run_next_cmd
364  *
365  * @dev: the device structure
366  *
367  * returns 0 on success, <0 on failure.
368  */
369 void mei_amthif_run_next_cmd(struct mei_device *dev)
370 {
371         struct mei_cl_cb *pos = NULL;
372         struct mei_cl_cb *next = NULL;
373         int status;
374
375         if (!dev)
376                 return;
377
378         dev->iamthif_msg_buf_size = 0;
379         dev->iamthif_msg_buf_index = 0;
380         dev->iamthif_canceled = false;
381         dev->iamthif_ioctl = true;
382         dev->iamthif_state = MEI_IAMTHIF_IDLE;
383         dev->iamthif_timer = 0;
384         dev->iamthif_file_object = NULL;
385
386         dev_dbg(&dev->pdev->dev, "complete amthif cmd_list cb.\n");
387
388         list_for_each_entry_safe(pos, next, &dev->amthif_cmd_list.list, list) {
389                 list_del(&pos->list);
390
391                 if (pos->cl && pos->cl == &dev->iamthif_cl) {
392                         status = mei_amthif_send_cmd(dev, pos);
393                         if (status) {
394                                 dev_dbg(&dev->pdev->dev,
395                                         "amthif write failed status = %d\n",
396                                                 status);
397                                 return;
398                         }
399                         break;
400                 }
401         }
402 }
403
404
405 unsigned int mei_amthif_poll(struct mei_device *dev,
406                 struct file *file, poll_table *wait)
407 {
408         unsigned int mask = 0;
409         mutex_unlock(&dev->device_lock);
410         poll_wait(file, &dev->iamthif_cl.wait, wait);
411         mutex_lock(&dev->device_lock);
412         if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
413                 dev->iamthif_file_object == file) {
414                 mask |= (POLLIN | POLLRDNORM);
415                 dev_dbg(&dev->pdev->dev, "run next amthif cb\n");
416                 mei_amthif_run_next_cmd(dev);
417         }
418         return mask;
419 }
420
421
422
423 /**
424  * mei_amthif_irq_process_completed - processes completed iamthif operation.
425  *
426  * @dev: the device structure.
427  * @slots: free slots.
428  * @cb_pos: callback block.
429  * @cl: private data of the file object.
430  * @cmpl_list: complete list.
431  *
432  * returns 0, OK; otherwise, error.
433  */
434 int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
435                         struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list)
436 {
437         struct mei_msg_hdr mei_hdr;
438         struct mei_cl *cl = cb->cl;
439         size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index;
440         size_t msg_slots = mei_data2slots(len);
441
442         mei_hdr.host_addr = cl->host_client_id;
443         mei_hdr.me_addr = cl->me_client_id;
444         mei_hdr.reserved = 0;
445
446         if (*slots >= msg_slots) {
447                 mei_hdr.length = len;
448                 mei_hdr.msg_complete = 1;
449         /* Split the message only if we can write the whole host buffer */
450         } else if (*slots == dev->hbuf_depth) {
451                 msg_slots = *slots;
452                 len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
453                 mei_hdr.length = len;
454                 mei_hdr.msg_complete = 0;
455         } else {
456                 /* wait for next time the host buffer is empty */
457                 return 0;
458         }
459
460         dev_dbg(&dev->pdev->dev, MEI_HDR_FMT,  MEI_HDR_PRM(&mei_hdr));
461
462         *slots -=  msg_slots;
463         if (mei_write_message(dev, &mei_hdr,
464                 dev->iamthif_msg_buf + dev->iamthif_msg_buf_index)) {
465                         dev->iamthif_state = MEI_IAMTHIF_IDLE;
466                         cl->status = -ENODEV;
467                         list_del(&cb->list);
468                         return -ENODEV;
469         }
470
471         if (mei_cl_flow_ctrl_reduce(cl))
472                 return -ENODEV;
473
474         dev->iamthif_msg_buf_index += mei_hdr.length;
475         cl->status = 0;
476
477         if (mei_hdr.msg_complete) {
478                 dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
479                 dev->iamthif_flow_control_pending = true;
480
481                 /* save iamthif cb sent to amthif client */
482                 cb->buf_idx = dev->iamthif_msg_buf_index;
483                 dev->iamthif_current_cb = cb;
484
485                 list_move_tail(&cb->list, &dev->write_waiting_list.list);
486         }
487
488
489         return 0;
490 }
491
492 /**
493  * mei_amthif_irq_read_message - read routine after ISR to
494  *                      handle the read amthif message
495  *
496  * @complete_list: An instance of our list structure
497  * @dev: the device structure
498  * @mei_hdr: header of amthif message
499  *
500  * returns 0 on success, <0 on failure.
501  */
502 int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list,
503                 struct mei_device *dev, struct mei_msg_hdr *mei_hdr)
504 {
505         struct mei_cl_cb *cb;
506         unsigned char *buffer;
507
508         BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id);
509         BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING);
510
511         buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index;
512         BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length);
513
514         mei_read_slots(dev, buffer, mei_hdr->length);
515
516         dev->iamthif_msg_buf_index += mei_hdr->length;
517
518         if (!mei_hdr->msg_complete)
519                 return 0;
520
521         dev_dbg(&dev->pdev->dev,
522                         "amthif_message_buffer_index =%d\n",
523                         mei_hdr->length);
524
525         dev_dbg(&dev->pdev->dev, "completed amthif read.\n ");
526         if (!dev->iamthif_current_cb)
527                 return -ENODEV;
528
529         cb = dev->iamthif_current_cb;
530         dev->iamthif_current_cb = NULL;
531
532         if (!cb->cl)
533                 return -ENODEV;
534
535         dev->iamthif_stall_timer = 0;
536         cb->buf_idx = dev->iamthif_msg_buf_index;
537         cb->read_time = jiffies;
538         if (dev->iamthif_ioctl && cb->cl == &dev->iamthif_cl) {
539                 /* found the iamthif cb */
540                 dev_dbg(&dev->pdev->dev, "complete the amthif read cb.\n ");
541                 dev_dbg(&dev->pdev->dev, "add the amthif read cb to complete.\n ");
542                 list_add_tail(&cb->list, &complete_list->list);
543         }
544         return 0;
545 }
546
547 /**
548  * mei_amthif_irq_read - prepares to read amthif data.
549  *
550  * @dev: the device structure.
551  * @slots: free slots.
552  *
553  * returns 0, OK; otherwise, error.
554  */
555 int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
556 {
557
558         if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr)
559                         + sizeof(struct hbm_flow_control))) {
560                 return -EMSGSIZE;
561         }
562         *slots -= mei_data2slots(sizeof(struct hbm_flow_control));
563         if (mei_hbm_cl_flow_control_req(dev, &dev->iamthif_cl)) {
564                 dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
565                 return -EIO;
566         }
567
568         dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
569         dev->iamthif_state = MEI_IAMTHIF_READING;
570         dev->iamthif_flow_control_pending = false;
571         dev->iamthif_msg_buf_index = 0;
572         dev->iamthif_msg_buf_size = 0;
573         dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
574         dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev);
575         return 0;
576 }
577
578 /**
579  * mei_amthif_complete - complete amthif callback.
580  *
581  * @dev: the device structure.
582  * @cb_pos: callback block.
583  */
584 void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
585 {
586         if (dev->iamthif_canceled != 1) {
587                 dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
588                 dev->iamthif_stall_timer = 0;
589                 memcpy(cb->response_buffer.data,
590                                 dev->iamthif_msg_buf,
591                                 dev->iamthif_msg_buf_index);
592                 list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
593                 dev_dbg(&dev->pdev->dev, "amthif read completed\n");
594                 dev->iamthif_timer = jiffies;
595                 dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
596                                 dev->iamthif_timer);
597         } else {
598                 mei_amthif_run_next_cmd(dev);
599         }
600
601         dev_dbg(&dev->pdev->dev, "completing amthif call back.\n");
602         wake_up_interruptible(&dev->iamthif_cl.wait);
603 }
604
605 /**
606  * mei_clear_list - removes all callbacks associated with file
607  *              from mei_cb_list
608  *
609  * @dev: device structure.
610  * @file: file structure
611  * @mei_cb_list: callbacks list
612  *
613  * mei_clear_list is called to clear resources associated with file
614  * when application calls close function or Ctrl-C was pressed
615  *
616  * returns true if callback removed from the list, false otherwise
617  */
618 static bool mei_clear_list(struct mei_device *dev,
619                 const struct file *file, struct list_head *mei_cb_list)
620 {
621         struct mei_cl_cb *cb_pos = NULL;
622         struct mei_cl_cb *cb_next = NULL;
623         bool removed = false;
624
625         /* list all list member */
626         list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, list) {
627                 /* check if list member associated with a file */
628                 if (file == cb_pos->file_object) {
629                         /* remove member from the list */
630                         list_del(&cb_pos->list);
631                         /* check if cb equal to current iamthif cb */
632                         if (dev->iamthif_current_cb == cb_pos) {
633                                 dev->iamthif_current_cb = NULL;
634                                 /* send flow control to iamthif client */
635                                 mei_hbm_cl_flow_control_req(dev,
636                                                         &dev->iamthif_cl);
637                         }
638                         /* free all allocated buffers */
639                         mei_io_cb_free(cb_pos);
640                         cb_pos = NULL;
641                         removed = true;
642                 }
643         }
644         return removed;
645 }
646
647 /**
648  * mei_clear_lists - removes all callbacks associated with file
649  *
650  * @dev: device structure
651  * @file: file structure
652  *
653  * mei_clear_lists is called to clear resources associated with file
654  * when application calls close function or Ctrl-C was pressed
655  *
656  * returns true if callback removed from the list, false otherwise
657  */
658 static bool mei_clear_lists(struct mei_device *dev, struct file *file)
659 {
660         bool removed = false;
661
662         /* remove callbacks associated with a file */
663         mei_clear_list(dev, file, &dev->amthif_cmd_list.list);
664         if (mei_clear_list(dev, file, &dev->amthif_rd_complete_list.list))
665                 removed = true;
666
667         mei_clear_list(dev, file, &dev->ctrl_rd_list.list);
668
669         if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list))
670                 removed = true;
671
672         if (mei_clear_list(dev, file, &dev->write_waiting_list.list))
673                 removed = true;
674
675         if (mei_clear_list(dev, file, &dev->write_list.list))
676                 removed = true;
677
678         /* check if iamthif_current_cb not NULL */
679         if (dev->iamthif_current_cb && !removed) {
680                 /* check file and iamthif current cb association */
681                 if (dev->iamthif_current_cb->file_object == file) {
682                         /* remove cb */
683                         mei_io_cb_free(dev->iamthif_current_cb);
684                         dev->iamthif_current_cb = NULL;
685                         removed = true;
686                 }
687         }
688         return removed;
689 }
690
691 /**
692 * mei_amthif_release - the release function
693 *
694 *  @inode: pointer to inode structure
695 *  @file: pointer to file structure
696 *
697 *  returns 0 on success, <0 on error
698 */
699 int mei_amthif_release(struct mei_device *dev, struct file *file)
700 {
701         if (dev->open_handle_count > 0)
702                 dev->open_handle_count--;
703
704         if (dev->iamthif_file_object == file &&
705             dev->iamthif_state != MEI_IAMTHIF_IDLE) {
706
707                 dev_dbg(&dev->pdev->dev, "amthif canceled iamthif state %d\n",
708                     dev->iamthif_state);
709                 dev->iamthif_canceled = true;
710                 if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
711                         dev_dbg(&dev->pdev->dev, "run next amthif iamthif cb\n");
712                         mei_amthif_run_next_cmd(dev);
713                 }
714         }
715
716         if (mei_clear_lists(dev, file))
717                 dev->iamthif_state = MEI_IAMTHIF_IDLE;
718
719         return 0;
720 }