Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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