linux/drivers/misc/mei/hbm.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/pci.h>
  18#include <linux/sched.h>
  19#include <linux/wait.h>
  20#include <linux/mei.h>
  21
  22#include "mei_dev.h"
  23#include "hbm.h"
  24#include "hw-me.h"
  25
  26/**
  27 * mei_hbm_me_cl_allocate - allocates storage for me clients
  28 *
  29 * @dev: the device structure
  30 *
  31 * returns none.
  32 */
  33static void mei_hbm_me_cl_allocate(struct mei_device *dev)
  34{
  35        struct mei_me_client *clients;
  36        int b;
  37
  38        /* count how many ME clients we have */
  39        for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
  40                dev->me_clients_num++;
  41
  42        if (dev->me_clients_num <= 0)
  43                return;
  44
  45        kfree(dev->me_clients);
  46        dev->me_clients = NULL;
  47
  48        dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n",
  49                dev->me_clients_num * sizeof(struct mei_me_client));
  50        /* allocate storage for ME clients representation */
  51        clients = kcalloc(dev->me_clients_num,
  52                        sizeof(struct mei_me_client), GFP_KERNEL);
  53        if (!clients) {
  54                dev_err(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
  55                dev->dev_state = MEI_DEV_RESETTING;
  56                mei_reset(dev, 1);
  57                return;
  58        }
  59        dev->me_clients = clients;
  60        return;
  61}
  62
  63/**
  64 * mei_hbm_cl_hdr - construct client hbm header
  65 *
  66 * @cl: - client
  67 * @hbm_cmd: host bus message command
  68 * @buf: buffer for cl header
  69 * @len: buffer length
  70 */
  71static inline
  72void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
  73{
  74        struct mei_hbm_cl_cmd *cmd = buf;
  75
  76        memset(cmd, 0, len);
  77
  78        cmd->hbm_cmd = hbm_cmd;
  79        cmd->host_addr = cl->host_client_id;
  80        cmd->me_addr = cl->me_client_id;
  81}
  82
  83/**
  84 * same_disconn_addr - tells if they have the same address
  85 *
  86 * @file: private data of the file object.
  87 * @disconn: disconnection request.
  88 *
  89 * returns true if addres are same
  90 */
  91static inline
  92bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf)
  93{
  94        struct mei_hbm_cl_cmd *cmd = buf;
  95        return cl->host_client_id == cmd->host_addr &&
  96                cl->me_client_id == cmd->me_addr;
  97}
  98
  99
 100/**
 101 * is_treat_specially_client - checks if the message belongs
 102 * to the file private data.
 103 *
 104 * @cl: private data of the file object
 105 * @rs: connect response bus message
 106 *
 107 */
 108static bool is_treat_specially_client(struct mei_cl *cl,
 109                struct hbm_client_connect_response *rs)
 110{
 111        if (mei_hbm_cl_addr_equal(cl, rs)) {
 112                if (!rs->status) {
 113                        cl->state = MEI_FILE_CONNECTED;
 114                        cl->status = 0;
 115
 116                } else {
 117                        cl->state = MEI_FILE_DISCONNECTED;
 118                        cl->status = -ENODEV;
 119                }
 120                cl->timer_count = 0;
 121
 122                return true;
 123        }
 124        return false;
 125}
 126
 127int mei_hbm_start_wait(struct mei_device *dev)
 128{
 129        int ret;
 130        if (dev->hbm_state > MEI_HBM_START)
 131                return 0;
 132
 133        mutex_unlock(&dev->device_lock);
 134        ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
 135                        dev->hbm_state == MEI_HBM_IDLE ||
 136                        dev->hbm_state > MEI_HBM_START,
 137                        mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
 138        mutex_lock(&dev->device_lock);
 139
 140        if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
 141                dev->hbm_state = MEI_HBM_IDLE;
 142                dev_err(&dev->pdev->dev, "waiting for mei start failed\n");
 143                return -ETIMEDOUT;
 144        }
 145        return 0;
 146}
 147
 148/**
 149 * mei_hbm_start_req - sends start request message.
 150 *
 151 * @dev: the device structure
 152 */
 153int mei_hbm_start_req(struct mei_device *dev)
 154{
 155        struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
 156        struct hbm_host_version_request *start_req;
 157        const size_t len = sizeof(struct hbm_host_version_request);
 158
 159        mei_hbm_hdr(mei_hdr, len);
 160
 161        /* host start message */
 162        start_req = (struct hbm_host_version_request *)dev->wr_msg.data;
 163        memset(start_req, 0, len);
 164        start_req->hbm_cmd = HOST_START_REQ_CMD;
 165        start_req->host_version.major_version = HBM_MAJOR_VERSION;
 166        start_req->host_version.minor_version = HBM_MINOR_VERSION;
 167
 168        dev->hbm_state = MEI_HBM_IDLE;
 169        if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
 170                dev_err(&dev->pdev->dev, "version message write failed\n");
 171                dev->dev_state = MEI_DEV_RESETTING;
 172                mei_reset(dev, 1);
 173                return -ENODEV;
 174        }
 175        dev->hbm_state = MEI_HBM_START;
 176        dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
 177        return 0;
 178}
 179
 180/*
 181 * mei_hbm_enum_clients_req - sends enumeration client request message.
 182 *
 183 * @dev: the device structure
 184 *
 185 * returns none.
 186 */
 187static void mei_hbm_enum_clients_req(struct mei_device *dev)
 188{
 189        struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
 190        struct hbm_host_enum_request *enum_req;
 191        const size_t len = sizeof(struct hbm_host_enum_request);
 192        /* enumerate clients */
 193        mei_hbm_hdr(mei_hdr, len);
 194
 195        enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data;
 196        memset(enum_req, 0, len);
 197        enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
 198
 199        if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
 200                dev->dev_state = MEI_DEV_RESETTING;
 201                dev_err(&dev->pdev->dev, "enumeration request write failed.\n");
 202                mei_reset(dev, 1);
 203        }
 204        dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
 205        dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
 206        return;
 207}
 208
 209/**
 210 * mei_hbm_prop_req - request property for a single client
 211 *
 212 * @dev: the device structure
 213 *
 214 * returns none.
 215 */
 216
 217static int mei_hbm_prop_req(struct mei_device *dev)
 218{
 219
 220        struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
 221        struct hbm_props_request *prop_req;
 222        const size_t len = sizeof(struct hbm_props_request);
 223        unsigned long next_client_index;
 224        u8 client_num;
 225
 226
 227        client_num = dev->me_client_presentation_num;
 228
 229        next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX,
 230                                          dev->me_client_index);
 231
 232        /* We got all client properties */
 233        if (next_client_index == MEI_CLIENTS_MAX) {
 234                dev->hbm_state = MEI_HBM_STARTED;
 235                schedule_work(&dev->init_work);
 236
 237                return 0;
 238        }
 239
 240        dev->me_clients[client_num].client_id = next_client_index;
 241        dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
 242
 243        mei_hbm_hdr(mei_hdr, len);
 244        prop_req = (struct hbm_props_request *)dev->wr_msg.data;
 245
 246        memset(prop_req, 0, sizeof(struct hbm_props_request));
 247
 248
 249        prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
 250        prop_req->address = next_client_index;
 251
 252        if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
 253                dev->dev_state = MEI_DEV_RESETTING;
 254                dev_err(&dev->pdev->dev, "properties request write failed\n");
 255                mei_reset(dev, 1);
 256
 257                return -EIO;
 258        }
 259
 260        dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
 261        dev->me_client_index = next_client_index;
 262
 263        return 0;
 264}
 265
 266/**
 267 * mei_hbm_stop_req_prepare - perpare stop request message
 268 *
 269 * @dev - mei device
 270 * @mei_hdr - mei message header
 271 * @data - hbm message body buffer
 272 */
 273static void mei_hbm_stop_req_prepare(struct mei_device *dev,
 274                struct mei_msg_hdr *mei_hdr, unsigned char *data)
 275{
 276        struct hbm_host_stop_request *req =
 277                        (struct hbm_host_stop_request *)data;
 278        const size_t len = sizeof(struct hbm_host_stop_request);
 279
 280        mei_hbm_hdr(mei_hdr, len);
 281
 282        memset(req, 0, len);
 283        req->hbm_cmd = HOST_STOP_REQ_CMD;
 284        req->reason = DRIVER_STOP_REQUEST;
 285}
 286
 287/**
 288 * mei_hbm_cl_flow_control_req - sends flow control requst.
 289 *
 290 * @dev: the device structure
 291 * @cl: client info
 292 *
 293 * This function returns -EIO on write failure
 294 */
 295int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
 296{
 297        struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
 298        const size_t len = sizeof(struct hbm_flow_control);
 299
 300        mei_hbm_hdr(mei_hdr, len);
 301        mei_hbm_cl_hdr(cl, MEI_FLOW_CONTROL_CMD, dev->wr_msg.data, len);
 302
 303        dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
 304                cl->host_client_id, cl->me_client_id);
 305
 306        return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
 307}
 308
 309/**
 310 * mei_hbm_add_single_flow_creds - adds single buffer credentials.
 311 *
 312 * @dev: the device structure
 313 * @flow: flow control.
 314 */
 315static void mei_hbm_add_single_flow_creds(struct mei_device *dev,
 316                                  struct hbm_flow_control *flow)
 317{
 318        struct mei_me_client *client;
 319        int i;
 320
 321        for (i = 0; i < dev->me_clients_num; i++) {
 322                client = &dev->me_clients[i];
 323                if (client && flow->me_addr == client->client_id) {
 324                        if (client->props.single_recv_buf) {
 325                                client->mei_flow_ctrl_creds++;
 326                                dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
 327                                    flow->me_addr);
 328                                dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
 329                                    client->mei_flow_ctrl_creds);
 330                        } else {
 331                                BUG();  /* error in flow control */
 332                        }
 333                }
 334        }
 335}
 336
 337/**
 338 * mei_hbm_cl_flow_control_res - flow control response from me
 339 *
 340 * @dev: the device structure
 341 * @flow_control: flow control response bus message
 342 */
 343static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
 344                struct hbm_flow_control *flow_control)
 345{
 346        struct mei_cl *cl = NULL;
 347        struct mei_cl *next = NULL;
 348
 349        if (!flow_control->host_addr) {
 350                /* single receive buffer */
 351                mei_hbm_add_single_flow_creds(dev, flow_control);
 352                return;
 353        }
 354
 355        /* normal connection */
 356        list_for_each_entry_safe(cl, next, &dev->file_list, link) {
 357                if (mei_hbm_cl_addr_equal(cl, flow_control)) {
 358                        cl->mei_flow_ctrl_creds++;
 359                        dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
 360                                flow_control->host_addr, flow_control->me_addr);
 361                        dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
 362                                    cl->mei_flow_ctrl_creds);
 363                                break;
 364                }
 365        }
 366}
 367
 368
 369/**
 370 * mei_hbm_cl_disconnect_req - sends disconnect message to fw.
 371 *
 372 * @dev: the device structure
 373 * @cl: a client to disconnect from
 374 *
 375 * This function returns -EIO on write failure
 376 */
 377int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
 378{
 379        struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
 380        const size_t len = sizeof(struct hbm_client_connect_request);
 381
 382        mei_hbm_hdr(mei_hdr, len);
 383        mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, dev->wr_msg.data, len);
 384
 385        return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
 386}
 387
 388/**
 389 * mei_hbm_cl_disconnect_res - disconnect response from ME
 390 *
 391 * @dev: the device structure
 392 * @rs: disconnect response bus message
 393 */
 394static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
 395                struct hbm_client_connect_response *rs)
 396{
 397        struct mei_cl *cl;
 398        struct mei_cl_cb *pos = NULL, *next = NULL;
 399
 400        dev_dbg(&dev->pdev->dev,
 401                        "disconnect_response:\n"
 402                        "ME Client = %d\n"
 403                        "Host Client = %d\n"
 404                        "Status = %d\n",
 405                        rs->me_addr,
 406                        rs->host_addr,
 407                        rs->status);
 408
 409        list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
 410                cl = pos->cl;
 411
 412                if (!cl) {
 413                        list_del(&pos->list);
 414                        return;
 415                }
 416
 417                dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
 418                if (mei_hbm_cl_addr_equal(cl, rs)) {
 419                        list_del(&pos->list);
 420                        if (!rs->status)
 421                                cl->state = MEI_FILE_DISCONNECTED;
 422
 423                        cl->status = 0;
 424                        cl->timer_count = 0;
 425                        break;
 426                }
 427        }
 428}
 429
 430/**
 431 * mei_hbm_cl_connect_req - send connection request to specific me client
 432 *
 433 * @dev: the device structure
 434 * @cl: a client to connect to
 435 *
 436 * returns -EIO on write failure
 437 */
 438int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
 439{
 440        struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
 441        const size_t len = sizeof(struct hbm_client_connect_request);
 442
 443        mei_hbm_hdr(mei_hdr, len);
 444        mei_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, dev->wr_msg.data, len);
 445
 446        return mei_write_message(dev, mei_hdr,  dev->wr_msg.data);
 447}
 448
 449/**
 450 * mei_hbm_cl_connect_res - connect resposne from the ME
 451 *
 452 * @dev: the device structure
 453 * @rs: connect response bus message
 454 */
 455static void mei_hbm_cl_connect_res(struct mei_device *dev,
 456                struct hbm_client_connect_response *rs)
 457{
 458
 459        struct mei_cl *cl;
 460        struct mei_cl_cb *pos = NULL, *next = NULL;
 461
 462        dev_dbg(&dev->pdev->dev,
 463                        "connect_response:\n"
 464                        "ME Client = %d\n"
 465                        "Host Client = %d\n"
 466                        "Status = %d\n",
 467                        rs->me_addr,
 468                        rs->host_addr,
 469                        rs->status);
 470
 471        /* if WD or iamthif client treat specially */
 472
 473        if (is_treat_specially_client(&dev->wd_cl, rs)) {
 474                dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
 475                mei_watchdog_register(dev);
 476
 477                return;
 478        }
 479
 480        if (is_treat_specially_client(&dev->iamthif_cl, rs)) {
 481                dev->iamthif_state = MEI_IAMTHIF_IDLE;
 482                return;
 483        }
 484        list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
 485
 486                cl = pos->cl;
 487                if (!cl) {
 488                        list_del(&pos->list);
 489                        return;
 490                }
 491                if (pos->fop_type == MEI_FOP_IOCTL) {
 492                        if (is_treat_specially_client(cl, rs)) {
 493                                list_del(&pos->list);
 494                                cl->status = 0;
 495                                cl->timer_count = 0;
 496                                break;
 497                        }
 498                }
 499        }
 500}
 501
 502
 503/**
 504 * mei_hbm_fw_disconnect_req - disconnect request initiated by me
 505 *  host sends disoconnect response
 506 *
 507 * @dev: the device structure.
 508 * @disconnect_req: disconnect request bus message from the me
 509 */
 510static void mei_hbm_fw_disconnect_req(struct mei_device *dev,
 511                struct hbm_client_connect_request *disconnect_req)
 512{
 513        struct mei_cl *cl, *next;
 514        const size_t len = sizeof(struct hbm_client_connect_response);
 515
 516        list_for_each_entry_safe(cl, next, &dev->file_list, link) {
 517                if (mei_hbm_cl_addr_equal(cl, disconnect_req)) {
 518                        dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
 519                                        disconnect_req->host_addr,
 520                                        disconnect_req->me_addr);
 521                        cl->state = MEI_FILE_DISCONNECTED;
 522                        cl->timer_count = 0;
 523                        if (cl == &dev->wd_cl)
 524                                dev->wd_pending = false;
 525                        else if (cl == &dev->iamthif_cl)
 526                                dev->iamthif_timer = 0;
 527
 528                        /* prepare disconnect response */
 529                        mei_hbm_hdr(&dev->wr_ext_msg.hdr, len);
 530                        mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD,
 531                                         dev->wr_ext_msg.data, len);
 532                        break;
 533                }
 534        }
 535}
 536
 537
 538/**
 539 * mei_hbm_version_is_supported - checks whether the driver can
 540 *     support the hbm version of the device
 541 *
 542 * @dev: the device structure
 543 * returns true if driver can support hbm version of the device
 544 */
 545bool mei_hbm_version_is_supported(struct mei_device *dev)
 546{
 547        return  (dev->version.major_version < HBM_MAJOR_VERSION) ||
 548                (dev->version.major_version == HBM_MAJOR_VERSION &&
 549                 dev->version.minor_version <= HBM_MINOR_VERSION);
 550}
 551
 552/**
 553 * mei_hbm_dispatch - bottom half read routine after ISR to
 554 * handle the read bus message cmd processing.
 555 *
 556 * @dev: the device structure
 557 * @mei_hdr: header of bus message
 558 */
 559void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
 560{
 561        struct mei_bus_message *mei_msg;
 562        struct mei_me_client *me_client;
 563        struct hbm_host_version_response *version_res;
 564        struct hbm_client_connect_response *connect_res;
 565        struct hbm_client_connect_response *disconnect_res;
 566        struct hbm_client_connect_request *disconnect_req;
 567        struct hbm_flow_control *flow_control;
 568        struct hbm_props_response *props_res;
 569        struct hbm_host_enum_response *enum_res;
 570
 571        /* read the message to our buffer */
 572        BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
 573        mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
 574        mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
 575
 576        switch (mei_msg->hbm_cmd) {
 577        case HOST_START_RES_CMD:
 578                version_res = (struct hbm_host_version_response *)mei_msg;
 579
 580                dev_dbg(&dev->pdev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n",
 581                                HBM_MAJOR_VERSION, HBM_MINOR_VERSION,
 582                                version_res->me_max_version.major_version,
 583                                version_res->me_max_version.minor_version);
 584
 585                if (version_res->host_version_supported) {
 586                        dev->version.major_version = HBM_MAJOR_VERSION;
 587                        dev->version.minor_version = HBM_MINOR_VERSION;
 588                } else {
 589                        dev->version.major_version =
 590                                version_res->me_max_version.major_version;
 591                        dev->version.minor_version =
 592                                version_res->me_max_version.minor_version;
 593                }
 594
 595                if (!mei_hbm_version_is_supported(dev)) {
 596                        dev_warn(&dev->pdev->dev, "hbm version mismatch: stopping the driver.\n");
 597
 598                        dev->hbm_state = MEI_HBM_STOP;
 599                        mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
 600                                                dev->wr_msg.data);
 601                        mei_write_message(dev, &dev->wr_msg.hdr,
 602                                        dev->wr_msg.data);
 603
 604                        return;
 605                }
 606
 607                if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
 608                    dev->hbm_state == MEI_HBM_START) {
 609                        dev->init_clients_timer = 0;
 610                        mei_hbm_enum_clients_req(dev);
 611                } else {
 612                        dev_err(&dev->pdev->dev, "reset: wrong host start response\n");
 613                        mei_reset(dev, 1);
 614                        return;
 615                }
 616
 617                wake_up_interruptible(&dev->wait_recvd_msg);
 618                dev_dbg(&dev->pdev->dev, "host start response message received.\n");
 619                break;
 620
 621        case CLIENT_CONNECT_RES_CMD:
 622                connect_res = (struct hbm_client_connect_response *) mei_msg;
 623                mei_hbm_cl_connect_res(dev, connect_res);
 624                dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
 625                wake_up(&dev->wait_recvd_msg);
 626                break;
 627
 628        case CLIENT_DISCONNECT_RES_CMD:
 629                disconnect_res = (struct hbm_client_connect_response *) mei_msg;
 630                mei_hbm_cl_disconnect_res(dev, disconnect_res);
 631                dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
 632                wake_up(&dev->wait_recvd_msg);
 633                break;
 634
 635        case MEI_FLOW_CONTROL_CMD:
 636                flow_control = (struct hbm_flow_control *) mei_msg;
 637                mei_hbm_cl_flow_control_res(dev, flow_control);
 638                dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
 639                break;
 640
 641        case HOST_CLIENT_PROPERTIES_RES_CMD:
 642                props_res = (struct hbm_props_response *)mei_msg;
 643                me_client = &dev->me_clients[dev->me_client_presentation_num];
 644
 645                if (props_res->status || !dev->me_clients) {
 646                        dev_err(&dev->pdev->dev, "reset: properties response hbm wrong status.\n");
 647                        mei_reset(dev, 1);
 648                        return;
 649                }
 650
 651                if (me_client->client_id != props_res->address) {
 652                        dev_err(&dev->pdev->dev, "reset: host properties response address mismatch\n");
 653                        mei_reset(dev, 1);
 654                        return;
 655                }
 656
 657                if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
 658                    dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
 659                        dev_err(&dev->pdev->dev, "reset: unexpected properties response\n");
 660                        mei_reset(dev, 1);
 661
 662                        return;
 663                }
 664
 665                me_client->props = props_res->client_properties;
 666                dev->me_client_index++;
 667                dev->me_client_presentation_num++;
 668
 669                /* request property for the next client */
 670                mei_hbm_prop_req(dev);
 671
 672                break;
 673
 674        case HOST_ENUM_RES_CMD:
 675                enum_res = (struct hbm_host_enum_response *) mei_msg;
 676                memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
 677                if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
 678                    dev->hbm_state == MEI_HBM_ENUM_CLIENTS) {
 679                                dev->init_clients_timer = 0;
 680                                dev->me_client_presentation_num = 0;
 681                                dev->me_client_index = 0;
 682                                mei_hbm_me_cl_allocate(dev);
 683                                dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
 684
 685                                /* first property reqeust */
 686                                mei_hbm_prop_req(dev);
 687                } else {
 688                        dev_err(&dev->pdev->dev, "reset: unexpected enumeration response hbm.\n");
 689                        mei_reset(dev, 1);
 690                        return;
 691                }
 692                break;
 693
 694        case HOST_STOP_RES_CMD:
 695
 696                if (dev->hbm_state != MEI_HBM_STOP)
 697                        dev_err(&dev->pdev->dev, "unexpected stop response hbm.\n");
 698                dev->dev_state = MEI_DEV_DISABLED;
 699                dev_info(&dev->pdev->dev, "reset: FW stop response.\n");
 700                mei_reset(dev, 1);
 701                break;
 702
 703        case CLIENT_DISCONNECT_REQ_CMD:
 704                /* search for client */
 705                disconnect_req = (struct hbm_client_connect_request *)mei_msg;
 706                mei_hbm_fw_disconnect_req(dev, disconnect_req);
 707                break;
 708
 709        case ME_STOP_REQ_CMD:
 710
 711                dev->hbm_state = MEI_HBM_STOP;
 712                mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
 713                                        dev->wr_ext_msg.data);
 714                break;
 715        default:
 716                BUG();
 717                break;
 718
 719        }
 720}
 721
 722