linux/drivers/staging/mei/init.c
<<
>>
Prefs
   1/*
   2 *
   3 * Intel Management Engine Interface (Intel MEI) Linux driver
   4 * Copyright (c) 2003-2011, 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/pci.h>
  18#include <linux/sched.h>
  19#include <linux/wait.h>
  20#include <linux/delay.h>
  21
  22#include "mei_dev.h"
  23#include "hw.h"
  24#include "interface.h"
  25#include "mei.h"
  26
  27const uuid_le mei_amthi_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
  28                                                0xa8, 0x46, 0xe0, 0xff, 0x65,
  29                                                0x81, 0x4c);
  30
  31/**
  32 * mei_initialize_list - Sets up a queue list.
  33 *
  34 * @list: An instance of our list structure
  35 * @dev: the device structure
  36 */
  37void mei_initialize_list(struct mei_io_list *list, struct mei_device *dev)
  38{
  39        /* initialize our queue list */
  40        INIT_LIST_HEAD(&list->mei_cb.cb_list);
  41        list->status = 0;
  42        list->device_extension = dev;
  43}
  44
  45/**
  46 * mei_flush_queues - flushes queue lists belonging to cl.
  47 *
  48 * @dev: the device structure
  49 * @cl: private data of the file object
  50 */
  51void mei_flush_queues(struct mei_device *dev, struct mei_cl *cl)
  52{
  53        int i;
  54
  55        if (!dev || !cl)
  56                return;
  57
  58        for (i = 0; i < MEI_IO_LISTS_NUMBER; i++) {
  59                dev_dbg(&dev->pdev->dev, "remove list entry belonging to cl\n");
  60                mei_flush_list(dev->io_list_array[i], cl);
  61        }
  62}
  63
  64
  65/**
  66 * mei_flush_list - removes list entry belonging to cl.
  67 *
  68 * @list:  An instance of our list structure
  69 * @cl: private data of the file object
  70 */
  71void mei_flush_list(struct mei_io_list *list, struct mei_cl *cl)
  72{
  73        struct mei_cl *cl_tmp;
  74        struct mei_cl_cb *cb_pos = NULL;
  75        struct mei_cl_cb *cb_next = NULL;
  76
  77        if (!list || !cl)
  78                return;
  79
  80        if (list->status != 0)
  81                return;
  82
  83        if (list_empty(&list->mei_cb.cb_list))
  84                return;
  85
  86        list_for_each_entry_safe(cb_pos, cb_next,
  87                                 &list->mei_cb.cb_list, cb_list) {
  88                if (cb_pos) {
  89                        cl_tmp = (struct mei_cl *)
  90                                cb_pos->file_private;
  91                        if (cl_tmp &&
  92                            mei_fe_same_id(cl, cl_tmp))
  93                                list_del(&cb_pos->cb_list);
  94                }
  95        }
  96}
  97
  98/**
  99 * mei_reset_iamthif_params - initializes mei device iamthif
 100 *
 101 * @dev: the device structure
 102 */
 103static void mei_reset_iamthif_params(struct mei_device *dev)
 104{
 105        /* reset iamthif parameters. */
 106        dev->iamthif_current_cb = NULL;
 107        dev->iamthif_msg_buf_size = 0;
 108        dev->iamthif_msg_buf_index = 0;
 109        dev->iamthif_canceled = 0;
 110        dev->iamthif_ioctl = 0;
 111        dev->iamthif_state = MEI_IAMTHIF_IDLE;
 112        dev->iamthif_timer = 0;
 113}
 114
 115/**
 116 * init_mei_device - allocates and initializes the mei device structure
 117 *
 118 * @pdev: The pci device structure
 119 *
 120 * returns The mei_device_device pointer on success, NULL on failure.
 121 */
 122struct mei_device *init_mei_device(struct pci_dev *pdev)
 123{
 124        int i;
 125        struct mei_device *dev;
 126
 127        dev = kzalloc(sizeof(struct mei_device), GFP_KERNEL);
 128        if (!dev)
 129                return NULL;
 130
 131        /* setup our list array */
 132        dev->io_list_array[0] = &dev->read_list;
 133        dev->io_list_array[1] = &dev->write_list;
 134        dev->io_list_array[2] = &dev->write_waiting_list;
 135        dev->io_list_array[3] = &dev->ctrl_wr_list;
 136        dev->io_list_array[4] = &dev->ctrl_rd_list;
 137        dev->io_list_array[5] = &dev->amthi_cmd_list;
 138        dev->io_list_array[6] = &dev->amthi_read_complete_list;
 139        INIT_LIST_HEAD(&dev->file_list);
 140        INIT_LIST_HEAD(&dev->wd_cl.link);
 141        INIT_LIST_HEAD(&dev->iamthif_cl.link);
 142        mutex_init(&dev->device_lock);
 143        init_waitqueue_head(&dev->wait_recvd_msg);
 144        init_waitqueue_head(&dev->wait_stop_wd);
 145        dev->mei_state = MEI_INITIALIZING;
 146        dev->iamthif_state = MEI_IAMTHIF_IDLE;
 147        for (i = 0; i < MEI_IO_LISTS_NUMBER; i++)
 148                mei_initialize_list(dev->io_list_array[i], dev);
 149        dev->pdev = pdev;
 150        return dev;
 151}
 152
 153/**
 154 * mei_hw_init - initializes host and fw to start work.
 155 *
 156 * @dev: the device structure
 157 *
 158 * returns 0 on success, <0 on failure.
 159 */
 160int mei_hw_init(struct mei_device *dev)
 161{
 162        int err = 0;
 163        int ret;
 164
 165        mutex_lock(&dev->device_lock);
 166
 167        dev->host_hw_state = mei_hcsr_read(dev);
 168        dev->me_hw_state = mei_mecsr_read(dev);
 169        dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, mestate = 0x%08x.\n",
 170            dev->host_hw_state, dev->me_hw_state);
 171
 172        /* acknowledge interrupt and stop interupts */
 173        if ((dev->host_hw_state & H_IS) == H_IS)
 174                mei_reg_write(dev, H_CSR, dev->host_hw_state);
 175
 176        dev->recvd_msg = 0;
 177        dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
 178
 179        mei_reset(dev, 1);
 180
 181        dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
 182            dev->host_hw_state, dev->me_hw_state);
 183
 184        /* wait for ME to turn on ME_RDY */
 185        if (!dev->recvd_msg) {
 186                mutex_unlock(&dev->device_lock);
 187                err = wait_event_interruptible_timeout(dev->wait_recvd_msg,
 188                        dev->recvd_msg, MEI_INTEROP_TIMEOUT);
 189                mutex_lock(&dev->device_lock);
 190        }
 191
 192        if (err <= 0 && !dev->recvd_msg) {
 193                dev->mei_state = MEI_DISABLED;
 194                dev_dbg(&dev->pdev->dev,
 195                        "wait_event_interruptible_timeout failed"
 196                        "on wait for ME to turn on ME_RDY.\n");
 197                ret = -ENODEV;
 198                goto out;
 199        }
 200
 201        if (!(((dev->host_hw_state & H_RDY) == H_RDY) &&
 202              ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) {
 203                dev->mei_state = MEI_DISABLED;
 204                dev_dbg(&dev->pdev->dev,
 205                        "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
 206                        dev->host_hw_state, dev->me_hw_state);
 207
 208                if (!(dev->host_hw_state & H_RDY))
 209                        dev_dbg(&dev->pdev->dev, "host turn off H_RDY.\n");
 210
 211                if (!(dev->me_hw_state & ME_RDY_HRA))
 212                        dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n");
 213
 214                printk(KERN_ERR "mei: link layer initialization failed.\n");
 215                ret = -ENODEV;
 216                goto out;
 217        }
 218
 219        if (dev->version.major_version != HBM_MAJOR_VERSION ||
 220            dev->version.minor_version != HBM_MINOR_VERSION) {
 221                dev_dbg(&dev->pdev->dev, "MEI start failed.\n");
 222                ret = -ENODEV;
 223                goto out;
 224        }
 225
 226        dev->recvd_msg = 0;
 227        dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
 228            dev->host_hw_state, dev->me_hw_state);
 229        dev_dbg(&dev->pdev->dev, "ME turn on ME_RDY and host turn on H_RDY.\n");
 230        dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
 231        dev_dbg(&dev->pdev->dev, "MEI  start success.\n");
 232        ret = 0;
 233
 234out:
 235        mutex_unlock(&dev->device_lock);
 236        return ret;
 237}
 238
 239/**
 240 * mei_hw_reset - resets fw via mei csr register.
 241 *
 242 * @dev: the device structure
 243 * @interrupts_enabled: if interrupt should be enabled after reset.
 244 */
 245static void mei_hw_reset(struct mei_device *dev, int interrupts_enabled)
 246{
 247        dev->host_hw_state |= (H_RST | H_IG);
 248
 249        if (interrupts_enabled)
 250                mei_enable_interrupts(dev);
 251        else
 252                mei_disable_interrupts(dev);
 253}
 254
 255/**
 256 * mei_reset - resets host and fw.
 257 *
 258 * @dev: the device structure
 259 * @interrupts_enabled: if interrupt should be enabled after reset.
 260 */
 261void mei_reset(struct mei_device *dev, int interrupts_enabled)
 262{
 263        struct mei_cl *cl_pos = NULL;
 264        struct mei_cl *cl_next = NULL;
 265        struct mei_cl_cb *cb_pos = NULL;
 266        struct mei_cl_cb *cb_next = NULL;
 267        bool unexpected;
 268
 269        if (dev->mei_state == MEI_RECOVERING_FROM_RESET) {
 270                dev->need_reset = 1;
 271                return;
 272        }
 273
 274        unexpected = (dev->mei_state != MEI_INITIALIZING &&
 275                        dev->mei_state != MEI_DISABLED &&
 276                        dev->mei_state != MEI_POWER_DOWN &&
 277                        dev->mei_state != MEI_POWER_UP);
 278
 279        dev->host_hw_state = mei_hcsr_read(dev);
 280
 281        dev_dbg(&dev->pdev->dev, "before reset host_hw_state = 0x%08x.\n",
 282            dev->host_hw_state);
 283
 284        mei_hw_reset(dev, interrupts_enabled);
 285
 286        dev->host_hw_state &= ~H_RST;
 287        dev->host_hw_state |= H_IG;
 288
 289        mei_hcsr_set(dev);
 290
 291        dev_dbg(&dev->pdev->dev, "currently saved host_hw_state = 0x%08x.\n",
 292            dev->host_hw_state);
 293
 294        dev->need_reset = 0;
 295
 296        if (dev->mei_state != MEI_INITIALIZING) {
 297                if (dev->mei_state != MEI_DISABLED &&
 298                    dev->mei_state != MEI_POWER_DOWN)
 299                        dev->mei_state = MEI_RESETING;
 300
 301                list_for_each_entry_safe(cl_pos,
 302                                cl_next, &dev->file_list, link) {
 303                        cl_pos->state = MEI_FILE_DISCONNECTED;
 304                        cl_pos->mei_flow_ctrl_creds = 0;
 305                        cl_pos->read_cb = NULL;
 306                        cl_pos->timer_count = 0;
 307                }
 308                /* remove entry if already in list */
 309                dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n");
 310                mei_remove_client_from_file_list(dev,
 311                                dev->wd_cl.host_client_id);
 312
 313                mei_remove_client_from_file_list(dev,
 314                                dev->iamthif_cl.host_client_id);
 315
 316                mei_reset_iamthif_params(dev);
 317                dev->wd_due_counter = 0;
 318                dev->extra_write_index = 0;
 319        }
 320
 321        dev->num_mei_me_clients = 0;
 322        dev->rd_msg_hdr = 0;
 323        dev->stop = 0;
 324        dev->wd_pending = 0;
 325
 326        /* update the state of the registers after reset */
 327        dev->host_hw_state = mei_hcsr_read(dev);
 328        dev->me_hw_state = mei_mecsr_read(dev);
 329
 330        dev_dbg(&dev->pdev->dev, "after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
 331            dev->host_hw_state, dev->me_hw_state);
 332
 333        if (unexpected)
 334                dev_warn(&dev->pdev->dev, "unexpected reset.\n");
 335
 336        /* Wake up all readings so they can be interrupted */
 337        list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
 338                if (waitqueue_active(&cl_pos->rx_wait)) {
 339                        dev_dbg(&dev->pdev->dev, "Waking up client!\n");
 340                        wake_up_interruptible(&cl_pos->rx_wait);
 341                }
 342        }
 343        /* remove all waiting requests */
 344        if (dev->write_list.status == 0 &&
 345                !list_empty(&dev->write_list.mei_cb.cb_list)) {
 346                list_for_each_entry_safe(cb_pos, cb_next,
 347                                &dev->write_list.mei_cb.cb_list, cb_list) {
 348                        if (cb_pos) {
 349                                list_del(&cb_pos->cb_list);
 350                                mei_free_cb_private(cb_pos);
 351                                cb_pos = NULL;
 352                        }
 353                }
 354        }
 355}
 356
 357
 358
 359/**
 360 * host_start_message - mei host sends start message.
 361 *
 362 * @dev: the device structure
 363 *
 364 * returns none.
 365 */
 366void host_start_message(struct mei_device *dev)
 367{
 368        struct mei_msg_hdr *mei_hdr;
 369        struct hbm_host_version_request *host_start_req;
 370
 371        /* host start message */
 372        mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
 373        mei_hdr->host_addr = 0;
 374        mei_hdr->me_addr = 0;
 375        mei_hdr->length = sizeof(struct hbm_host_version_request);
 376        mei_hdr->msg_complete = 1;
 377        mei_hdr->reserved = 0;
 378
 379        host_start_req =
 380            (struct hbm_host_version_request *) &dev->wr_msg_buf[1];
 381        memset(host_start_req, 0, sizeof(struct hbm_host_version_request));
 382        host_start_req->cmd.cmd = HOST_START_REQ_CMD;
 383        host_start_req->host_version.major_version = HBM_MAJOR_VERSION;
 384        host_start_req->host_version.minor_version = HBM_MINOR_VERSION;
 385        dev->recvd_msg = 0;
 386        if (!mei_write_message(dev, mei_hdr,
 387                                       (unsigned char *) (host_start_req),
 388                                       mei_hdr->length)) {
 389                dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
 390                dev->mei_state = MEI_RESETING;
 391                mei_reset(dev, 1);
 392        }
 393        dev->init_clients_state = MEI_START_MESSAGE;
 394        dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
 395        return ;
 396}
 397
 398/**
 399 * host_enum_clients_message - host sends enumeration client request message.
 400 *
 401 * @dev: the device structure
 402 *
 403 * returns none.
 404 */
 405void host_enum_clients_message(struct mei_device *dev)
 406{
 407        struct mei_msg_hdr *mei_hdr;
 408        struct hbm_host_enum_request *host_enum_req;
 409        mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
 410        /* enumerate clients */
 411        mei_hdr->host_addr = 0;
 412        mei_hdr->me_addr = 0;
 413        mei_hdr->length = sizeof(struct hbm_host_enum_request);
 414        mei_hdr->msg_complete = 1;
 415        mei_hdr->reserved = 0;
 416
 417        host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1];
 418        memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request));
 419        host_enum_req->cmd.cmd = HOST_ENUM_REQ_CMD;
 420        if (!mei_write_message(dev, mei_hdr,
 421                               (unsigned char *) (host_enum_req),
 422                                mei_hdr->length)) {
 423                dev->mei_state = MEI_RESETING;
 424                dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
 425                mei_reset(dev, 1);
 426        }
 427        dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
 428        dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
 429        return ;
 430}
 431
 432
 433/**
 434 * allocate_me_clients_storage - allocates storage for me clients
 435 *
 436 * @dev: the device structure
 437 *
 438 * returns none.
 439 */
 440void allocate_me_clients_storage(struct mei_device *dev)
 441{
 442        struct mei_me_client *clients;
 443        int b;
 444
 445        /* count how many ME clients we have */
 446        for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
 447                dev->num_mei_me_clients++;
 448
 449        if (dev->num_mei_me_clients <= 0)
 450                return ;
 451
 452
 453        if (dev->me_clients != NULL) {
 454                kfree(dev->me_clients);
 455                dev->me_clients = NULL;
 456        }
 457        dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n",
 458                dev->num_mei_me_clients * sizeof(struct mei_me_client));
 459        /* allocate storage for ME clients representation */
 460        clients = kcalloc(dev->num_mei_me_clients,
 461                        sizeof(struct mei_me_client), GFP_KERNEL);
 462        if (!clients) {
 463                dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
 464                dev->mei_state = MEI_RESETING;
 465                mei_reset(dev, 1);
 466                return ;
 467        }
 468        dev->me_clients = clients;
 469        return ;
 470}
 471/**
 472 * host_client_properties - reads properties for client
 473 *
 474 * @dev: the device structure
 475 *
 476 * returns none.
 477 */
 478void host_client_properties(struct mei_device *dev)
 479{
 480        struct mei_msg_hdr *mei_header;
 481        struct hbm_props_request *host_cli_req;
 482        int b;
 483        u8 client_num = dev->me_client_presentation_num;
 484
 485        b = dev->me_client_index;
 486        b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b);
 487        if (b < MEI_CLIENTS_MAX) {
 488                dev->me_clients[client_num].client_id = b;
 489                dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
 490                mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
 491                mei_header->host_addr = 0;
 492                mei_header->me_addr = 0;
 493                mei_header->length = sizeof(struct hbm_props_request);
 494                mei_header->msg_complete = 1;
 495                mei_header->reserved = 0;
 496
 497                host_cli_req = (struct hbm_props_request *)&dev->wr_msg_buf[1];
 498
 499                memset(host_cli_req, 0, sizeof(struct hbm_props_request));
 500
 501                host_cli_req->cmd.cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
 502                host_cli_req->address = b;
 503
 504                if (!mei_write_message(dev, mei_header,
 505                                (unsigned char *)host_cli_req,
 506                                mei_header->length)) {
 507                        dev->mei_state = MEI_RESETING;
 508                        dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
 509                        mei_reset(dev, 1);
 510                        return;
 511                }
 512
 513                dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
 514                dev->me_client_index = b;
 515                return;
 516        }
 517
 518
 519        /*
 520         * Clear Map for indicating now ME clients
 521         * with associated host client
 522         */
 523        bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
 524        dev->write_hang = -1;
 525        dev->open_handle_count = 0;
 526        bitmap_set(dev->host_clients_map, 0, 3);
 527        dev->mei_state = MEI_ENABLED;
 528
 529        mei_wd_host_init(dev);
 530        return;
 531}
 532
 533/**
 534 * mei_init_file_private - initializes private file structure.
 535 *
 536 * @priv: private file structure to be initialized
 537 * @file: the file structure
 538 */
 539void mei_init_file_private(struct mei_cl *priv, struct mei_device *dev)
 540{
 541        memset(priv, 0, sizeof(struct mei_cl));
 542        init_waitqueue_head(&priv->wait);
 543        init_waitqueue_head(&priv->rx_wait);
 544        init_waitqueue_head(&priv->tx_wait);
 545        INIT_LIST_HEAD(&priv->link);
 546        priv->reading_state = MEI_IDLE;
 547        priv->writing_state = MEI_IDLE;
 548        priv->dev = dev;
 549}
 550
 551int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid)
 552{
 553        int i, res = -1;
 554
 555        for (i = 0; i < dev->num_mei_me_clients; ++i)
 556                if (uuid_le_cmp(cuuid,
 557                                dev->me_clients[i].props.protocol_name) == 0) {
 558                        res = i;
 559                        break;
 560                }
 561
 562        return res;
 563}
 564
 565
 566/**
 567 * mei_find_me_client_update_filext - searches for ME client guid
 568 *                       sets client_id in mei_file_private if found
 569 * @dev: the device structure
 570 * @priv: private file structure to set client_id in
 571 * @cguid: searched guid of ME client
 572 * @client_id: id of host client to be set in file private structure
 573 *
 574 * returns ME client index
 575 */
 576u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv,
 577                                const uuid_le *cguid, u8 client_id)
 578{
 579        int i;
 580
 581        if (!dev || !priv || !cguid)
 582                return 0;
 583
 584        /* check for valid client id */
 585        i = mei_find_me_client_index(dev, *cguid);
 586        if (i >= 0) {
 587                priv->me_client_id = dev->me_clients[i].client_id;
 588                priv->state = MEI_FILE_CONNECTING;
 589                priv->host_client_id = client_id;
 590
 591                list_add_tail(&priv->link, &dev->file_list);
 592                return (u8)i;
 593        }
 594
 595        return 0;
 596}
 597
 598/**
 599 * host_init_iamthif - mei initialization iamthif client.
 600 *
 601 * @dev: the device structure
 602 *
 603 */
 604void host_init_iamthif(struct mei_device *dev)
 605{
 606        u8 i;
 607        unsigned char *msg_buf;
 608
 609        mei_init_file_private(&dev->iamthif_cl, dev);
 610        dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
 611
 612        /* find ME amthi client */
 613        i = mei_find_me_client_update_filext(dev, &dev->iamthif_cl,
 614                            &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID);
 615        if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) {
 616                dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n");
 617                return;
 618        }
 619
 620        /* Do not render the system unusable when iamthif_mtu is not equal to
 621        the value received from ME.
 622        Assign iamthif_mtu to the value received from ME in order to solve the
 623        hardware macro incompatibility. */
 624
 625        dev_dbg(&dev->pdev->dev, "[DEFAULT] IAMTHIF = %d\n", dev->iamthif_mtu);
 626        dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length;
 627        dev_dbg(&dev->pdev->dev,
 628                        "IAMTHIF = %d\n",
 629                        dev->me_clients[i].props.max_msg_length);
 630
 631        kfree(dev->iamthif_msg_buf);
 632        dev->iamthif_msg_buf = NULL;
 633
 634        /* allocate storage for ME message buffer */
 635        msg_buf = kcalloc(dev->iamthif_mtu,
 636                        sizeof(unsigned char), GFP_KERNEL);
 637        if (!msg_buf) {
 638                dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n");
 639                return;
 640        }
 641
 642        dev->iamthif_msg_buf = msg_buf;
 643
 644        if (!mei_connect(dev, &dev->iamthif_cl)) {
 645                dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n");
 646                dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
 647                dev->iamthif_cl.host_client_id = 0;
 648        } else {
 649                dev->iamthif_cl.timer_count = CONNECT_TIMEOUT;
 650        }
 651}
 652
 653/**
 654 * mei_alloc_file_private - allocates a private file structure and sets it up.
 655 * @file: the file structure
 656 *
 657 * returns  The allocated file or NULL on failure
 658 */
 659struct mei_cl *mei_alloc_file_private(struct mei_device *dev)
 660{
 661        struct mei_cl *priv;
 662
 663        priv = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
 664        if (!priv)
 665                return NULL;
 666
 667        mei_init_file_private(priv, dev);
 668
 669        return priv;
 670}
 671
 672
 673
 674/**
 675 * mei_disconnect_host_client - sends disconnect message to fw from host client.
 676 *
 677 * @dev: the device structure
 678 * @cl: private data of the file object
 679 *
 680 * Locking: called under "dev->device_lock" lock
 681 *
 682 * returns 0 on success, <0 on failure.
 683 */
 684int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl)
 685{
 686        int rets, err;
 687        long timeout = 15;      /* 15 seconds */
 688        struct mei_cl_cb *cb;
 689
 690        if (!dev || !cl)
 691                return -ENODEV;
 692
 693        if (cl->state != MEI_FILE_DISCONNECTING)
 694                return 0;
 695
 696        cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
 697        if (!cb)
 698                return -ENOMEM;
 699
 700        INIT_LIST_HEAD(&cb->cb_list);
 701        cb->file_private = cl;
 702        cb->major_file_operations = MEI_CLOSE;
 703        if (dev->mei_host_buffer_is_empty) {
 704                dev->mei_host_buffer_is_empty = 0;
 705                if (mei_disconnect(dev, cl)) {
 706                        mdelay(10); /* Wait for hardware disconnection ready */
 707                        list_add_tail(&cb->cb_list,
 708                                &dev->ctrl_rd_list.mei_cb.cb_list);
 709                } else {
 710                        rets = -ENODEV;
 711                        dev_dbg(&dev->pdev->dev, "failed to call mei_disconnect.\n");
 712                        goto free;
 713                }
 714        } else {
 715                dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
 716                list_add_tail(&cb->cb_list,
 717                                &dev->ctrl_wr_list.mei_cb.cb_list);
 718        }
 719        mutex_unlock(&dev->device_lock);
 720
 721        err = wait_event_timeout(dev->wait_recvd_msg,
 722                 (MEI_FILE_DISCONNECTED == cl->state),
 723                 timeout * HZ);
 724
 725        mutex_lock(&dev->device_lock);
 726        if (MEI_FILE_DISCONNECTED == cl->state) {
 727                rets = 0;
 728                dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n");
 729        } else {
 730                rets = -ENODEV;
 731                if (MEI_FILE_DISCONNECTED != cl->state)
 732                        dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n");
 733
 734                if (err)
 735                        dev_dbg(&dev->pdev->dev,
 736                                        "wait failed disconnect err=%08x\n",
 737                                        err);
 738
 739                dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
 740        }
 741
 742        mei_flush_list(&dev->ctrl_rd_list, cl);
 743        mei_flush_list(&dev->ctrl_wr_list, cl);
 744free:
 745        mei_free_cb_private(cb);
 746        return rets;
 747}
 748
 749/**
 750 * mei_remove_client_from_file_list -
 751 *      removes file private data from device file list
 752 *
 753 * @dev: the device structure
 754 * @host_client_id: host client id to be removed
 755 */
 756void mei_remove_client_from_file_list(struct mei_device *dev,
 757                                       u8 host_client_id)
 758{
 759        struct mei_cl *cl_pos = NULL;
 760        struct mei_cl *cl_next = NULL;
 761        list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
 762                if (host_client_id == cl_pos->host_client_id) {
 763                        dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n",
 764                                        cl_pos->host_client_id,
 765                                        cl_pos->me_client_id);
 766                        list_del_init(&cl_pos->link);
 767                        break;
 768                }
 769        }
 770}
 771