.. | .. |
---|
| 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--; |
---|