at v3.0 770 lines 20 kB view raw
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}