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/delay.h> 21 22 #include <linux/mei.h> 23 24 #include "mei_dev.h" 25 #include "hbm.h" 26 #include "interface.h" 27 #include "client.h" 28 29 /** 30 * mei_me_cl_by_uuid - locate index of me client 31 * 32 * @dev: mei device 33 * returns me client index or -ENOENT if not found 34 */ 35 int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid) 36 { 37 int i, res = -ENOENT; 38 39 for (i = 0; i < dev->me_clients_num; ++i) 40 if (uuid_le_cmp(*uuid, 41 dev->me_clients[i].props.protocol_name) == 0) { 42 res = i; 43 break; 44 } 45 46 return res; 47 } 48 49 50 /** 51 * mei_me_cl_by_id return index to me_clients for client_id 52 * 53 * @dev: the device structure 54 * @client_id: me client id 55 * 56 * Locking: called under "dev->device_lock" lock 57 * 58 * returns index on success, -ENOENT on failure. 59 */ 60 61 int mei_me_cl_by_id(struct mei_device *dev, u8 client_id) 62 { 63 int i; 64 for (i = 0; i < dev->me_clients_num; i++) 65 if (dev->me_clients[i].client_id == client_id) 66 break; 67 if (WARN_ON(dev->me_clients[i].client_id != client_id)) 68 return -ENOENT; 69 70 if (i == dev->me_clients_num) 71 return -ENOENT; 72 73 return i; 74 } 75 76 77 /** 78 * mei_io_list_flush - removes list entry belonging to cl. 79 * 80 * @list: An instance of our list structure 81 * @cl: host client 82 */ 83 void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) 84 { 85 struct mei_cl_cb *cb; 86 struct mei_cl_cb *next; 87 88 list_for_each_entry_safe(cb, next, &list->list, list) { 89 if (cb->cl && mei_cl_cmp_id(cl, cb->cl)) 90 list_del(&cb->list); 91 } 92 } 93 94 /** 95 * mei_io_cb_free - free mei_cb_private related memory 96 * 97 * @cb: mei callback struct 98 */ 99 void mei_io_cb_free(struct mei_cl_cb *cb) 100 { 101 if (cb == NULL) 102 return; 103 104 kfree(cb->request_buffer.data); 105 kfree(cb->response_buffer.data); 106 kfree(cb); 107 } 108 109 /** 110 * mei_io_cb_init - allocate and initialize io callback 111 * 112 * @cl - mei client 113 * @file: pointer to file structure 114 * 115 * returns mei_cl_cb pointer or NULL; 116 */ 117 struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) 118 { 119 struct mei_cl_cb *cb; 120 121 cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); 122 if (!cb) 123 return NULL; 124 125 mei_io_list_init(cb); 126 127 cb->file_object = fp; 128 cb->cl = cl; 129 cb->buf_idx = 0; 130 return cb; 131 } 132 133 /** 134 * mei_io_cb_alloc_req_buf - allocate request buffer 135 * 136 * @cb - io callback structure 137 * @size: size of the buffer 138 * 139 * returns 0 on success 140 * -EINVAL if cb is NULL 141 * -ENOMEM if allocation failed 142 */ 143 int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) 144 { 145 if (!cb) 146 return -EINVAL; 147 148 if (length == 0) 149 return 0; 150 151 cb->request_buffer.data = kmalloc(length, GFP_KERNEL); 152 if (!cb->request_buffer.data) 153 return -ENOMEM; 154 cb->request_buffer.size = length; 155 return 0; 156 } 157 /** 158 * mei_io_cb_alloc_req_buf - allocate respose buffer 159 * 160 * @cb - io callback structure 161 * @size: size of the buffer 162 * 163 * returns 0 on success 164 * -EINVAL if cb is NULL 165 * -ENOMEM if allocation failed 166 */ 167 int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) 168 { 169 if (!cb) 170 return -EINVAL; 171 172 if (length == 0) 173 return 0; 174 175 cb->response_buffer.data = kmalloc(length, GFP_KERNEL); 176 if (!cb->response_buffer.data) 177 return -ENOMEM; 178 cb->response_buffer.size = length; 179 return 0; 180 } 181 182 183 184 /** 185 * mei_cl_flush_queues - flushes queue lists belonging to cl. 186 * 187 * @dev: the device structure 188 * @cl: host client 189 */ 190 int mei_cl_flush_queues(struct mei_cl *cl) 191 { 192 if (WARN_ON(!cl || !cl->dev)) 193 return -EINVAL; 194 195 dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n"); 196 mei_io_list_flush(&cl->dev->read_list, cl); 197 mei_io_list_flush(&cl->dev->write_list, cl); 198 mei_io_list_flush(&cl->dev->write_waiting_list, cl); 199 mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); 200 mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); 201 mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); 202 mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); 203 return 0; 204 } 205 206 207 /** 208 * mei_cl_init - initializes intialize cl. 209 * 210 * @cl: host client to be initialized 211 * @dev: mei device 212 */ 213 void mei_cl_init(struct mei_cl *cl, struct mei_device *dev) 214 { 215 memset(cl, 0, sizeof(struct mei_cl)); 216 init_waitqueue_head(&cl->wait); 217 init_waitqueue_head(&cl->rx_wait); 218 init_waitqueue_head(&cl->tx_wait); 219 INIT_LIST_HEAD(&cl->link); 220 cl->reading_state = MEI_IDLE; 221 cl->writing_state = MEI_IDLE; 222 cl->dev = dev; 223 } 224 225 /** 226 * mei_cl_allocate - allocates cl structure and sets it up. 227 * 228 * @dev: mei device 229 * returns The allocated file or NULL on failure 230 */ 231 struct mei_cl *mei_cl_allocate(struct mei_device *dev) 232 { 233 struct mei_cl *cl; 234 235 cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL); 236 if (!cl) 237 return NULL; 238 239 mei_cl_init(cl, dev); 240 241 return cl; 242 } 243 244 /** 245 * mei_cl_find_read_cb - find this cl's callback in the read list 246 * 247 * @dev: device structure 248 * returns cb on success, NULL on error 249 */ 250 struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl) 251 { 252 struct mei_device *dev = cl->dev; 253 struct mei_cl_cb *cb = NULL; 254 struct mei_cl_cb *next = NULL; 255 256 list_for_each_entry_safe(cb, next, &dev->read_list.list, list) 257 if (mei_cl_cmp_id(cl, cb->cl)) 258 return cb; 259 return NULL; 260 } 261 262 263 /** 264 * mei_me_cl_link - create link between host and me clinet and add 265 * me_cl to the list 266 * 267 * @cl: link between me and host client assocated with opened file descriptor 268 * @uuid: uuid of ME client 269 * @client_id: id of the host client 270 * 271 * returns ME client index if ME client 272 * -EINVAL on incorrect values 273 * -ENONET if client not found 274 */ 275 int mei_cl_link_me(struct mei_cl *cl, const uuid_le *uuid, u8 host_cl_id) 276 { 277 struct mei_device *dev; 278 int i; 279 280 if (WARN_ON(!cl || !cl->dev || !uuid)) 281 return -EINVAL; 282 283 dev = cl->dev; 284 285 /* check for valid client id */ 286 i = mei_me_cl_by_uuid(dev, uuid); 287 if (i >= 0) { 288 cl->me_client_id = dev->me_clients[i].client_id; 289 cl->state = MEI_FILE_CONNECTING; 290 cl->host_client_id = host_cl_id; 291 292 list_add_tail(&cl->link, &dev->file_list); 293 return (u8)i; 294 } 295 296 return -ENOENT; 297 } 298 /** 299 * mei_cl_unlink - remove me_cl from the list 300 * 301 * @dev: the device structure 302 * @host_client_id: host client id to be removed 303 */ 304 int mei_cl_unlink(struct mei_cl *cl) 305 { 306 struct mei_device *dev; 307 struct mei_cl *pos, *next; 308 309 if (WARN_ON(!cl || !cl->dev)) 310 return -EINVAL; 311 312 dev = cl->dev; 313 314 list_for_each_entry_safe(pos, next, &dev->file_list, link) { 315 if (cl->host_client_id == pos->host_client_id) { 316 dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", 317 pos->host_client_id, pos->me_client_id); 318 list_del_init(&pos->link); 319 break; 320 } 321 } 322 return 0; 323 } 324 325 326 void mei_host_client_init(struct work_struct *work) 327 { 328 struct mei_device *dev = container_of(work, 329 struct mei_device, init_work); 330 struct mei_client_properties *client_props; 331 int i; 332 333 mutex_lock(&dev->device_lock); 334 335 bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); 336 dev->open_handle_count = 0; 337 338 /* 339 * Reserving the first three client IDs 340 * 0: Reserved for MEI Bus Message communications 341 * 1: Reserved for Watchdog 342 * 2: Reserved for AMTHI 343 */ 344 bitmap_set(dev->host_clients_map, 0, 3); 345 346 for (i = 0; i < dev->me_clients_num; i++) { 347 client_props = &dev->me_clients[i].props; 348 349 if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid)) 350 mei_amthif_host_init(dev); 351 else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid)) 352 mei_wd_host_init(dev); 353 } 354 355 dev->dev_state = MEI_DEV_ENABLED; 356 357 mutex_unlock(&dev->device_lock); 358 } 359 360 361 /** 362 * mei_cl_disconnect - disconnect host clinet form the me one 363 * 364 * @cl: host client 365 * 366 * Locking: called under "dev->device_lock" lock 367 * 368 * returns 0 on success, <0 on failure. 369 */ 370 int mei_cl_disconnect(struct mei_cl *cl) 371 { 372 struct mei_device *dev; 373 struct mei_cl_cb *cb; 374 int rets, err; 375 376 if (WARN_ON(!cl || !cl->dev)) 377 return -ENODEV; 378 379 dev = cl->dev; 380 381 if (cl->state != MEI_FILE_DISCONNECTING) 382 return 0; 383 384 cb = mei_io_cb_init(cl, NULL); 385 if (!cb) 386 return -ENOMEM; 387 388 cb->fop_type = MEI_FOP_CLOSE; 389 if (dev->mei_host_buffer_is_empty) { 390 dev->mei_host_buffer_is_empty = false; 391 if (mei_hbm_cl_disconnect_req(dev, cl)) { 392 rets = -ENODEV; 393 dev_err(&dev->pdev->dev, "failed to disconnect.\n"); 394 goto free; 395 } 396 mdelay(10); /* Wait for hardware disconnection ready */ 397 list_add_tail(&cb->list, &dev->ctrl_rd_list.list); 398 } else { 399 dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); 400 list_add_tail(&cb->list, &dev->ctrl_wr_list.list); 401 402 } 403 mutex_unlock(&dev->device_lock); 404 405 err = wait_event_timeout(dev->wait_recvd_msg, 406 MEI_FILE_DISCONNECTED == cl->state, 407 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); 408 409 mutex_lock(&dev->device_lock); 410 if (MEI_FILE_DISCONNECTED == cl->state) { 411 rets = 0; 412 dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n"); 413 } else { 414 rets = -ENODEV; 415 if (MEI_FILE_DISCONNECTED != cl->state) 416 dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n"); 417 418 if (err) 419 dev_dbg(&dev->pdev->dev, 420 "wait failed disconnect err=%08x\n", 421 err); 422 423 dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n"); 424 } 425 426 mei_io_list_flush(&dev->ctrl_rd_list, cl); 427 mei_io_list_flush(&dev->ctrl_wr_list, cl); 428 free: 429 mei_io_cb_free(cb); 430 return rets; 431 } 432 433 434 /** 435 * mei_cl_is_other_connecting - checks if other 436 * client with the same me client id is connecting 437 * 438 * @cl: private data of the file object 439 * 440 * returns ture if other client is connected, 0 - otherwise. 441 */ 442 bool mei_cl_is_other_connecting(struct mei_cl *cl) 443 { 444 struct mei_device *dev; 445 struct mei_cl *pos; 446 struct mei_cl *next; 447 448 if (WARN_ON(!cl || !cl->dev)) 449 return false; 450 451 dev = cl->dev; 452 453 list_for_each_entry_safe(pos, next, &dev->file_list, link) { 454 if ((pos->state == MEI_FILE_CONNECTING) && 455 (pos != cl) && cl->me_client_id == pos->me_client_id) 456 return true; 457 458 } 459 460 return false; 461 } 462 463 /** 464 * mei_cl_connect - connect host clinet to the me one 465 * 466 * @cl: host client 467 * 468 * Locking: called under "dev->device_lock" lock 469 * 470 * returns 0 on success, <0 on failure. 471 */ 472 int mei_cl_connect(struct mei_cl *cl, struct file *file) 473 { 474 struct mei_device *dev; 475 struct mei_cl_cb *cb; 476 long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT); 477 int rets; 478 479 if (WARN_ON(!cl || !cl->dev)) 480 return -ENODEV; 481 482 dev = cl->dev; 483 484 cb = mei_io_cb_init(cl, file); 485 if (!cb) { 486 rets = -ENOMEM; 487 goto out; 488 } 489 490 cb->fop_type = MEI_FOP_IOCTL; 491 492 if (dev->mei_host_buffer_is_empty && 493 !mei_cl_is_other_connecting(cl)) { 494 dev->mei_host_buffer_is_empty = false; 495 496 if (mei_hbm_cl_connect_req(dev, cl)) { 497 rets = -ENODEV; 498 goto out; 499 } 500 cl->timer_count = MEI_CONNECT_TIMEOUT; 501 list_add_tail(&cb->list, &dev->ctrl_rd_list.list); 502 } else { 503 list_add_tail(&cb->list, &dev->ctrl_wr_list.list); 504 } 505 506 mutex_unlock(&dev->device_lock); 507 rets = wait_event_timeout(dev->wait_recvd_msg, 508 (cl->state == MEI_FILE_CONNECTED || 509 cl->state == MEI_FILE_DISCONNECTED), 510 timeout * HZ); 511 mutex_lock(&dev->device_lock); 512 513 if (cl->state != MEI_FILE_CONNECTED) { 514 rets = -EFAULT; 515 516 mei_io_list_flush(&dev->ctrl_rd_list, cl); 517 mei_io_list_flush(&dev->ctrl_wr_list, cl); 518 goto out; 519 } 520 521 rets = cl->status; 522 523 out: 524 mei_io_cb_free(cb); 525 return rets; 526 } 527 528 /** 529 * mei_cl_flow_ctrl_creds - checks flow_control credits for cl. 530 * 531 * @dev: the device structure 532 * @cl: private data of the file object 533 * 534 * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise. 535 * -ENOENT if mei_cl is not present 536 * -EINVAL if single_recv_buf == 0 537 */ 538 int mei_cl_flow_ctrl_creds(struct mei_cl *cl) 539 { 540 struct mei_device *dev; 541 int i; 542 543 if (WARN_ON(!cl || !cl->dev)) 544 return -EINVAL; 545 546 dev = cl->dev; 547 548 if (!dev->me_clients_num) 549 return 0; 550 551 if (cl->mei_flow_ctrl_creds > 0) 552 return 1; 553 554 for (i = 0; i < dev->me_clients_num; i++) { 555 struct mei_me_client *me_cl = &dev->me_clients[i]; 556 if (me_cl->client_id == cl->me_client_id) { 557 if (me_cl->mei_flow_ctrl_creds) { 558 if (WARN_ON(me_cl->props.single_recv_buf == 0)) 559 return -EINVAL; 560 return 1; 561 } else { 562 return 0; 563 } 564 } 565 } 566 return -ENOENT; 567 } 568 569 /** 570 * mei_cl_flow_ctrl_reduce - reduces flow_control. 571 * 572 * @dev: the device structure 573 * @cl: private data of the file object 574 * @returns 575 * 0 on success 576 * -ENOENT when me client is not found 577 * -EINVAL when ctrl credits are <= 0 578 */ 579 int mei_cl_flow_ctrl_reduce(struct mei_cl *cl) 580 { 581 struct mei_device *dev; 582 int i; 583 584 if (WARN_ON(!cl || !cl->dev)) 585 return -EINVAL; 586 587 dev = cl->dev; 588 589 if (!dev->me_clients_num) 590 return -ENOENT; 591 592 for (i = 0; i < dev->me_clients_num; i++) { 593 struct mei_me_client *me_cl = &dev->me_clients[i]; 594 if (me_cl->client_id == cl->me_client_id) { 595 if (me_cl->props.single_recv_buf != 0) { 596 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) 597 return -EINVAL; 598 dev->me_clients[i].mei_flow_ctrl_creds--; 599 } else { 600 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) 601 return -EINVAL; 602 cl->mei_flow_ctrl_creds--; 603 } 604 return 0; 605 } 606 } 607 return -ENOENT; 608 } 609 610 /** 611 * mei_cl_start_read - the start read client message function. 612 * 613 * @cl: host client 614 * 615 * returns 0 on success, <0 on failure. 616 */ 617 int mei_cl_read_start(struct mei_cl *cl) 618 { 619 struct mei_device *dev; 620 struct mei_cl_cb *cb; 621 int rets; 622 int i; 623 624 if (WARN_ON(!cl || !cl->dev)) 625 return -ENODEV; 626 627 dev = cl->dev; 628 629 if (cl->state != MEI_FILE_CONNECTED) 630 return -ENODEV; 631 632 if (dev->dev_state != MEI_DEV_ENABLED) 633 return -ENODEV; 634 635 if (cl->read_pending || cl->read_cb) { 636 dev_dbg(&dev->pdev->dev, "read is pending.\n"); 637 return -EBUSY; 638 } 639 i = mei_me_cl_by_id(dev, cl->me_client_id); 640 if (i < 0) { 641 dev_err(&dev->pdev->dev, "no such me client %d\n", 642 cl->me_client_id); 643 return -ENODEV; 644 } 645 646 cb = mei_io_cb_init(cl, NULL); 647 if (!cb) 648 return -ENOMEM; 649 650 rets = mei_io_cb_alloc_resp_buf(cb, 651 dev->me_clients[i].props.max_msg_length); 652 if (rets) 653 goto err; 654 655 cb->fop_type = MEI_FOP_READ; 656 cl->read_cb = cb; 657 if (dev->mei_host_buffer_is_empty) { 658 dev->mei_host_buffer_is_empty = false; 659 if (mei_hbm_cl_flow_control_req(dev, cl)) { 660 rets = -ENODEV; 661 goto err; 662 } 663 list_add_tail(&cb->list, &dev->read_list.list); 664 } else { 665 list_add_tail(&cb->list, &dev->ctrl_wr_list.list); 666 } 667 return rets; 668 err: 669 mei_io_cb_free(cb); 670 return rets; 671 } 672 673