| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | | - * |
|---|
| 3 | + * Copyright (c) 2003-2020, Intel Corporation. All rights reserved. |
|---|
| 3 | 4 | * 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 | 5 | */ |
|---|
| 16 | 6 | |
|---|
| 17 | 7 | #include <linux/sched/signal.h> |
|---|
| .. | .. |
|---|
| 320 | 310 | } |
|---|
| 321 | 311 | |
|---|
| 322 | 312 | /** |
|---|
| 323 | | - * mei_cl_cmp_id - tells if the clients are the same |
|---|
| 324 | | - * |
|---|
| 325 | | - * @cl1: host client 1 |
|---|
| 326 | | - * @cl2: host client 2 |
|---|
| 327 | | - * |
|---|
| 328 | | - * Return: true - if the clients has same host and me ids |
|---|
| 329 | | - * false - otherwise |
|---|
| 330 | | - */ |
|---|
| 331 | | -static inline bool mei_cl_cmp_id(const struct mei_cl *cl1, |
|---|
| 332 | | - const struct mei_cl *cl2) |
|---|
| 333 | | -{ |
|---|
| 334 | | - return cl1 && cl2 && |
|---|
| 335 | | - (cl1->host_client_id == cl2->host_client_id) && |
|---|
| 336 | | - (mei_cl_me_id(cl1) == mei_cl_me_id(cl2)); |
|---|
| 337 | | -} |
|---|
| 338 | | - |
|---|
| 339 | | -/** |
|---|
| 340 | 313 | * mei_io_cb_free - free mei_cb_private related memory |
|---|
| 341 | 314 | * |
|---|
| 342 | 315 | * @cb: mei callback struct |
|---|
| .. | .. |
|---|
| 382 | 355 | } |
|---|
| 383 | 356 | |
|---|
| 384 | 357 | /** |
|---|
| 358 | + * mei_cl_set_read_by_fp - set pending_read flag to vtag struct for given fp |
|---|
| 359 | + * |
|---|
| 360 | + * Locking: called under "dev->device_lock" lock |
|---|
| 361 | + * |
|---|
| 362 | + * @cl: mei client |
|---|
| 363 | + * @fp: pointer to file structure |
|---|
| 364 | + */ |
|---|
| 365 | +static void mei_cl_set_read_by_fp(const struct mei_cl *cl, |
|---|
| 366 | + const struct file *fp) |
|---|
| 367 | +{ |
|---|
| 368 | + struct mei_cl_vtag *cl_vtag; |
|---|
| 369 | + |
|---|
| 370 | + list_for_each_entry(cl_vtag, &cl->vtag_map, list) { |
|---|
| 371 | + if (cl_vtag->fp == fp) { |
|---|
| 372 | + cl_vtag->pending_read = true; |
|---|
| 373 | + return; |
|---|
| 374 | + } |
|---|
| 375 | + } |
|---|
| 376 | +} |
|---|
| 377 | + |
|---|
| 378 | +/** |
|---|
| 385 | 379 | * mei_io_cb_init - allocate and initialize io callback |
|---|
| 386 | 380 | * |
|---|
| 387 | 381 | * @cl: mei client |
|---|
| .. | .. |
|---|
| 396 | 390 | { |
|---|
| 397 | 391 | struct mei_cl_cb *cb; |
|---|
| 398 | 392 | |
|---|
| 399 | | - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); |
|---|
| 393 | + cb = kzalloc(sizeof(*cb), GFP_KERNEL); |
|---|
| 400 | 394 | if (!cb) |
|---|
| 401 | 395 | return NULL; |
|---|
| 402 | 396 | |
|---|
| .. | .. |
|---|
| 405 | 399 | cb->cl = cl; |
|---|
| 406 | 400 | cb->buf_idx = 0; |
|---|
| 407 | 401 | cb->fop_type = type; |
|---|
| 402 | + cb->vtag = 0; |
|---|
| 403 | + |
|---|
| 408 | 404 | return cb; |
|---|
| 409 | 405 | } |
|---|
| 410 | 406 | |
|---|
| .. | .. |
|---|
| 420 | 416 | struct mei_cl_cb *cb, *next; |
|---|
| 421 | 417 | |
|---|
| 422 | 418 | list_for_each_entry_safe(cb, next, head, list) { |
|---|
| 423 | | - if (mei_cl_cmp_id(cl, cb->cl)) |
|---|
| 419 | + if (cl == cb->cl) { |
|---|
| 424 | 420 | list_del_init(&cb->list); |
|---|
| 421 | + if (cb->fop_type == MEI_FOP_READ) |
|---|
| 422 | + mei_io_cb_free(cb); |
|---|
| 423 | + } |
|---|
| 425 | 424 | } |
|---|
| 426 | 425 | } |
|---|
| 427 | 426 | |
|---|
| .. | .. |
|---|
| 430 | 429 | * |
|---|
| 431 | 430 | * @head: An instance of our list structure |
|---|
| 432 | 431 | * @cl: host client |
|---|
| 432 | + * @fp: file pointer (matching cb file object), may be NULL |
|---|
| 433 | 433 | */ |
|---|
| 434 | 434 | static void mei_io_tx_list_free_cl(struct list_head *head, |
|---|
| 435 | | - const struct mei_cl *cl) |
|---|
| 435 | + const struct mei_cl *cl, |
|---|
| 436 | + const struct file *fp) |
|---|
| 436 | 437 | { |
|---|
| 437 | 438 | struct mei_cl_cb *cb, *next; |
|---|
| 438 | 439 | |
|---|
| 439 | 440 | list_for_each_entry_safe(cb, next, head, list) { |
|---|
| 440 | | - if (mei_cl_cmp_id(cl, cb->cl)) |
|---|
| 441 | + if (cl == cb->cl && (!fp || fp == cb->fp)) |
|---|
| 441 | 442 | mei_tx_cb_dequeue(cb); |
|---|
| 442 | 443 | } |
|---|
| 443 | 444 | } |
|---|
| .. | .. |
|---|
| 455 | 456 | list_for_each_entry_safe(cb, next, head, list) |
|---|
| 456 | 457 | if (!fp || fp == cb->fp) |
|---|
| 457 | 458 | mei_io_cb_free(cb); |
|---|
| 459 | +} |
|---|
| 460 | + |
|---|
| 461 | +/** |
|---|
| 462 | + * mei_cl_free_pending - free pending cb |
|---|
| 463 | + * |
|---|
| 464 | + * @cl: host client |
|---|
| 465 | + */ |
|---|
| 466 | +static void mei_cl_free_pending(struct mei_cl *cl) |
|---|
| 467 | +{ |
|---|
| 468 | + struct mei_cl_cb *cb; |
|---|
| 469 | + |
|---|
| 470 | + cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list); |
|---|
| 471 | + mei_io_cb_free(cb); |
|---|
| 458 | 472 | } |
|---|
| 459 | 473 | |
|---|
| 460 | 474 | /** |
|---|
| .. | .. |
|---|
| 480 | 494 | if (length == 0) |
|---|
| 481 | 495 | return cb; |
|---|
| 482 | 496 | |
|---|
| 483 | | - cb->buf.data = kmalloc(length, GFP_KERNEL); |
|---|
| 497 | + cb->buf.data = kmalloc(roundup(length, MEI_SLOT_SIZE), GFP_KERNEL); |
|---|
| 484 | 498 | if (!cb->buf.data) { |
|---|
| 485 | 499 | mei_io_cb_free(cb); |
|---|
| 486 | 500 | return NULL; |
|---|
| .. | .. |
|---|
| 529 | 543 | * |
|---|
| 530 | 544 | * Return: cb on success, NULL if cb is not found |
|---|
| 531 | 545 | */ |
|---|
| 532 | | -struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, const struct file *fp) |
|---|
| 546 | +struct mei_cl_cb *mei_cl_read_cb(struct mei_cl *cl, const struct file *fp) |
|---|
| 533 | 547 | { |
|---|
| 534 | 548 | struct mei_cl_cb *cb; |
|---|
| 549 | + struct mei_cl_cb *ret_cb = NULL; |
|---|
| 535 | 550 | |
|---|
| 551 | + spin_lock(&cl->rd_completed_lock); |
|---|
| 536 | 552 | list_for_each_entry(cb, &cl->rd_completed, list) |
|---|
| 537 | | - if (!fp || fp == cb->fp) |
|---|
| 538 | | - return cb; |
|---|
| 539 | | - |
|---|
| 540 | | - return NULL; |
|---|
| 553 | + if (!fp || fp == cb->fp) { |
|---|
| 554 | + ret_cb = cb; |
|---|
| 555 | + break; |
|---|
| 556 | + } |
|---|
| 557 | + spin_unlock(&cl->rd_completed_lock); |
|---|
| 558 | + return ret_cb; |
|---|
| 541 | 559 | } |
|---|
| 542 | 560 | |
|---|
| 543 | 561 | /** |
|---|
| .. | .. |
|---|
| 558 | 576 | dev = cl->dev; |
|---|
| 559 | 577 | |
|---|
| 560 | 578 | cl_dbg(dev, cl, "remove list entry belonging to cl\n"); |
|---|
| 561 | | - mei_io_tx_list_free_cl(&cl->dev->write_list, cl); |
|---|
| 562 | | - mei_io_tx_list_free_cl(&cl->dev->write_waiting_list, cl); |
|---|
| 563 | | - mei_io_list_flush_cl(&cl->dev->ctrl_wr_list, cl); |
|---|
| 564 | | - mei_io_list_flush_cl(&cl->dev->ctrl_rd_list, cl); |
|---|
| 565 | | - mei_io_list_free_fp(&cl->rd_pending, fp); |
|---|
| 579 | + mei_io_tx_list_free_cl(&cl->dev->write_list, cl, fp); |
|---|
| 580 | + mei_io_tx_list_free_cl(&cl->dev->write_waiting_list, cl, fp); |
|---|
| 581 | + /* free pending and control cb only in final flush */ |
|---|
| 582 | + if (!fp) { |
|---|
| 583 | + mei_io_list_flush_cl(&cl->dev->ctrl_wr_list, cl); |
|---|
| 584 | + mei_io_list_flush_cl(&cl->dev->ctrl_rd_list, cl); |
|---|
| 585 | + mei_cl_free_pending(cl); |
|---|
| 586 | + } |
|---|
| 587 | + spin_lock(&cl->rd_completed_lock); |
|---|
| 566 | 588 | mei_io_list_free_fp(&cl->rd_completed, fp); |
|---|
| 589 | + spin_unlock(&cl->rd_completed_lock); |
|---|
| 567 | 590 | |
|---|
| 568 | 591 | return 0; |
|---|
| 569 | 592 | } |
|---|
| .. | .. |
|---|
| 576 | 599 | */ |
|---|
| 577 | 600 | static void mei_cl_init(struct mei_cl *cl, struct mei_device *dev) |
|---|
| 578 | 601 | { |
|---|
| 579 | | - memset(cl, 0, sizeof(struct mei_cl)); |
|---|
| 602 | + memset(cl, 0, sizeof(*cl)); |
|---|
| 580 | 603 | init_waitqueue_head(&cl->wait); |
|---|
| 581 | 604 | init_waitqueue_head(&cl->rx_wait); |
|---|
| 582 | 605 | init_waitqueue_head(&cl->tx_wait); |
|---|
| 583 | 606 | init_waitqueue_head(&cl->ev_wait); |
|---|
| 607 | + INIT_LIST_HEAD(&cl->vtag_map); |
|---|
| 608 | + spin_lock_init(&cl->rd_completed_lock); |
|---|
| 584 | 609 | INIT_LIST_HEAD(&cl->rd_completed); |
|---|
| 585 | 610 | INIT_LIST_HEAD(&cl->rd_pending); |
|---|
| 586 | 611 | INIT_LIST_HEAD(&cl->link); |
|---|
| .. | .. |
|---|
| 599 | 624 | { |
|---|
| 600 | 625 | struct mei_cl *cl; |
|---|
| 601 | 626 | |
|---|
| 602 | | - cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL); |
|---|
| 627 | + cl = kmalloc(sizeof(*cl), GFP_KERNEL); |
|---|
| 603 | 628 | if (!cl) |
|---|
| 604 | 629 | return NULL; |
|---|
| 605 | 630 | |
|---|
| .. | .. |
|---|
| 695 | 720 | |
|---|
| 696 | 721 | void mei_host_client_init(struct mei_device *dev) |
|---|
| 697 | 722 | { |
|---|
| 698 | | - dev->dev_state = MEI_DEV_ENABLED; |
|---|
| 723 | + mei_set_devstate(dev, MEI_DEV_ENABLED); |
|---|
| 699 | 724 | dev->reset_count = 0; |
|---|
| 700 | 725 | |
|---|
| 701 | 726 | schedule_work(&dev->bus_rescan_work); |
|---|
| .. | .. |
|---|
| 776 | 801 | return; |
|---|
| 777 | 802 | |
|---|
| 778 | 803 | cl->state = MEI_FILE_DISCONNECTED; |
|---|
| 779 | | - mei_io_tx_list_free_cl(&dev->write_list, cl); |
|---|
| 780 | | - mei_io_tx_list_free_cl(&dev->write_waiting_list, cl); |
|---|
| 804 | + mei_io_tx_list_free_cl(&dev->write_list, cl, NULL); |
|---|
| 805 | + mei_io_tx_list_free_cl(&dev->write_waiting_list, cl, NULL); |
|---|
| 781 | 806 | mei_io_list_flush_cl(&dev->ctrl_rd_list, cl); |
|---|
| 782 | 807 | mei_io_list_flush_cl(&dev->ctrl_wr_list, cl); |
|---|
| 783 | 808 | mei_cl_wake_all(cl); |
|---|
| .. | .. |
|---|
| 1253 | 1278 | } |
|---|
| 1254 | 1279 | |
|---|
| 1255 | 1280 | /** |
|---|
| 1281 | + * mei_cl_vtag_alloc - allocate and fill the vtag structure |
|---|
| 1282 | + * |
|---|
| 1283 | + * @fp: pointer to file structure |
|---|
| 1284 | + * @vtag: vm tag |
|---|
| 1285 | + * |
|---|
| 1286 | + * Return: |
|---|
| 1287 | + * * Pointer to allocated struct - on success |
|---|
| 1288 | + * * ERR_PTR(-ENOMEM) on memory allocation failure |
|---|
| 1289 | + */ |
|---|
| 1290 | +struct mei_cl_vtag *mei_cl_vtag_alloc(struct file *fp, u8 vtag) |
|---|
| 1291 | +{ |
|---|
| 1292 | + struct mei_cl_vtag *cl_vtag; |
|---|
| 1293 | + |
|---|
| 1294 | + cl_vtag = kzalloc(sizeof(*cl_vtag), GFP_KERNEL); |
|---|
| 1295 | + if (!cl_vtag) |
|---|
| 1296 | + return ERR_PTR(-ENOMEM); |
|---|
| 1297 | + |
|---|
| 1298 | + INIT_LIST_HEAD(&cl_vtag->list); |
|---|
| 1299 | + cl_vtag->vtag = vtag; |
|---|
| 1300 | + cl_vtag->fp = fp; |
|---|
| 1301 | + |
|---|
| 1302 | + return cl_vtag; |
|---|
| 1303 | +} |
|---|
| 1304 | + |
|---|
| 1305 | +/** |
|---|
| 1306 | + * mei_cl_fp_by_vtag - obtain the file pointer by vtag |
|---|
| 1307 | + * |
|---|
| 1308 | + * @cl: host client |
|---|
| 1309 | + * @vtag: vm tag |
|---|
| 1310 | + * |
|---|
| 1311 | + * Return: |
|---|
| 1312 | + * * A file pointer - on success |
|---|
| 1313 | + * * ERR_PTR(-ENOENT) if vtag is not found in the client vtag list |
|---|
| 1314 | + */ |
|---|
| 1315 | +const struct file *mei_cl_fp_by_vtag(const struct mei_cl *cl, u8 vtag) |
|---|
| 1316 | +{ |
|---|
| 1317 | + struct mei_cl_vtag *vtag_l; |
|---|
| 1318 | + |
|---|
| 1319 | + list_for_each_entry(vtag_l, &cl->vtag_map, list) |
|---|
| 1320 | + if (vtag_l->vtag == vtag) |
|---|
| 1321 | + return vtag_l->fp; |
|---|
| 1322 | + |
|---|
| 1323 | + return ERR_PTR(-ENOENT); |
|---|
| 1324 | +} |
|---|
| 1325 | + |
|---|
| 1326 | +/** |
|---|
| 1327 | + * mei_cl_reset_read_by_vtag - reset pending_read flag by given vtag |
|---|
| 1328 | + * |
|---|
| 1329 | + * @cl: host client |
|---|
| 1330 | + * @vtag: vm tag |
|---|
| 1331 | + */ |
|---|
| 1332 | +static void mei_cl_reset_read_by_vtag(const struct mei_cl *cl, u8 vtag) |
|---|
| 1333 | +{ |
|---|
| 1334 | + struct mei_cl_vtag *vtag_l; |
|---|
| 1335 | + |
|---|
| 1336 | + list_for_each_entry(vtag_l, &cl->vtag_map, list) { |
|---|
| 1337 | + if (vtag_l->vtag == vtag) { |
|---|
| 1338 | + vtag_l->pending_read = false; |
|---|
| 1339 | + break; |
|---|
| 1340 | + } |
|---|
| 1341 | + } |
|---|
| 1342 | +} |
|---|
| 1343 | + |
|---|
| 1344 | +/** |
|---|
| 1345 | + * mei_cl_read_vtag_add_fc - add flow control for next pending reader |
|---|
| 1346 | + * in the vtag list |
|---|
| 1347 | + * |
|---|
| 1348 | + * @cl: host client |
|---|
| 1349 | + */ |
|---|
| 1350 | +static void mei_cl_read_vtag_add_fc(struct mei_cl *cl) |
|---|
| 1351 | +{ |
|---|
| 1352 | + struct mei_cl_vtag *cl_vtag; |
|---|
| 1353 | + |
|---|
| 1354 | + list_for_each_entry(cl_vtag, &cl->vtag_map, list) { |
|---|
| 1355 | + if (cl_vtag->pending_read) { |
|---|
| 1356 | + if (mei_cl_enqueue_ctrl_wr_cb(cl, |
|---|
| 1357 | + mei_cl_mtu(cl), |
|---|
| 1358 | + MEI_FOP_READ, |
|---|
| 1359 | + cl_vtag->fp)) |
|---|
| 1360 | + cl->rx_flow_ctrl_creds++; |
|---|
| 1361 | + break; |
|---|
| 1362 | + } |
|---|
| 1363 | + } |
|---|
| 1364 | +} |
|---|
| 1365 | + |
|---|
| 1366 | +/** |
|---|
| 1367 | + * mei_cl_vt_support_check - check if client support vtags |
|---|
| 1368 | + * |
|---|
| 1369 | + * @cl: host client |
|---|
| 1370 | + * |
|---|
| 1371 | + * Return: |
|---|
| 1372 | + * * 0 - supported, or not connected at all |
|---|
| 1373 | + * * -EOPNOTSUPP - vtags are not supported by client |
|---|
| 1374 | + */ |
|---|
| 1375 | +int mei_cl_vt_support_check(const struct mei_cl *cl) |
|---|
| 1376 | +{ |
|---|
| 1377 | + struct mei_device *dev = cl->dev; |
|---|
| 1378 | + |
|---|
| 1379 | + if (!dev->hbm_f_vt_supported) |
|---|
| 1380 | + return -EOPNOTSUPP; |
|---|
| 1381 | + |
|---|
| 1382 | + if (!cl->me_cl) |
|---|
| 1383 | + return 0; |
|---|
| 1384 | + |
|---|
| 1385 | + return cl->me_cl->props.vt_supported ? 0 : -EOPNOTSUPP; |
|---|
| 1386 | +} |
|---|
| 1387 | + |
|---|
| 1388 | +/** |
|---|
| 1389 | + * mei_cl_add_rd_completed - add read completed callback to list with lock |
|---|
| 1390 | + * and vtag check |
|---|
| 1391 | + * |
|---|
| 1392 | + * @cl: host client |
|---|
| 1393 | + * @cb: callback block |
|---|
| 1394 | + * |
|---|
| 1395 | + */ |
|---|
| 1396 | +void mei_cl_add_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb) |
|---|
| 1397 | +{ |
|---|
| 1398 | + const struct file *fp; |
|---|
| 1399 | + |
|---|
| 1400 | + if (!mei_cl_vt_support_check(cl)) { |
|---|
| 1401 | + fp = mei_cl_fp_by_vtag(cl, cb->vtag); |
|---|
| 1402 | + if (IS_ERR(fp)) { |
|---|
| 1403 | + /* client already disconnected, discarding */ |
|---|
| 1404 | + mei_io_cb_free(cb); |
|---|
| 1405 | + return; |
|---|
| 1406 | + } |
|---|
| 1407 | + cb->fp = fp; |
|---|
| 1408 | + mei_cl_reset_read_by_vtag(cl, cb->vtag); |
|---|
| 1409 | + mei_cl_read_vtag_add_fc(cl); |
|---|
| 1410 | + } |
|---|
| 1411 | + |
|---|
| 1412 | + spin_lock(&cl->rd_completed_lock); |
|---|
| 1413 | + list_add_tail(&cb->list, &cl->rd_completed); |
|---|
| 1414 | + spin_unlock(&cl->rd_completed_lock); |
|---|
| 1415 | +} |
|---|
| 1416 | + |
|---|
| 1417 | +/** |
|---|
| 1418 | + * mei_cl_del_rd_completed - free read completed callback with lock |
|---|
| 1419 | + * |
|---|
| 1420 | + * @cl: host client |
|---|
| 1421 | + * @cb: callback block |
|---|
| 1422 | + * |
|---|
| 1423 | + */ |
|---|
| 1424 | +void mei_cl_del_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb) |
|---|
| 1425 | +{ |
|---|
| 1426 | + spin_lock(&cl->rd_completed_lock); |
|---|
| 1427 | + mei_io_cb_free(cb); |
|---|
| 1428 | + spin_unlock(&cl->rd_completed_lock); |
|---|
| 1429 | +} |
|---|
| 1430 | + |
|---|
| 1431 | +/** |
|---|
| 1256 | 1432 | * mei_cl_notify_fop2req - convert fop to proper request |
|---|
| 1257 | 1433 | * |
|---|
| 1258 | 1434 | * @fop: client notification start response command |
|---|
| .. | .. |
|---|
| 1376 | 1552 | |
|---|
| 1377 | 1553 | mutex_unlock(&dev->device_lock); |
|---|
| 1378 | 1554 | wait_event_timeout(cl->wait, |
|---|
| 1379 | | - cl->notify_en == request || !mei_cl_is_connected(cl), |
|---|
| 1555 | + cl->notify_en == request || |
|---|
| 1556 | + cl->status || |
|---|
| 1557 | + !mei_cl_is_connected(cl), |
|---|
| 1380 | 1558 | mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); |
|---|
| 1381 | 1559 | mutex_lock(&dev->device_lock); |
|---|
| 1382 | 1560 | |
|---|
| .. | .. |
|---|
| 1505 | 1683 | return 0; |
|---|
| 1506 | 1684 | |
|---|
| 1507 | 1685 | /* HW currently supports only one pending read */ |
|---|
| 1508 | | - if (cl->rx_flow_ctrl_creds) |
|---|
| 1686 | + if (cl->rx_flow_ctrl_creds) { |
|---|
| 1687 | + mei_cl_set_read_by_fp(cl, fp); |
|---|
| 1509 | 1688 | return -EBUSY; |
|---|
| 1689 | + } |
|---|
| 1510 | 1690 | |
|---|
| 1511 | 1691 | cb = mei_cl_enqueue_ctrl_wr_cb(cl, length, MEI_FOP_READ, fp); |
|---|
| 1512 | 1692 | if (!cb) |
|---|
| 1513 | 1693 | return -ENOMEM; |
|---|
| 1694 | + |
|---|
| 1695 | + mei_cl_set_read_by_fp(cl, fp); |
|---|
| 1514 | 1696 | |
|---|
| 1515 | 1697 | rets = pm_runtime_get(dev->dev); |
|---|
| 1516 | 1698 | if (rets < 0 && rets != -EINPROGRESS) { |
|---|
| .. | .. |
|---|
| 1540 | 1722 | return rets; |
|---|
| 1541 | 1723 | } |
|---|
| 1542 | 1724 | |
|---|
| 1543 | | -/** |
|---|
| 1544 | | - * mei_msg_hdr_init - initialize mei message header |
|---|
| 1545 | | - * |
|---|
| 1546 | | - * @mei_hdr: mei message header |
|---|
| 1547 | | - * @cb: message callback structure |
|---|
| 1548 | | - */ |
|---|
| 1549 | | -static void mei_msg_hdr_init(struct mei_msg_hdr *mei_hdr, struct mei_cl_cb *cb) |
|---|
| 1725 | +static inline u8 mei_ext_hdr_set_vtag(struct mei_ext_hdr *ext, u8 vtag) |
|---|
| 1550 | 1726 | { |
|---|
| 1727 | + ext->type = MEI_EXT_HDR_VTAG; |
|---|
| 1728 | + ext->ext_payload[0] = vtag; |
|---|
| 1729 | + ext->length = mei_data2slots(sizeof(*ext)); |
|---|
| 1730 | + return ext->length; |
|---|
| 1731 | +} |
|---|
| 1732 | + |
|---|
| 1733 | +/** |
|---|
| 1734 | + * mei_msg_hdr_init - allocate and initialize mei message header |
|---|
| 1735 | + * |
|---|
| 1736 | + * @cb: message callback structure |
|---|
| 1737 | + * |
|---|
| 1738 | + * Return: a pointer to initialized header |
|---|
| 1739 | + */ |
|---|
| 1740 | +static struct mei_msg_hdr *mei_msg_hdr_init(const struct mei_cl_cb *cb) |
|---|
| 1741 | +{ |
|---|
| 1742 | + size_t hdr_len; |
|---|
| 1743 | + struct mei_ext_meta_hdr *meta; |
|---|
| 1744 | + struct mei_ext_hdr *ext; |
|---|
| 1745 | + struct mei_msg_hdr *mei_hdr; |
|---|
| 1746 | + bool is_ext, is_vtag; |
|---|
| 1747 | + |
|---|
| 1748 | + if (!cb) |
|---|
| 1749 | + return ERR_PTR(-EINVAL); |
|---|
| 1750 | + |
|---|
| 1751 | + /* Extended header for vtag is attached only on the first fragment */ |
|---|
| 1752 | + is_vtag = (cb->vtag && cb->buf_idx == 0); |
|---|
| 1753 | + is_ext = is_vtag; |
|---|
| 1754 | + |
|---|
| 1755 | + /* Compute extended header size */ |
|---|
| 1756 | + hdr_len = sizeof(*mei_hdr); |
|---|
| 1757 | + |
|---|
| 1758 | + if (!is_ext) |
|---|
| 1759 | + goto setup_hdr; |
|---|
| 1760 | + |
|---|
| 1761 | + hdr_len += sizeof(*meta); |
|---|
| 1762 | + if (is_vtag) |
|---|
| 1763 | + hdr_len += sizeof(*ext); |
|---|
| 1764 | + |
|---|
| 1765 | +setup_hdr: |
|---|
| 1766 | + mei_hdr = kzalloc(hdr_len, GFP_KERNEL); |
|---|
| 1767 | + if (!mei_hdr) |
|---|
| 1768 | + return ERR_PTR(-ENOMEM); |
|---|
| 1769 | + |
|---|
| 1551 | 1770 | mei_hdr->host_addr = mei_cl_host_addr(cb->cl); |
|---|
| 1552 | 1771 | mei_hdr->me_addr = mei_cl_me_id(cb->cl); |
|---|
| 1553 | | - mei_hdr->length = 0; |
|---|
| 1554 | | - mei_hdr->reserved = 0; |
|---|
| 1555 | | - mei_hdr->msg_complete = 0; |
|---|
| 1556 | | - mei_hdr->dma_ring = 0; |
|---|
| 1557 | 1772 | mei_hdr->internal = cb->internal; |
|---|
| 1773 | + mei_hdr->extended = is_ext; |
|---|
| 1774 | + |
|---|
| 1775 | + if (!is_ext) |
|---|
| 1776 | + goto out; |
|---|
| 1777 | + |
|---|
| 1778 | + meta = (struct mei_ext_meta_hdr *)mei_hdr->extension; |
|---|
| 1779 | + if (is_vtag) { |
|---|
| 1780 | + meta->count++; |
|---|
| 1781 | + meta->size += mei_ext_hdr_set_vtag(meta->hdrs, cb->vtag); |
|---|
| 1782 | + } |
|---|
| 1783 | +out: |
|---|
| 1784 | + mei_hdr->length = hdr_len - sizeof(*mei_hdr); |
|---|
| 1785 | + return mei_hdr; |
|---|
| 1558 | 1786 | } |
|---|
| 1559 | 1787 | |
|---|
| 1560 | 1788 | /** |
|---|
| .. | .. |
|---|
| 1572 | 1800 | { |
|---|
| 1573 | 1801 | struct mei_device *dev; |
|---|
| 1574 | 1802 | struct mei_msg_data *buf; |
|---|
| 1575 | | - struct mei_msg_hdr mei_hdr; |
|---|
| 1576 | | - size_t hdr_len = sizeof(mei_hdr); |
|---|
| 1577 | | - size_t len; |
|---|
| 1578 | | - size_t hbuf_len; |
|---|
| 1803 | + struct mei_msg_hdr *mei_hdr = NULL; |
|---|
| 1804 | + size_t hdr_len; |
|---|
| 1805 | + size_t hbuf_len, dr_len; |
|---|
| 1806 | + size_t buf_len; |
|---|
| 1807 | + size_t data_len; |
|---|
| 1579 | 1808 | int hbuf_slots; |
|---|
| 1809 | + u32 dr_slots; |
|---|
| 1810 | + u32 dma_len; |
|---|
| 1580 | 1811 | int rets; |
|---|
| 1581 | 1812 | bool first_chunk; |
|---|
| 1813 | + const void *data; |
|---|
| 1582 | 1814 | |
|---|
| 1583 | 1815 | if (WARN_ON(!cl || !cl->dev)) |
|---|
| 1584 | 1816 | return -ENODEV; |
|---|
| .. | .. |
|---|
| 1598 | 1830 | return 0; |
|---|
| 1599 | 1831 | } |
|---|
| 1600 | 1832 | |
|---|
| 1601 | | - len = buf->size - cb->buf_idx; |
|---|
| 1833 | + buf_len = buf->size - cb->buf_idx; |
|---|
| 1834 | + data = buf->data + cb->buf_idx; |
|---|
| 1602 | 1835 | hbuf_slots = mei_hbuf_empty_slots(dev); |
|---|
| 1603 | 1836 | if (hbuf_slots < 0) { |
|---|
| 1604 | 1837 | rets = -EOVERFLOW; |
|---|
| 1605 | 1838 | goto err; |
|---|
| 1606 | 1839 | } |
|---|
| 1607 | 1840 | |
|---|
| 1608 | | - hbuf_len = mei_slots2data(hbuf_slots); |
|---|
| 1841 | + hbuf_len = mei_slots2data(hbuf_slots) & MEI_MSG_MAX_LEN_MASK; |
|---|
| 1842 | + dr_slots = mei_dma_ring_empty_slots(dev); |
|---|
| 1843 | + dr_len = mei_slots2data(dr_slots); |
|---|
| 1609 | 1844 | |
|---|
| 1610 | | - mei_msg_hdr_init(&mei_hdr, cb); |
|---|
| 1845 | + mei_hdr = mei_msg_hdr_init(cb); |
|---|
| 1846 | + if (IS_ERR(mei_hdr)) { |
|---|
| 1847 | + rets = PTR_ERR(mei_hdr); |
|---|
| 1848 | + mei_hdr = NULL; |
|---|
| 1849 | + goto err; |
|---|
| 1850 | + } |
|---|
| 1851 | + |
|---|
| 1852 | + cl_dbg(dev, cl, "Extended Header %d vtag = %d\n", |
|---|
| 1853 | + mei_hdr->extended, cb->vtag); |
|---|
| 1854 | + |
|---|
| 1855 | + hdr_len = sizeof(*mei_hdr) + mei_hdr->length; |
|---|
| 1611 | 1856 | |
|---|
| 1612 | 1857 | /** |
|---|
| 1613 | 1858 | * Split the message only if we can write the whole host buffer |
|---|
| 1614 | 1859 | * otherwise wait for next time the host buffer is empty. |
|---|
| 1615 | 1860 | */ |
|---|
| 1616 | | - if (len + hdr_len <= hbuf_len) { |
|---|
| 1617 | | - mei_hdr.length = len; |
|---|
| 1618 | | - mei_hdr.msg_complete = 1; |
|---|
| 1861 | + if (hdr_len + buf_len <= hbuf_len) { |
|---|
| 1862 | + data_len = buf_len; |
|---|
| 1863 | + mei_hdr->msg_complete = 1; |
|---|
| 1864 | + } else if (dr_slots && hbuf_len >= hdr_len + sizeof(dma_len)) { |
|---|
| 1865 | + mei_hdr->dma_ring = 1; |
|---|
| 1866 | + if (buf_len > dr_len) |
|---|
| 1867 | + buf_len = dr_len; |
|---|
| 1868 | + else |
|---|
| 1869 | + mei_hdr->msg_complete = 1; |
|---|
| 1870 | + |
|---|
| 1871 | + data_len = sizeof(dma_len); |
|---|
| 1872 | + dma_len = buf_len; |
|---|
| 1873 | + data = &dma_len; |
|---|
| 1619 | 1874 | } else if ((u32)hbuf_slots == mei_hbuf_depth(dev)) { |
|---|
| 1620 | | - mei_hdr.length = hbuf_len - hdr_len; |
|---|
| 1875 | + buf_len = hbuf_len - hdr_len; |
|---|
| 1876 | + data_len = buf_len; |
|---|
| 1621 | 1877 | } else { |
|---|
| 1878 | + kfree(mei_hdr); |
|---|
| 1622 | 1879 | return 0; |
|---|
| 1623 | 1880 | } |
|---|
| 1881 | + mei_hdr->length += data_len; |
|---|
| 1624 | 1882 | |
|---|
| 1625 | | - cl_dbg(dev, cl, "buf: size = %zu idx = %zu\n", |
|---|
| 1626 | | - cb->buf.size, cb->buf_idx); |
|---|
| 1883 | + if (mei_hdr->dma_ring) |
|---|
| 1884 | + mei_dma_ring_write(dev, buf->data + cb->buf_idx, buf_len); |
|---|
| 1885 | + rets = mei_write_message(dev, mei_hdr, hdr_len, data, data_len); |
|---|
| 1627 | 1886 | |
|---|
| 1628 | | - rets = mei_write_message(dev, &mei_hdr, hdr_len, |
|---|
| 1629 | | - buf->data + cb->buf_idx, mei_hdr.length); |
|---|
| 1630 | 1887 | if (rets) |
|---|
| 1631 | 1888 | goto err; |
|---|
| 1632 | 1889 | |
|---|
| 1633 | 1890 | cl->status = 0; |
|---|
| 1634 | 1891 | cl->writing_state = MEI_WRITING; |
|---|
| 1635 | | - cb->buf_idx += mei_hdr.length; |
|---|
| 1892 | + cb->buf_idx += buf_len; |
|---|
| 1636 | 1893 | |
|---|
| 1637 | 1894 | if (first_chunk) { |
|---|
| 1638 | 1895 | if (mei_cl_tx_flow_ctrl_creds_reduce(cl)) { |
|---|
| .. | .. |
|---|
| 1641 | 1898 | } |
|---|
| 1642 | 1899 | } |
|---|
| 1643 | 1900 | |
|---|
| 1644 | | - if (mei_hdr.msg_complete) |
|---|
| 1901 | + if (mei_hdr->msg_complete) |
|---|
| 1645 | 1902 | list_move_tail(&cb->list, &dev->write_waiting_list); |
|---|
| 1646 | 1903 | |
|---|
| 1904 | + kfree(mei_hdr); |
|---|
| 1647 | 1905 | return 0; |
|---|
| 1648 | 1906 | |
|---|
| 1649 | 1907 | err: |
|---|
| 1908 | + kfree(mei_hdr); |
|---|
| 1650 | 1909 | cl->status = rets; |
|---|
| 1651 | 1910 | list_move_tail(&cb->list, cmpl_list); |
|---|
| 1652 | 1911 | return rets; |
|---|
| .. | .. |
|---|
| 1665 | 1924 | { |
|---|
| 1666 | 1925 | struct mei_device *dev; |
|---|
| 1667 | 1926 | struct mei_msg_data *buf; |
|---|
| 1668 | | - struct mei_msg_hdr mei_hdr; |
|---|
| 1669 | | - size_t hdr_len = sizeof(mei_hdr); |
|---|
| 1670 | | - size_t len; |
|---|
| 1671 | | - size_t hbuf_len; |
|---|
| 1927 | + struct mei_msg_hdr *mei_hdr = NULL; |
|---|
| 1928 | + size_t hdr_len; |
|---|
| 1929 | + size_t hbuf_len, dr_len; |
|---|
| 1930 | + size_t buf_len; |
|---|
| 1931 | + size_t data_len; |
|---|
| 1672 | 1932 | int hbuf_slots; |
|---|
| 1933 | + u32 dr_slots; |
|---|
| 1934 | + u32 dma_len; |
|---|
| 1673 | 1935 | ssize_t rets; |
|---|
| 1674 | 1936 | bool blocking; |
|---|
| 1937 | + const void *data; |
|---|
| 1675 | 1938 | |
|---|
| 1676 | 1939 | if (WARN_ON(!cl || !cl->dev)) |
|---|
| 1677 | 1940 | return -ENODEV; |
|---|
| .. | .. |
|---|
| 1682 | 1945 | dev = cl->dev; |
|---|
| 1683 | 1946 | |
|---|
| 1684 | 1947 | buf = &cb->buf; |
|---|
| 1685 | | - len = buf->size; |
|---|
| 1686 | | - blocking = cb->blocking; |
|---|
| 1948 | + buf_len = buf->size; |
|---|
| 1687 | 1949 | |
|---|
| 1688 | | - cl_dbg(dev, cl, "len=%zd\n", len); |
|---|
| 1950 | + cl_dbg(dev, cl, "buf_len=%zd\n", buf_len); |
|---|
| 1951 | + |
|---|
| 1952 | + blocking = cb->blocking; |
|---|
| 1953 | + data = buf->data; |
|---|
| 1689 | 1954 | |
|---|
| 1690 | 1955 | rets = pm_runtime_get(dev->dev); |
|---|
| 1691 | 1956 | if (rets < 0 && rets != -EINPROGRESS) { |
|---|
| .. | .. |
|---|
| 1702 | 1967 | if (rets < 0) |
|---|
| 1703 | 1968 | goto err; |
|---|
| 1704 | 1969 | |
|---|
| 1705 | | - mei_msg_hdr_init(&mei_hdr, cb); |
|---|
| 1970 | + mei_hdr = mei_msg_hdr_init(cb); |
|---|
| 1971 | + if (IS_ERR(mei_hdr)) { |
|---|
| 1972 | + rets = -PTR_ERR(mei_hdr); |
|---|
| 1973 | + mei_hdr = NULL; |
|---|
| 1974 | + goto err; |
|---|
| 1975 | + } |
|---|
| 1976 | + |
|---|
| 1977 | + cl_dbg(dev, cl, "Extended Header %d vtag = %d\n", |
|---|
| 1978 | + mei_hdr->extended, cb->vtag); |
|---|
| 1979 | + |
|---|
| 1980 | + hdr_len = sizeof(*mei_hdr) + mei_hdr->length; |
|---|
| 1706 | 1981 | |
|---|
| 1707 | 1982 | if (rets == 0) { |
|---|
| 1708 | 1983 | cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); |
|---|
| 1709 | | - rets = len; |
|---|
| 1984 | + rets = buf_len; |
|---|
| 1710 | 1985 | goto out; |
|---|
| 1711 | 1986 | } |
|---|
| 1712 | 1987 | |
|---|
| 1713 | 1988 | if (!mei_hbuf_acquire(dev)) { |
|---|
| 1714 | 1989 | cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n"); |
|---|
| 1715 | | - rets = len; |
|---|
| 1990 | + rets = buf_len; |
|---|
| 1716 | 1991 | goto out; |
|---|
| 1717 | 1992 | } |
|---|
| 1718 | 1993 | |
|---|
| .. | .. |
|---|
| 1722 | 1997 | goto out; |
|---|
| 1723 | 1998 | } |
|---|
| 1724 | 1999 | |
|---|
| 1725 | | - hbuf_len = mei_slots2data(hbuf_slots); |
|---|
| 2000 | + hbuf_len = mei_slots2data(hbuf_slots) & MEI_MSG_MAX_LEN_MASK; |
|---|
| 2001 | + dr_slots = mei_dma_ring_empty_slots(dev); |
|---|
| 2002 | + dr_len = mei_slots2data(dr_slots); |
|---|
| 1726 | 2003 | |
|---|
| 1727 | | - if (len + hdr_len <= hbuf_len) { |
|---|
| 1728 | | - mei_hdr.length = len; |
|---|
| 1729 | | - mei_hdr.msg_complete = 1; |
|---|
| 2004 | + if (hdr_len + buf_len <= hbuf_len) { |
|---|
| 2005 | + data_len = buf_len; |
|---|
| 2006 | + mei_hdr->msg_complete = 1; |
|---|
| 2007 | + } else if (dr_slots && hbuf_len >= hdr_len + sizeof(dma_len)) { |
|---|
| 2008 | + mei_hdr->dma_ring = 1; |
|---|
| 2009 | + if (buf_len > dr_len) |
|---|
| 2010 | + buf_len = dr_len; |
|---|
| 2011 | + else |
|---|
| 2012 | + mei_hdr->msg_complete = 1; |
|---|
| 2013 | + |
|---|
| 2014 | + data_len = sizeof(dma_len); |
|---|
| 2015 | + dma_len = buf_len; |
|---|
| 2016 | + data = &dma_len; |
|---|
| 1730 | 2017 | } else { |
|---|
| 1731 | | - mei_hdr.length = hbuf_len - hdr_len; |
|---|
| 2018 | + buf_len = hbuf_len - hdr_len; |
|---|
| 2019 | + data_len = buf_len; |
|---|
| 1732 | 2020 | } |
|---|
| 1733 | 2021 | |
|---|
| 1734 | | - rets = mei_write_message(dev, &mei_hdr, hdr_len, |
|---|
| 1735 | | - buf->data, mei_hdr.length); |
|---|
| 2022 | + mei_hdr->length += data_len; |
|---|
| 2023 | + |
|---|
| 2024 | + if (mei_hdr->dma_ring) |
|---|
| 2025 | + mei_dma_ring_write(dev, buf->data, buf_len); |
|---|
| 2026 | + rets = mei_write_message(dev, mei_hdr, hdr_len, data, data_len); |
|---|
| 2027 | + |
|---|
| 1736 | 2028 | if (rets) |
|---|
| 1737 | 2029 | goto err; |
|---|
| 1738 | 2030 | |
|---|
| .. | .. |
|---|
| 1741 | 2033 | goto err; |
|---|
| 1742 | 2034 | |
|---|
| 1743 | 2035 | cl->writing_state = MEI_WRITING; |
|---|
| 1744 | | - cb->buf_idx = mei_hdr.length; |
|---|
| 2036 | + cb->buf_idx = buf_len; |
|---|
| 2037 | + /* restore return value */ |
|---|
| 2038 | + buf_len = buf->size; |
|---|
| 1745 | 2039 | |
|---|
| 1746 | 2040 | out: |
|---|
| 1747 | | - if (mei_hdr.msg_complete) |
|---|
| 2041 | + if (mei_hdr->msg_complete) |
|---|
| 1748 | 2042 | mei_tx_cb_enqueue(cb, &dev->write_waiting_list); |
|---|
| 1749 | 2043 | else |
|---|
| 1750 | 2044 | mei_tx_cb_enqueue(cb, &dev->write_list); |
|---|
| .. | .. |
|---|
| 1769 | 2063 | } |
|---|
| 1770 | 2064 | } |
|---|
| 1771 | 2065 | |
|---|
| 1772 | | - rets = len; |
|---|
| 2066 | + rets = buf_len; |
|---|
| 1773 | 2067 | err: |
|---|
| 1774 | 2068 | cl_dbg(dev, cl, "rpm: autosuspend\n"); |
|---|
| 1775 | 2069 | pm_runtime_mark_last_busy(dev->dev); |
|---|
| .. | .. |
|---|
| 1777 | 2071 | free: |
|---|
| 1778 | 2072 | mei_io_cb_free(cb); |
|---|
| 1779 | 2073 | |
|---|
| 2074 | + kfree(mei_hdr); |
|---|
| 2075 | + |
|---|
| 1780 | 2076 | return rets; |
|---|
| 1781 | 2077 | } |
|---|
| 1782 | | - |
|---|
| 1783 | 2078 | |
|---|
| 1784 | 2079 | /** |
|---|
| 1785 | 2080 | * mei_cl_complete - processes completed operation for a client |
|---|
| .. | .. |
|---|
| 1804 | 2099 | break; |
|---|
| 1805 | 2100 | |
|---|
| 1806 | 2101 | case MEI_FOP_READ: |
|---|
| 1807 | | - list_add_tail(&cb->list, &cl->rd_completed); |
|---|
| 2102 | + mei_cl_add_rd_completed(cl, cb); |
|---|
| 1808 | 2103 | if (!mei_cl_is_fixed_address(cl) && |
|---|
| 1809 | 2104 | !WARN_ON(!cl->rx_flow_ctrl_creds)) |
|---|
| 1810 | 2105 | cl->rx_flow_ctrl_creds--; |
|---|