diff options
| author | Ingo Molnar <mingo@kernel.org> | 2013-01-24 06:47:48 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2013-01-24 06:47:48 -0500 |
| commit | befddb21c845f8fb49e637997891ef97c6a869dc (patch) | |
| tree | 0e7629123184f2dd50291ad6d477b894175f0f26 /drivers/misc/mei/init.c | |
| parent | e716efde75267eab919cdb2bef5b2cb77f305326 (diff) | |
| parent | 7d1f9aeff1ee4a20b1aeb377dd0f579fe9647619 (diff) | |
Merge tag 'v3.8-rc4' into irq/core
Merge Linux 3.8-rc4 before pulling in new commits - we were on an old v3.7 base.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/misc/mei/init.c')
| -rw-r--r-- | drivers/misc/mei/init.c | 368 |
1 files changed, 149 insertions, 219 deletions
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 98f1430e3e14..a54cd5567ca2 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c | |||
| @@ -43,21 +43,6 @@ const char *mei_dev_state_str(int state) | |||
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | 45 | ||
| 46 | const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, | ||
| 47 | 0xa8, 0x46, 0xe0, 0xff, 0x65, | ||
| 48 | 0x81, 0x4c); | ||
| 49 | |||
| 50 | /** | ||
| 51 | * mei_io_list_init - Sets up a queue list. | ||
| 52 | * | ||
| 53 | * @list: An instance io list structure | ||
| 54 | * @dev: the device structure | ||
| 55 | */ | ||
| 56 | void mei_io_list_init(struct mei_io_list *list) | ||
| 57 | { | ||
| 58 | /* initialize our queue list */ | ||
| 59 | INIT_LIST_HEAD(&list->mei_cb.cb_list); | ||
| 60 | } | ||
| 61 | 46 | ||
| 62 | /** | 47 | /** |
| 63 | * mei_io_list_flush - removes list entry belonging to cl. | 48 | * mei_io_list_flush - removes list entry belonging to cl. |
| @@ -65,17 +50,15 @@ void mei_io_list_init(struct mei_io_list *list) | |||
| 65 | * @list: An instance of our list structure | 50 | * @list: An instance of our list structure |
| 66 | * @cl: private data of the file object | 51 | * @cl: private data of the file object |
| 67 | */ | 52 | */ |
| 68 | void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl) | 53 | void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) |
| 69 | { | 54 | { |
| 70 | struct mei_cl_cb *pos; | 55 | struct mei_cl_cb *pos; |
| 71 | struct mei_cl_cb *next; | 56 | struct mei_cl_cb *next; |
| 72 | 57 | ||
| 73 | list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) { | 58 | list_for_each_entry_safe(pos, next, &list->list, list) { |
| 74 | if (pos->file_private) { | 59 | if (pos->cl) { |
| 75 | struct mei_cl *cl_tmp; | 60 | if (mei_cl_cmp_id(cl, pos->cl)) |
| 76 | cl_tmp = (struct mei_cl *)pos->file_private; | 61 | list_del(&pos->list); |
| 77 | if (mei_cl_cmp_id(cl, cl_tmp)) | ||
| 78 | list_del(&pos->cb_list); | ||
| 79 | } | 62 | } |
| 80 | } | 63 | } |
| 81 | } | 64 | } |
| @@ -96,31 +79,14 @@ int mei_cl_flush_queues(struct mei_cl *cl) | |||
| 96 | mei_io_list_flush(&cl->dev->write_waiting_list, cl); | 79 | mei_io_list_flush(&cl->dev->write_waiting_list, cl); |
| 97 | mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); | 80 | mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); |
| 98 | mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); | 81 | mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); |
| 99 | mei_io_list_flush(&cl->dev->amthi_cmd_list, cl); | 82 | mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); |
| 100 | mei_io_list_flush(&cl->dev->amthi_read_complete_list, cl); | 83 | mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); |
| 101 | return 0; | 84 | return 0; |
| 102 | } | 85 | } |
| 103 | 86 | ||
| 104 | 87 | ||
| 105 | 88 | ||
| 106 | /** | 89 | /** |
| 107 | * mei_reset_iamthif_params - initializes mei device iamthif | ||
| 108 | * | ||
| 109 | * @dev: the device structure | ||
| 110 | */ | ||
| 111 | static void mei_reset_iamthif_params(struct mei_device *dev) | ||
| 112 | { | ||
| 113 | /* reset iamthif parameters. */ | ||
| 114 | dev->iamthif_current_cb = NULL; | ||
| 115 | dev->iamthif_msg_buf_size = 0; | ||
| 116 | dev->iamthif_msg_buf_index = 0; | ||
| 117 | dev->iamthif_canceled = false; | ||
| 118 | dev->iamthif_ioctl = false; | ||
| 119 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
| 120 | dev->iamthif_timer = 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | /** | ||
| 124 | * init_mei_device - allocates and initializes the mei device structure | 90 | * init_mei_device - allocates and initializes the mei device structure |
| 125 | * | 91 | * |
| 126 | * @pdev: The pci device structure | 92 | * @pdev: The pci device structure |
| @@ -144,16 +110,14 @@ struct mei_device *mei_device_init(struct pci_dev *pdev) | |||
| 144 | init_waitqueue_head(&dev->wait_stop_wd); | 110 | init_waitqueue_head(&dev->wait_stop_wd); |
| 145 | dev->dev_state = MEI_DEV_INITIALIZING; | 111 | dev->dev_state = MEI_DEV_INITIALIZING; |
| 146 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | 112 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
| 147 | dev->wd_interface_reg = false; | ||
| 148 | |||
| 149 | 113 | ||
| 150 | mei_io_list_init(&dev->read_list); | 114 | mei_io_list_init(&dev->read_list); |
| 151 | mei_io_list_init(&dev->write_list); | 115 | mei_io_list_init(&dev->write_list); |
| 152 | mei_io_list_init(&dev->write_waiting_list); | 116 | mei_io_list_init(&dev->write_waiting_list); |
| 153 | mei_io_list_init(&dev->ctrl_wr_list); | 117 | mei_io_list_init(&dev->ctrl_wr_list); |
| 154 | mei_io_list_init(&dev->ctrl_rd_list); | 118 | mei_io_list_init(&dev->ctrl_rd_list); |
| 155 | mei_io_list_init(&dev->amthi_cmd_list); | 119 | mei_io_list_init(&dev->amthif_cmd_list); |
| 156 | mei_io_list_init(&dev->amthi_read_complete_list); | 120 | mei_io_list_init(&dev->amthif_rd_complete_list); |
| 157 | dev->pdev = pdev; | 121 | dev->pdev = pdev; |
| 158 | return dev; | 122 | return dev; |
| 159 | } | 123 | } |
| @@ -196,7 +160,8 @@ int mei_hw_init(struct mei_device *dev) | |||
| 196 | if (!dev->recvd_msg) { | 160 | if (!dev->recvd_msg) { |
| 197 | mutex_unlock(&dev->device_lock); | 161 | mutex_unlock(&dev->device_lock); |
| 198 | err = wait_event_interruptible_timeout(dev->wait_recvd_msg, | 162 | err = wait_event_interruptible_timeout(dev->wait_recvd_msg, |
| 199 | dev->recvd_msg, MEI_INTEROP_TIMEOUT); | 163 | dev->recvd_msg, |
| 164 | mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT)); | ||
| 200 | mutex_lock(&dev->device_lock); | 165 | mutex_lock(&dev->device_lock); |
| 201 | } | 166 | } |
| 202 | 167 | ||
| @@ -317,15 +282,13 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) | |||
| 317 | cl_pos->timer_count = 0; | 282 | cl_pos->timer_count = 0; |
| 318 | } | 283 | } |
| 319 | /* remove entry if already in list */ | 284 | /* remove entry if already in list */ |
| 320 | dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n"); | 285 | dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); |
| 321 | mei_remove_client_from_file_list(dev, | 286 | mei_me_cl_unlink(dev, &dev->wd_cl); |
| 322 | dev->wd_cl.host_client_id); | ||
| 323 | 287 | ||
| 324 | mei_remove_client_from_file_list(dev, | 288 | mei_me_cl_unlink(dev, &dev->iamthif_cl); |
| 325 | dev->iamthif_cl.host_client_id); | ||
| 326 | 289 | ||
| 327 | mei_reset_iamthif_params(dev); | 290 | mei_amthif_reset_params(dev); |
| 328 | dev->extra_write_index = 0; | 291 | memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); |
| 329 | } | 292 | } |
| 330 | 293 | ||
| 331 | dev->me_clients_num = 0; | 294 | dev->me_clients_num = 0; |
| @@ -351,10 +314,9 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) | |||
| 351 | } | 314 | } |
| 352 | } | 315 | } |
| 353 | /* remove all waiting requests */ | 316 | /* remove all waiting requests */ |
| 354 | list_for_each_entry_safe(cb_pos, cb_next, | 317 | list_for_each_entry_safe(cb_pos, cb_next, &dev->write_list.list, list) { |
| 355 | &dev->write_list.mei_cb.cb_list, cb_list) { | 318 | list_del(&cb_pos->list); |
| 356 | list_del(&cb_pos->cb_list); | 319 | mei_io_cb_free(cb_pos); |
| 357 | mei_free_cb_private(cb_pos); | ||
| 358 | } | 320 | } |
| 359 | } | 321 | } |
| 360 | 322 | ||
| @@ -370,31 +332,26 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) | |||
| 370 | void mei_host_start_message(struct mei_device *dev) | 332 | void mei_host_start_message(struct mei_device *dev) |
| 371 | { | 333 | { |
| 372 | struct mei_msg_hdr *mei_hdr; | 334 | struct mei_msg_hdr *mei_hdr; |
| 373 | struct hbm_host_version_request *host_start_req; | 335 | struct hbm_host_version_request *start_req; |
| 336 | const size_t len = sizeof(struct hbm_host_version_request); | ||
| 337 | |||
| 338 | mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); | ||
| 374 | 339 | ||
| 375 | /* host start message */ | 340 | /* host start message */ |
| 376 | mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; | 341 | start_req = (struct hbm_host_version_request *)&dev->wr_msg_buf[1]; |
| 377 | mei_hdr->host_addr = 0; | 342 | memset(start_req, 0, len); |
| 378 | mei_hdr->me_addr = 0; | 343 | start_req->hbm_cmd = HOST_START_REQ_CMD; |
| 379 | mei_hdr->length = sizeof(struct hbm_host_version_request); | 344 | start_req->host_version.major_version = HBM_MAJOR_VERSION; |
| 380 | mei_hdr->msg_complete = 1; | 345 | start_req->host_version.minor_version = HBM_MINOR_VERSION; |
| 381 | mei_hdr->reserved = 0; | 346 | |
| 382 | |||
| 383 | host_start_req = | ||
| 384 | (struct hbm_host_version_request *) &dev->wr_msg_buf[1]; | ||
| 385 | memset(host_start_req, 0, sizeof(struct hbm_host_version_request)); | ||
| 386 | host_start_req->hbm_cmd = HOST_START_REQ_CMD; | ||
| 387 | host_start_req->host_version.major_version = HBM_MAJOR_VERSION; | ||
| 388 | host_start_req->host_version.minor_version = HBM_MINOR_VERSION; | ||
| 389 | dev->recvd_msg = false; | 347 | dev->recvd_msg = false; |
| 390 | if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req, | 348 | if (mei_write_message(dev, mei_hdr, (unsigned char *)start_req, len)) { |
| 391 | mei_hdr->length)) { | ||
| 392 | dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n"); | 349 | dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n"); |
| 393 | dev->dev_state = MEI_DEV_RESETING; | 350 | dev->dev_state = MEI_DEV_RESETING; |
| 394 | mei_reset(dev, 1); | 351 | mei_reset(dev, 1); |
| 395 | } | 352 | } |
| 396 | dev->init_clients_state = MEI_START_MESSAGE; | 353 | dev->init_clients_state = MEI_START_MESSAGE; |
| 397 | dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; | 354 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; |
| 398 | return ; | 355 | return ; |
| 399 | } | 356 | } |
| 400 | 357 | ||
| @@ -408,26 +365,22 @@ void mei_host_start_message(struct mei_device *dev) | |||
| 408 | void mei_host_enum_clients_message(struct mei_device *dev) | 365 | void mei_host_enum_clients_message(struct mei_device *dev) |
| 409 | { | 366 | { |
| 410 | struct mei_msg_hdr *mei_hdr; | 367 | struct mei_msg_hdr *mei_hdr; |
| 411 | struct hbm_host_enum_request *host_enum_req; | 368 | struct hbm_host_enum_request *enum_req; |
| 412 | mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; | 369 | const size_t len = sizeof(struct hbm_host_enum_request); |
| 413 | /* enumerate clients */ | 370 | /* enumerate clients */ |
| 414 | mei_hdr->host_addr = 0; | 371 | mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); |
| 415 | mei_hdr->me_addr = 0; | 372 | |
| 416 | mei_hdr->length = sizeof(struct hbm_host_enum_request); | 373 | enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; |
| 417 | mei_hdr->msg_complete = 1; | 374 | memset(enum_req, 0, sizeof(struct hbm_host_enum_request)); |
| 418 | mei_hdr->reserved = 0; | 375 | enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; |
| 419 | 376 | ||
| 420 | host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; | 377 | if (mei_write_message(dev, mei_hdr, (unsigned char *)enum_req, len)) { |
| 421 | memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request)); | ||
| 422 | host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; | ||
| 423 | if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req, | ||
| 424 | mei_hdr->length)) { | ||
| 425 | dev->dev_state = MEI_DEV_RESETING; | 378 | dev->dev_state = MEI_DEV_RESETING; |
| 426 | dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); | 379 | dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); |
| 427 | mei_reset(dev, 1); | 380 | mei_reset(dev, 1); |
| 428 | } | 381 | } |
| 429 | dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE; | 382 | dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE; |
| 430 | dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; | 383 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; |
| 431 | return; | 384 | return; |
| 432 | } | 385 | } |
| 433 | 386 | ||
| @@ -470,56 +423,87 @@ void mei_allocate_me_clients_storage(struct mei_device *dev) | |||
| 470 | dev->me_clients = clients; | 423 | dev->me_clients = clients; |
| 471 | return ; | 424 | return ; |
| 472 | } | 425 | } |
| 473 | /** | 426 | |
| 474 | * host_client_properties - reads properties for client | 427 | void mei_host_client_init(struct work_struct *work) |
| 475 | * | ||
| 476 | * @dev: the device structure | ||
| 477 | * | ||
| 478 | * returns: | ||
| 479 | * < 0 - Error. | ||
| 480 | * = 0 - no more clients. | ||
| 481 | * = 1 - still have clients to send properties request. | ||
| 482 | */ | ||
| 483 | int mei_host_client_properties(struct mei_device *dev) | ||
| 484 | { | 428 | { |
| 485 | struct mei_msg_hdr *mei_header; | 429 | struct mei_device *dev = container_of(work, |
| 486 | struct hbm_props_request *host_cli_req; | 430 | struct mei_device, init_work); |
| 487 | int b; | 431 | struct mei_client_properties *client_props; |
| 488 | u8 client_num = dev->me_client_presentation_num; | 432 | int i; |
| 489 | 433 | ||
| 490 | b = dev->me_client_index; | 434 | mutex_lock(&dev->device_lock); |
| 491 | b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b); | 435 | |
| 492 | if (b < MEI_CLIENTS_MAX) { | 436 | bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); |
| 493 | dev->me_clients[client_num].client_id = b; | 437 | dev->open_handle_count = 0; |
| 494 | dev->me_clients[client_num].mei_flow_ctrl_creds = 0; | 438 | |
| 495 | mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; | 439 | /* |
| 496 | mei_header->host_addr = 0; | 440 | * Reserving the first three client IDs |
| 497 | mei_header->me_addr = 0; | 441 | * 0: Reserved for MEI Bus Message communications |
| 498 | mei_header->length = sizeof(struct hbm_props_request); | 442 | * 1: Reserved for Watchdog |
| 499 | mei_header->msg_complete = 1; | 443 | * 2: Reserved for AMTHI |
| 500 | mei_header->reserved = 0; | 444 | */ |
| 501 | 445 | bitmap_set(dev->host_clients_map, 0, 3); | |
| 502 | host_cli_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; | 446 | |
| 503 | 447 | for (i = 0; i < dev->me_clients_num; i++) { | |
| 504 | memset(host_cli_req, 0, sizeof(struct hbm_props_request)); | 448 | client_props = &dev->me_clients[i].props; |
| 505 | 449 | ||
| 506 | host_cli_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; | 450 | if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid)) |
| 507 | host_cli_req->address = b; | 451 | mei_amthif_host_init(dev); |
| 508 | 452 | else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid)) | |
| 509 | if (mei_write_message(dev, mei_header, | 453 | mei_wd_host_init(dev); |
| 510 | (unsigned char *)host_cli_req, | 454 | } |
| 511 | mei_header->length)) { | 455 | |
| 512 | dev->dev_state = MEI_DEV_RESETING; | 456 | dev->dev_state = MEI_DEV_ENABLED; |
| 513 | dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); | ||
| 514 | mei_reset(dev, 1); | ||
| 515 | return -EIO; | ||
| 516 | } | ||
| 517 | 457 | ||
| 518 | dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; | 458 | mutex_unlock(&dev->device_lock); |
| 519 | dev->me_client_index = b; | 459 | } |
| 520 | return 1; | 460 | |
| 461 | int mei_host_client_enumerate(struct mei_device *dev) | ||
| 462 | { | ||
| 463 | |||
| 464 | struct mei_msg_hdr *mei_hdr; | ||
| 465 | struct hbm_props_request *prop_req; | ||
| 466 | const size_t len = sizeof(struct hbm_props_request); | ||
| 467 | unsigned long next_client_index; | ||
| 468 | u8 client_num; | ||
| 469 | |||
| 470 | |||
| 471 | client_num = dev->me_client_presentation_num; | ||
| 472 | |||
| 473 | next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, | ||
| 474 | dev->me_client_index); | ||
| 475 | |||
| 476 | /* We got all client properties */ | ||
| 477 | if (next_client_index == MEI_CLIENTS_MAX) { | ||
| 478 | schedule_work(&dev->init_work); | ||
| 479 | |||
| 480 | return 0; | ||
| 521 | } | 481 | } |
| 522 | 482 | ||
| 483 | dev->me_clients[client_num].client_id = next_client_index; | ||
| 484 | dev->me_clients[client_num].mei_flow_ctrl_creds = 0; | ||
| 485 | |||
| 486 | mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); | ||
| 487 | prop_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; | ||
| 488 | |||
| 489 | memset(prop_req, 0, sizeof(struct hbm_props_request)); | ||
| 490 | |||
| 491 | |||
| 492 | prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; | ||
| 493 | prop_req->address = next_client_index; | ||
| 494 | |||
| 495 | if (mei_write_message(dev, mei_hdr, (unsigned char *) prop_req, | ||
| 496 | mei_hdr->length)) { | ||
| 497 | dev->dev_state = MEI_DEV_RESETING; | ||
| 498 | dev_err(&dev->pdev->dev, "Properties request command failed\n"); | ||
| 499 | mei_reset(dev, 1); | ||
| 500 | |||
| 501 | return -EIO; | ||
| 502 | } | ||
| 503 | |||
| 504 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; | ||
| 505 | dev->me_client_index = next_client_index; | ||
| 506 | |||
| 523 | return 0; | 507 | return 0; |
| 524 | } | 508 | } |
| 525 | 509 | ||
| @@ -557,17 +541,20 @@ int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid) | |||
| 557 | 541 | ||
| 558 | 542 | ||
| 559 | /** | 543 | /** |
| 560 | * mei_me_cl_update_filext - searches for ME client guid | 544 | * mei_me_cl_link - create link between host and me clinet and add |
| 561 | * sets client_id in mei_file_private if found | 545 | * me_cl to the list |
| 546 | * | ||
| 562 | * @dev: the device structure | 547 | * @dev: the device structure |
| 563 | * @cl: private file structure to set client_id in | 548 | * @cl: link between me and host client assocated with opened file descriptor |
| 564 | * @cuuid: searched uuid of ME client | 549 | * @cuuid: uuid of ME client |
| 565 | * @client_id: id of host client to be set in file private structure | 550 | * @client_id: id of the host client |
| 566 | * | 551 | * |
| 567 | * returns ME client index | 552 | * returns ME client index if ME client |
| 553 | * -EINVAL on incorrect values | ||
| 554 | * -ENONET if client not found | ||
| 568 | */ | 555 | */ |
| 569 | int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, | 556 | int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl, |
| 570 | const uuid_le *cuuid, u8 host_cl_id) | 557 | const uuid_le *cuuid, u8 host_cl_id) |
| 571 | { | 558 | { |
| 572 | int i; | 559 | int i; |
| 573 | 560 | ||
| @@ -587,54 +574,22 @@ int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, | |||
| 587 | 574 | ||
| 588 | return -ENOENT; | 575 | return -ENOENT; |
| 589 | } | 576 | } |
| 590 | |||
| 591 | /** | 577 | /** |
| 592 | * host_init_iamthif - mei initialization iamthif client. | 578 | * mei_me_cl_unlink - remove me_cl from the list |
| 593 | * | 579 | * |
| 594 | * @dev: the device structure | 580 | * @dev: the device structure |
| 595 | * | 581 | * @host_client_id: host client id to be removed |
| 596 | */ | 582 | */ |
| 597 | void mei_host_init_iamthif(struct mei_device *dev) | 583 | void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl) |
| 598 | { | 584 | { |
| 599 | int i; | 585 | struct mei_cl *pos, *next; |
| 600 | unsigned char *msg_buf; | 586 | list_for_each_entry_safe(pos, next, &dev->file_list, link) { |
| 601 | 587 | if (cl->host_client_id == pos->host_client_id) { | |
| 602 | mei_cl_init(&dev->iamthif_cl, dev); | 588 | dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", |
| 603 | dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; | 589 | pos->host_client_id, pos->me_client_id); |
| 604 | 590 | list_del_init(&pos->link); | |
| 605 | /* find ME amthi client */ | 591 | break; |
| 606 | i = mei_me_cl_update_filext(dev, &dev->iamthif_cl, | 592 | } |
| 607 | &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); | ||
| 608 | if (i < 0) { | ||
| 609 | dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n"); | ||
| 610 | return; | ||
| 611 | } | ||
| 612 | |||
| 613 | /* Assign iamthif_mtu to the value received from ME */ | ||
| 614 | |||
| 615 | dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; | ||
| 616 | dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n", | ||
| 617 | dev->me_clients[i].props.max_msg_length); | ||
| 618 | |||
| 619 | kfree(dev->iamthif_msg_buf); | ||
| 620 | dev->iamthif_msg_buf = NULL; | ||
| 621 | |||
| 622 | /* allocate storage for ME message buffer */ | ||
| 623 | msg_buf = kcalloc(dev->iamthif_mtu, | ||
| 624 | sizeof(unsigned char), GFP_KERNEL); | ||
| 625 | if (!msg_buf) { | ||
| 626 | dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n"); | ||
| 627 | return; | ||
| 628 | } | ||
| 629 | |||
| 630 | dev->iamthif_msg_buf = msg_buf; | ||
| 631 | |||
| 632 | if (mei_connect(dev, &dev->iamthif_cl)) { | ||
| 633 | dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n"); | ||
| 634 | dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; | ||
| 635 | dev->iamthif_cl.host_client_id = 0; | ||
| 636 | } else { | ||
| 637 | dev->iamthif_cl.timer_count = CONNECT_TIMEOUT; | ||
| 638 | } | 593 | } |
| 639 | } | 594 | } |
| 640 | 595 | ||
| @@ -671,9 +626,8 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev) | |||
| 671 | */ | 626 | */ |
| 672 | int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) | 627 | int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) |
| 673 | { | 628 | { |
| 674 | int rets, err; | ||
| 675 | long timeout = 15; /* 15 seconds */ | ||
| 676 | struct mei_cl_cb *cb; | 629 | struct mei_cl_cb *cb; |
| 630 | int rets, err; | ||
| 677 | 631 | ||
| 678 | if (!dev || !cl) | 632 | if (!dev || !cl) |
| 679 | return -ENODEV; | 633 | return -ENODEV; |
| @@ -681,13 +635,11 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) | |||
| 681 | if (cl->state != MEI_FILE_DISCONNECTING) | 635 | if (cl->state != MEI_FILE_DISCONNECTING) |
| 682 | return 0; | 636 | return 0; |
| 683 | 637 | ||
| 684 | cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); | 638 | cb = mei_io_cb_init(cl, NULL); |
| 685 | if (!cb) | 639 | if (!cb) |
| 686 | return -ENOMEM; | 640 | return -ENOMEM; |
| 687 | 641 | ||
| 688 | INIT_LIST_HEAD(&cb->cb_list); | 642 | cb->fop_type = MEI_FOP_CLOSE; |
| 689 | cb->file_private = cl; | ||
| 690 | cb->major_file_operations = MEI_CLOSE; | ||
| 691 | if (dev->mei_host_buffer_is_empty) { | 643 | if (dev->mei_host_buffer_is_empty) { |
| 692 | dev->mei_host_buffer_is_empty = false; | 644 | dev->mei_host_buffer_is_empty = false; |
| 693 | if (mei_disconnect(dev, cl)) { | 645 | if (mei_disconnect(dev, cl)) { |
| @@ -696,17 +648,17 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) | |||
| 696 | goto free; | 648 | goto free; |
| 697 | } | 649 | } |
| 698 | mdelay(10); /* Wait for hardware disconnection ready */ | 650 | mdelay(10); /* Wait for hardware disconnection ready */ |
| 699 | list_add_tail(&cb->cb_list, &dev->ctrl_rd_list.mei_cb.cb_list); | 651 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); |
| 700 | } else { | 652 | } else { |
| 701 | dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); | 653 | dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); |
| 702 | list_add_tail(&cb->cb_list, | 654 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); |
| 703 | &dev->ctrl_wr_list.mei_cb.cb_list); | 655 | |
| 704 | } | 656 | } |
| 705 | mutex_unlock(&dev->device_lock); | 657 | mutex_unlock(&dev->device_lock); |
| 706 | 658 | ||
| 707 | err = wait_event_timeout(dev->wait_recvd_msg, | 659 | err = wait_event_timeout(dev->wait_recvd_msg, |
| 708 | (MEI_FILE_DISCONNECTED == cl->state), | 660 | MEI_FILE_DISCONNECTED == cl->state, |
| 709 | timeout * HZ); | 661 | mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); |
| 710 | 662 | ||
| 711 | mutex_lock(&dev->device_lock); | 663 | mutex_lock(&dev->device_lock); |
| 712 | if (MEI_FILE_DISCONNECTED == cl->state) { | 664 | if (MEI_FILE_DISCONNECTED == cl->state) { |
| @@ -728,29 +680,7 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) | |||
| 728 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | 680 | mei_io_list_flush(&dev->ctrl_rd_list, cl); |
| 729 | mei_io_list_flush(&dev->ctrl_wr_list, cl); | 681 | mei_io_list_flush(&dev->ctrl_wr_list, cl); |
| 730 | free: | 682 | free: |
| 731 | mei_free_cb_private(cb); | 683 | mei_io_cb_free(cb); |
| 732 | return rets; | 684 | return rets; |
| 733 | } | 685 | } |
| 734 | 686 | ||
| 735 | /** | ||
| 736 | * mei_remove_client_from_file_list - | ||
| 737 | * removes file private data from device file list | ||
| 738 | * | ||
| 739 | * @dev: the device structure | ||
| 740 | * @host_client_id: host client id to be removed | ||
| 741 | */ | ||
| 742 | void mei_remove_client_from_file_list(struct mei_device *dev, | ||
| 743 | u8 host_client_id) | ||
| 744 | { | ||
| 745 | struct mei_cl *cl_pos = NULL; | ||
| 746 | struct mei_cl *cl_next = NULL; | ||
| 747 | list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { | ||
| 748 | if (host_client_id == cl_pos->host_client_id) { | ||
| 749 | dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", | ||
| 750 | cl_pos->host_client_id, | ||
| 751 | cl_pos->me_client_id); | ||
| 752 | list_del_init(&cl_pos->link); | ||
| 753 | break; | ||
| 754 | } | ||
| 755 | } | ||
| 756 | } | ||
