| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 3 | + * Copyright (c) 2012-2019, Intel Corporation. All rights reserved. |
|---|
| 2 | 4 | * Intel Management Engine Interface (Intel MEI) Linux driver |
|---|
| 3 | | - * Copyright (c) 2012-2013, Intel Corporation. |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 6 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 7 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 10 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 11 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 12 | | - * more details. |
|---|
| 13 | | - * |
|---|
| 14 | 5 | */ |
|---|
| 15 | 6 | |
|---|
| 16 | 7 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 28 | 19 | #include "client.h" |
|---|
| 29 | 20 | |
|---|
| 30 | 21 | #define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver) |
|---|
| 31 | | -#define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev) |
|---|
| 32 | 22 | |
|---|
| 33 | 23 | /** |
|---|
| 34 | 24 | * __mei_cl_send - internal client send (write) |
|---|
| .. | .. |
|---|
| 162 | 152 | if (timeout) { |
|---|
| 163 | 153 | rets = wait_event_interruptible_timeout |
|---|
| 164 | 154 | (cl->rx_wait, |
|---|
| 165 | | - (!list_empty(&cl->rd_completed)) || |
|---|
| 155 | + mei_cl_read_cb(cl, NULL) || |
|---|
| 166 | 156 | (!mei_cl_is_connected(cl)), |
|---|
| 167 | 157 | msecs_to_jiffies(timeout)); |
|---|
| 168 | 158 | if (rets == 0) |
|---|
| .. | .. |
|---|
| 175 | 165 | } else { |
|---|
| 176 | 166 | if (wait_event_interruptible |
|---|
| 177 | 167 | (cl->rx_wait, |
|---|
| 178 | | - (!list_empty(&cl->rd_completed)) || |
|---|
| 168 | + mei_cl_read_cb(cl, NULL) || |
|---|
| 179 | 169 | (!mei_cl_is_connected(cl)))) { |
|---|
| 180 | 170 | if (signal_pending(current)) |
|---|
| 181 | 171 | return -EINTR; |
|---|
| .. | .. |
|---|
| 208 | 198 | rets = r_length; |
|---|
| 209 | 199 | |
|---|
| 210 | 200 | free: |
|---|
| 211 | | - mei_io_cb_free(cb); |
|---|
| 201 | + mei_cl_del_rd_completed(cl, cb); |
|---|
| 212 | 202 | out: |
|---|
| 213 | 203 | mutex_unlock(&bus->device_lock); |
|---|
| 214 | 204 | |
|---|
| .. | .. |
|---|
| 506 | 496 | } |
|---|
| 507 | 497 | |
|---|
| 508 | 498 | /** |
|---|
| 499 | + * mei_cl_bus_vtag - get bus vtag entry wrapper |
|---|
| 500 | + * The tag for bus client is always first. |
|---|
| 501 | + * |
|---|
| 502 | + * @cl: host client |
|---|
| 503 | + * |
|---|
| 504 | + * Return: bus vtag or NULL |
|---|
| 505 | + */ |
|---|
| 506 | +static inline struct mei_cl_vtag *mei_cl_bus_vtag(struct mei_cl *cl) |
|---|
| 507 | +{ |
|---|
| 508 | + return list_first_entry_or_null(&cl->vtag_map, |
|---|
| 509 | + struct mei_cl_vtag, list); |
|---|
| 510 | +} |
|---|
| 511 | + |
|---|
| 512 | +/** |
|---|
| 513 | + * mei_cl_bus_vtag_alloc - add bus client entry to vtag map |
|---|
| 514 | + * |
|---|
| 515 | + * @cldev: me client device |
|---|
| 516 | + * |
|---|
| 517 | + * Return: |
|---|
| 518 | + * * 0 on success |
|---|
| 519 | + * * -ENOMEM if memory allocation failed |
|---|
| 520 | + */ |
|---|
| 521 | +static int mei_cl_bus_vtag_alloc(struct mei_cl_device *cldev) |
|---|
| 522 | +{ |
|---|
| 523 | + struct mei_cl *cl = cldev->cl; |
|---|
| 524 | + struct mei_cl_vtag *cl_vtag; |
|---|
| 525 | + |
|---|
| 526 | + /* |
|---|
| 527 | + * Bail out if the client does not supports vtags |
|---|
| 528 | + * or has already allocated one |
|---|
| 529 | + */ |
|---|
| 530 | + if (mei_cl_vt_support_check(cl) || mei_cl_bus_vtag(cl)) |
|---|
| 531 | + return 0; |
|---|
| 532 | + |
|---|
| 533 | + cl_vtag = mei_cl_vtag_alloc(NULL, 0); |
|---|
| 534 | + if (IS_ERR(cl_vtag)) |
|---|
| 535 | + return -ENOMEM; |
|---|
| 536 | + |
|---|
| 537 | + list_add_tail(&cl_vtag->list, &cl->vtag_map); |
|---|
| 538 | + |
|---|
| 539 | + return 0; |
|---|
| 540 | +} |
|---|
| 541 | + |
|---|
| 542 | +/** |
|---|
| 543 | + * mei_cl_bus_vtag_free - remove the bus entry from vtag map |
|---|
| 544 | + * |
|---|
| 545 | + * @cldev: me client device |
|---|
| 546 | + */ |
|---|
| 547 | +static void mei_cl_bus_vtag_free(struct mei_cl_device *cldev) |
|---|
| 548 | +{ |
|---|
| 549 | + struct mei_cl *cl = cldev->cl; |
|---|
| 550 | + struct mei_cl_vtag *cl_vtag; |
|---|
| 551 | + |
|---|
| 552 | + cl_vtag = mei_cl_bus_vtag(cl); |
|---|
| 553 | + if (!cl_vtag) |
|---|
| 554 | + return; |
|---|
| 555 | + |
|---|
| 556 | + list_del(&cl_vtag->list); |
|---|
| 557 | + kfree(cl_vtag); |
|---|
| 558 | +} |
|---|
| 559 | + |
|---|
| 560 | +/** |
|---|
| 509 | 561 | * mei_cldev_enable - enable me client device |
|---|
| 510 | 562 | * create connection with me client |
|---|
| 511 | 563 | * |
|---|
| .. | .. |
|---|
| 541 | 593 | goto out; |
|---|
| 542 | 594 | } |
|---|
| 543 | 595 | |
|---|
| 596 | + ret = mei_cl_bus_vtag_alloc(cldev); |
|---|
| 597 | + if (ret) |
|---|
| 598 | + goto out; |
|---|
| 599 | + |
|---|
| 544 | 600 | ret = mei_cl_connect(cl, cldev->me_cl, NULL); |
|---|
| 545 | | - if (ret < 0) |
|---|
| 601 | + if (ret < 0) { |
|---|
| 546 | 602 | dev_err(&cldev->dev, "cannot connect\n"); |
|---|
| 603 | + mei_cl_bus_vtag_free(cldev); |
|---|
| 604 | + } |
|---|
| 547 | 605 | |
|---|
| 548 | 606 | out: |
|---|
| 549 | 607 | mutex_unlock(&bus->device_lock); |
|---|
| .. | .. |
|---|
| 595 | 653 | mei_cldev_unregister_callbacks(cldev); |
|---|
| 596 | 654 | |
|---|
| 597 | 655 | mutex_lock(&bus->device_lock); |
|---|
| 656 | + |
|---|
| 657 | + mei_cl_bus_vtag_free(cldev); |
|---|
| 598 | 658 | |
|---|
| 599 | 659 | if (!mei_cl_is_connected(cl)) { |
|---|
| 600 | 660 | dev_dbg(bus->dev, "Already disconnected\n"); |
|---|
| .. | .. |
|---|
| 774 | 834 | struct mei_cl_device *cldev = to_mei_cl_device(dev); |
|---|
| 775 | 835 | const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); |
|---|
| 776 | 836 | |
|---|
| 777 | | - return scnprintf(buf, PAGE_SIZE, "%pUl", uuid); |
|---|
| 837 | + return sprintf(buf, "%pUl", uuid); |
|---|
| 778 | 838 | } |
|---|
| 779 | 839 | static DEVICE_ATTR_RO(uuid); |
|---|
| 780 | 840 | |
|---|
| .. | .. |
|---|
| 784 | 844 | struct mei_cl_device *cldev = to_mei_cl_device(dev); |
|---|
| 785 | 845 | u8 version = mei_me_cl_ver(cldev->me_cl); |
|---|
| 786 | 846 | |
|---|
| 787 | | - return scnprintf(buf, PAGE_SIZE, "%02X", version); |
|---|
| 847 | + return sprintf(buf, "%02X", version); |
|---|
| 788 | 848 | } |
|---|
| 789 | 849 | static DEVICE_ATTR_RO(version); |
|---|
| 790 | 850 | |
|---|
| .. | .. |
|---|
| 800 | 860 | } |
|---|
| 801 | 861 | static DEVICE_ATTR_RO(modalias); |
|---|
| 802 | 862 | |
|---|
| 863 | +static ssize_t max_conn_show(struct device *dev, struct device_attribute *a, |
|---|
| 864 | + char *buf) |
|---|
| 865 | +{ |
|---|
| 866 | + struct mei_cl_device *cldev = to_mei_cl_device(dev); |
|---|
| 867 | + u8 maxconn = mei_me_cl_max_conn(cldev->me_cl); |
|---|
| 868 | + |
|---|
| 869 | + return sprintf(buf, "%d", maxconn); |
|---|
| 870 | +} |
|---|
| 871 | +static DEVICE_ATTR_RO(max_conn); |
|---|
| 872 | + |
|---|
| 873 | +static ssize_t fixed_show(struct device *dev, struct device_attribute *a, |
|---|
| 874 | + char *buf) |
|---|
| 875 | +{ |
|---|
| 876 | + struct mei_cl_device *cldev = to_mei_cl_device(dev); |
|---|
| 877 | + u8 fixed = mei_me_cl_fixed(cldev->me_cl); |
|---|
| 878 | + |
|---|
| 879 | + return sprintf(buf, "%d", fixed); |
|---|
| 880 | +} |
|---|
| 881 | +static DEVICE_ATTR_RO(fixed); |
|---|
| 882 | + |
|---|
| 883 | +static ssize_t vtag_show(struct device *dev, struct device_attribute *a, |
|---|
| 884 | + char *buf) |
|---|
| 885 | +{ |
|---|
| 886 | + struct mei_cl_device *cldev = to_mei_cl_device(dev); |
|---|
| 887 | + bool vt = mei_me_cl_vt(cldev->me_cl); |
|---|
| 888 | + |
|---|
| 889 | + return sprintf(buf, "%d", vt); |
|---|
| 890 | +} |
|---|
| 891 | +static DEVICE_ATTR_RO(vtag); |
|---|
| 892 | + |
|---|
| 893 | +static ssize_t max_len_show(struct device *dev, struct device_attribute *a, |
|---|
| 894 | + char *buf) |
|---|
| 895 | +{ |
|---|
| 896 | + struct mei_cl_device *cldev = to_mei_cl_device(dev); |
|---|
| 897 | + u32 maxlen = mei_me_cl_max_len(cldev->me_cl); |
|---|
| 898 | + |
|---|
| 899 | + return sprintf(buf, "%u", maxlen); |
|---|
| 900 | +} |
|---|
| 901 | +static DEVICE_ATTR_RO(max_len); |
|---|
| 902 | + |
|---|
| 803 | 903 | static struct attribute *mei_cldev_attrs[] = { |
|---|
| 804 | 904 | &dev_attr_name.attr, |
|---|
| 805 | 905 | &dev_attr_uuid.attr, |
|---|
| 806 | 906 | &dev_attr_version.attr, |
|---|
| 807 | 907 | &dev_attr_modalias.attr, |
|---|
| 908 | + &dev_attr_max_conn.attr, |
|---|
| 909 | + &dev_attr_fixed.attr, |
|---|
| 910 | + &dev_attr_vtag.attr, |
|---|
| 911 | + &dev_attr_max_len.attr, |
|---|
| 808 | 912 | NULL, |
|---|
| 809 | 913 | }; |
|---|
| 810 | 914 | ATTRIBUTE_GROUPS(mei_cldev); |
|---|
| .. | .. |
|---|
| 908 | 1012 | struct mei_cl_device *cldev; |
|---|
| 909 | 1013 | struct mei_cl *cl; |
|---|
| 910 | 1014 | |
|---|
| 911 | | - cldev = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL); |
|---|
| 1015 | + cldev = kzalloc(sizeof(*cldev), GFP_KERNEL); |
|---|
| 912 | 1016 | if (!cldev) |
|---|
| 913 | 1017 | return NULL; |
|---|
| 914 | 1018 | |
|---|