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