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/ioctl.h>
  23#include <linux/cdev.h>
  24#include <linux/list.h>
  25#include <linux/delay.h>
  26#include <linux/sched.h>
  27#include <linux/uuid.h>
  28#include <linux/jiffies.h>
  29#include <linux/uaccess.h>
  30#include <linux/slab.h>
  31
  32#include <linux/mei.h>
  33
  34#include "mei_dev.h"
  35#include "hbm.h"
  36#include "client.h"
  37
  38const uuid_le mei_amthif_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
  39                                         0xac, 0xa8, 0x46, 0xe0,
  40                                         0xff, 0x65, 0x81, 0x4c);
  41
  42/**
  43 * mei_amthif_reset_params - initializes mei device iamthif
  44 *
  45 * @dev: the device structure
  46 */
  47void mei_amthif_reset_params(struct mei_device *dev)
  48{
  49        /* reset iamthif parameters. */
  50        dev->iamthif_current_cb = NULL;
  51        dev->iamthif_canceled = false;
  52        dev->iamthif_state = MEI_IAMTHIF_IDLE;
  53        dev->iamthif_timer = 0;
  54        dev->iamthif_stall_timer = 0;
  55        dev->iamthif_open_count = 0;
  56}
  57
  58/**
  59 * mei_amthif_host_init - mei initialization amthif client.
  60 *
  61 * @dev: the device structure
  62 * @me_cl: me client
  63 *
  64 * Return: 0 on success, <0 on failure.
  65 */
  66int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
  67{
  68        struct mei_cl *cl = &dev->iamthif_cl;
  69        int ret;
  70
  71        dev->iamthif_state = MEI_IAMTHIF_IDLE;
  72
  73        mei_cl_init(cl, dev);
  74
  75        ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
  76        if (ret < 0) {
  77                dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
  78                return ret;
  79        }
  80
  81        ret = mei_cl_connect(cl, me_cl, NULL);
  82
  83        dev->iamthif_state = MEI_IAMTHIF_IDLE;
  84
  85        return ret;
  86}
  87
  88/**
  89 * mei_amthif_find_read_list_entry - finds a amthilist entry for current file
  90 *
  91 * @dev: the device structure
  92 * @file: pointer to file object
  93 *
  94 * Return:   returned a list entry on success, NULL on failure.
  95 */
  96struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
  97                                                struct file *file)
  98{
  99        struct mei_cl_cb *cb;
 100
 101        list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list)
 102                if (cb->file_object == file)
 103                        return cb;
 104        return NULL;
 105}
 106
 107
 108/**
 109 * mei_amthif_read - read data from AMTHIF client
 110 *
 111 * @dev: the device structure
 112 * @file: pointer to file object
 113 * @ubuf: pointer to user data in user space
 114 * @length: data length to read
 115 * @offset: data read offset
 116 *
 117 * Locking: called under "dev->device_lock" lock
 118 *
 119 * Return:
 120 *  returned data length on success,
 121 *  zero if no data to read,
 122 *  negative on failure.
 123 */
 124int mei_amthif_read(struct mei_device *dev, struct file *file,
 125               char __user *ubuf, size_t length, loff_t *offset)
 126{
 127        struct mei_cl *cl = file->private_data;
 128        struct mei_cl_cb *cb;
 129        unsigned long timeout;
 130        int rets;
 131        int wait_ret;
 132
 133        /* Only possible if we are in timeout */
 134        if (!cl) {
 135                dev_err(dev->dev, "bad file ext.\n");
 136                return -ETIME;
 137        }
 138
 139        dev_dbg(dev->dev, "checking amthif data\n");
 140        cb = mei_amthif_find_read_list_entry(dev, file);
 141
 142        /* Check for if we can block or not*/
 143        if (cb == NULL && file->f_flags & O_NONBLOCK)
 144                return -EAGAIN;
 145
 146
 147        dev_dbg(dev->dev, "waiting for amthif data\n");
 148        while (cb == NULL) {
 149                /* unlock the Mutex */
 150                mutex_unlock(&dev->device_lock);
 151
 152                wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
 153                        (cb = mei_amthif_find_read_list_entry(dev, file)));
 154
 155                /* Locking again the Mutex */
 156                mutex_lock(&dev->device_lock);
 157
 158                if (wait_ret)
 159                        return -ERESTARTSYS;
 160
 161                dev_dbg(dev->dev, "woke up from sleep\n");
 162        }
 163
 164        if (cb->status) {
 165                rets = cb->status;
 166                dev_dbg(dev->dev, "read operation failed %d\n", rets);
 167                goto free;
 168        }
 169
 170        dev_dbg(dev->dev, "Got amthif data\n");
 171        dev->iamthif_timer = 0;
 172
 173        timeout = cb->read_time +
 174                mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
 175        dev_dbg(dev->dev, "amthif timeout = %lud\n",
 176                        timeout);
 177
 178        if  (time_after(jiffies, timeout)) {
 179                dev_dbg(dev->dev, "amthif Time out\n");
 180                /* 15 sec for the message has expired */
 181                list_del_init(&cb->list);
 182                rets = -ETIME;
 183                goto free;
 184        }
 185        /* if the whole message will fit remove it from the list */
 186        if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset))
 187                list_del_init(&cb->list);
 188        else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) {
 189                /* end of the message has been reached */
 190                list_del_init(&cb->list);
 191                rets = 0;
 192                goto free;
 193        }
 194                /* else means that not full buffer will be read and do not
 195                 * remove message from deletion list
 196                 */
 197
 198        dev_dbg(dev->dev, "amthif cb->buf size - %d\n",
 199            cb->buf.size);
 200        dev_dbg(dev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
 201
 202        /* length is being truncated to PAGE_SIZE, however,
 203         * the buf_idx may point beyond */
 204        length = min_t(size_t, length, (cb->buf_idx - *offset));
 205
 206        if (copy_to_user(ubuf, cb->buf.data + *offset, length)) {
 207                dev_dbg(dev->dev, "failed to copy data to userland\n");
 208                rets = -EFAULT;
 209        } else {
 210                rets = length;
 211                if ((*offset + length) < cb->buf_idx) {
 212                        *offset += length;
 213                        goto out;
 214                }
 215        }
 216free:
 217        dev_dbg(dev->dev, "free amthif cb memory.\n");
 218        *offset = 0;
 219        mei_io_cb_free(cb);
 220out:
 221        return rets;
 222}
 223
 224/**
 225 * mei_amthif_read_start - queue message for sending read credential
 226 *
 227 * @cl: host client
 228 * @file: file pointer of message recipient
 229 *
 230 * Return: 0 on success, <0 on failure.
 231 */
 232static int mei_amthif_read_start(struct mei_cl *cl, struct file *file)
 233{
 234        struct mei_device *dev = cl->dev;
 235        struct mei_cl_cb *cb;
 236        int rets;
 237
 238        cb = mei_io_cb_init(cl, MEI_FOP_READ, file);
 239        if (!cb) {
 240                rets = -ENOMEM;
 241                goto err;
 242        }
 243
 244        rets = mei_io_cb_alloc_buf(cb, mei_cl_mtu(cl));
 245        if (rets)
 246                goto err;
 247
 248        list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
 249
 250        dev->iamthif_state = MEI_IAMTHIF_READING;
 251        dev->iamthif_file_object = cb->file_object;
 252        dev->iamthif_current_cb = cb;
 253
 254        return 0;
 255err:
 256        mei_io_cb_free(cb);
 257        return rets;
 258}
 259
 260/**
 261 * mei_amthif_send_cmd - send amthif command to the ME
 262 *
 263 * @cl: the host client
 264 * @cb: mei call back struct
 265 *
 266 * Return: 0 on success, <0 on failure.
 267 */
 268static int mei_amthif_send_cmd(struct mei_cl *cl, struct mei_cl_cb *cb)
 269{
 270        struct mei_device *dev;
 271        int ret;
 272
 273        if (!cl->dev || !cb)
 274                return -ENODEV;
 275
 276        dev = cl->dev;
 277
 278        dev->iamthif_state = MEI_IAMTHIF_WRITING;
 279        dev->iamthif_current_cb = cb;
 280        dev->iamthif_file_object = cb->file_object;
 281        dev->iamthif_canceled = false;
 282
 283        ret = mei_cl_write(cl, cb, false);
 284        if (ret < 0)
 285                return ret;
 286
 287        if (cb->completed)
 288                cb->status = mei_amthif_read_start(cl, cb->file_object);
 289
 290        return 0;
 291}
 292
 293/**
 294 * mei_amthif_run_next_cmd - send next amt command from queue
 295 *
 296 * @dev: the device structure
 297 *
 298 * Return: 0 on success, <0 on failure.
 299 */
 300int mei_amthif_run_next_cmd(struct mei_device *dev)
 301{
 302        struct mei_cl *cl = &dev->iamthif_cl;
 303        struct mei_cl_cb *cb;
 304
 305        dev->iamthif_canceled = false;
 306        dev->iamthif_state = MEI_IAMTHIF_IDLE;
 307        dev->iamthif_timer = 0;
 308        dev->iamthif_file_object = NULL;
 309
 310        dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
 311
 312        cb = list_first_entry_or_null(&dev->amthif_cmd_list.list,
 313                                        typeof(*cb), list);
 314        if (!cb)
 315                return 0;
 316
 317        list_del_init(&cb->list);
 318        return mei_amthif_send_cmd(cl, cb);
 319}
 320
 321/**
 322 * mei_amthif_write - write amthif data to amthif client
 323 *
 324 * @cl: host client
 325 * @cb: mei call back struct
 326 *
 327 * Return: 0 on success, <0 on failure.
 328 */
 329int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
 330{
 331
 332        struct mei_device *dev;
 333
 334        if (WARN_ON(!cl || !cl->dev))
 335                return -ENODEV;
 336
 337        if (WARN_ON(!cb))
 338                return -EINVAL;
 339
 340        dev = cl->dev;
 341
 342        list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
 343        return mei_amthif_run_next_cmd(dev);
 344}
 345
 346/**
 347 * mei_amthif_poll - the amthif poll function
 348 *
 349 * @dev: the device structure
 350 * @file: pointer to file structure
 351 * @wait: pointer to poll_table structure
 352 *
 353 * Return: poll mask
 354 *
 355 * Locking: called under "dev->device_lock" lock
 356 */
 357
 358unsigned int mei_amthif_poll(struct mei_device *dev,
 359                struct file *file, poll_table *wait)
 360{
 361        unsigned int mask = 0;
 362
 363        poll_wait(file, &dev->iamthif_cl.wait, wait);
 364
 365        if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
 366            dev->iamthif_file_object == file) {
 367
 368                mask |= POLLIN | POLLRDNORM;
 369                mei_amthif_run_next_cmd(dev);
 370        }
 371
 372        return mask;
 373}
 374
 375
 376
 377/**
 378 * mei_amthif_irq_write - write iamthif command in irq thread context.
 379 *
 380 * @cl: private data of the file object.
 381 * @cb: callback block.
 382 * @cmpl_list: complete list.
 383 *
 384 * Return: 0, OK; otherwise, error.
 385 */
 386int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
 387                         struct mei_cl_cb *cmpl_list)
 388{
 389        int ret;
 390
 391        ret = mei_cl_irq_write(cl, cb, cmpl_list);
 392        if (ret)
 393                return ret;
 394
 395        if (cb->completed)
 396                cb->status = mei_amthif_read_start(cl, cb->file_object);
 397
 398        return 0;
 399}
 400
 401/**
 402 * mei_amthif_irq_read_msg - read routine after ISR to
 403 *                      handle the read amthif message
 404 *
 405 * @cl: mei client
 406 * @mei_hdr: header of amthif message
 407 * @cmpl_list: completed callbacks list
 408 *
 409 * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status
 410 */
 411int mei_amthif_irq_read_msg(struct mei_cl *cl,
 412                            struct mei_msg_hdr *mei_hdr,
 413                            struct mei_cl_cb *cmpl_list)
 414{
 415        struct mei_device *dev;
 416        int ret;
 417
 418        dev = cl->dev;
 419
 420        if (dev->iamthif_state != MEI_IAMTHIF_READING)
 421                return 0;
 422
 423        ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
 424        if (ret)
 425                return ret;
 426
 427        if (!mei_hdr->msg_complete)
 428                return 0;
 429
 430        dev_dbg(dev->dev, "completed amthif read.\n ");
 431        dev->iamthif_current_cb = NULL;
 432        dev->iamthif_stall_timer = 0;
 433
 434        return 0;
 435}
 436
 437/**
 438 * mei_amthif_complete - complete amthif callback.
 439 *
 440 * @dev: the device structure.
 441 * @cb: callback block.
 442 */
 443void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
 444{
 445
 446        if (cb->fop_type == MEI_FOP_WRITE) {
 447                if (!cb->status) {
 448                        dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
 449                        mei_io_cb_free(cb);
 450                        return;
 451                }
 452                /*
 453                 * in case of error enqueue the write cb to complete read list
 454                 * so it can be propagated to the reader
 455                 */
 456                list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
 457                wake_up_interruptible(&dev->iamthif_cl.wait);
 458                return;
 459        }
 460
 461        if (dev->iamthif_canceled != 1) {
 462                dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
 463                dev->iamthif_stall_timer = 0;
 464                list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
 465                dev_dbg(dev->dev, "amthif read completed\n");
 466                dev->iamthif_timer = jiffies;
 467                dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n",
 468                        dev->iamthif_timer);
 469        } else {
 470                mei_amthif_run_next_cmd(dev);
 471        }
 472
 473        dev_dbg(dev->dev, "completing amthif call back.\n");
 474        wake_up_interruptible(&dev->iamthif_cl.wait);
 475}
 476
 477/**
 478 * mei_clear_list - removes all callbacks associated with file
 479 *              from mei_cb_list
 480 *
 481 * @dev: device structure.
 482 * @file: file structure
 483 * @mei_cb_list: callbacks list
 484 *
 485 * mei_clear_list is called to clear resources associated with file
 486 * when application calls close function or Ctrl-C was pressed
 487 *
 488 * Return: true if callback removed from the list, false otherwise
 489 */
 490static bool mei_clear_list(struct mei_device *dev,
 491                const struct file *file, struct list_head *mei_cb_list)
 492{
 493        struct mei_cl *cl = &dev->iamthif_cl;
 494        struct mei_cl_cb *cb, *next;
 495        bool removed = false;
 496
 497        /* list all list member */
 498        list_for_each_entry_safe(cb, next, mei_cb_list, list) {
 499                /* check if list member associated with a file */
 500                if (file == cb->file_object) {
 501                        /* check if cb equal to current iamthif cb */
 502                        if (dev->iamthif_current_cb == cb) {
 503                                dev->iamthif_current_cb = NULL;
 504                                /* send flow control to iamthif client */
 505                                mei_hbm_cl_flow_control_req(dev, cl);
 506                        }
 507                        /* free all allocated buffers */
 508                        mei_io_cb_free(cb);
 509                        removed = true;
 510                }
 511        }
 512        return removed;
 513}
 514
 515/**
 516 * mei_clear_lists - removes all callbacks associated with file
 517 *
 518 * @dev: device structure
 519 * @file: file structure
 520 *
 521 * mei_clear_lists is called to clear resources associated with file
 522 * when application calls close function or Ctrl-C was pressed
 523 *
 524 * Return: true if callback removed from the list, false otherwise
 525 */
 526static bool mei_clear_lists(struct mei_device *dev, struct file *file)
 527{
 528        bool removed = false;
 529
 530        /* remove callbacks associated with a file */
 531        mei_clear_list(dev, file, &dev->amthif_cmd_list.list);
 532        if (mei_clear_list(dev, file, &dev->amthif_rd_complete_list.list))
 533                removed = true;
 534
 535        mei_clear_list(dev, file, &dev->ctrl_rd_list.list);
 536
 537        if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list))
 538                removed = true;
 539
 540        if (mei_clear_list(dev, file, &dev->write_waiting_list.list))
 541                removed = true;
 542
 543        if (mei_clear_list(dev, file, &dev->write_list.list))
 544                removed = true;
 545
 546        /* check if iamthif_current_cb not NULL */
 547        if (dev->iamthif_current_cb && !removed) {
 548                /* check file and iamthif current cb association */
 549                if (dev->iamthif_current_cb->file_object == file) {
 550                        /* remove cb */
 551                        mei_io_cb_free(dev->iamthif_current_cb);
 552                        dev->iamthif_current_cb = NULL;
 553                        removed = true;
 554                }
 555        }
 556        return removed;
 557}
 558
 559/**
 560* mei_amthif_release - the release function
 561*
 562*  @dev: device structure
 563*  @file: pointer to file structure
 564*
 565*  Return: 0 on success, <0 on error
 566*/
 567int mei_amthif_release(struct mei_device *dev, struct file *file)
 568{
 569        if (dev->iamthif_open_count > 0)
 570                dev->iamthif_open_count--;
 571
 572        if (dev->iamthif_file_object == file &&
 573            dev->iamthif_state != MEI_IAMTHIF_IDLE) {
 574
 575                dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
 576                    dev->iamthif_state);
 577                dev->iamthif_canceled = true;
 578                if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
 579                        dev_dbg(dev->dev, "run next amthif iamthif cb\n");
 580                        mei_amthif_run_next_cmd(dev);
 581                }
 582        }
 583
 584        if (mei_clear_lists(dev, file))
 585                dev->iamthif_state = MEI_IAMTHIF_IDLE;
 586
 587        return 0;
 588}
 589