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