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