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