aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mei/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/mei/client.c')
-rw-r--r--drivers/misc/mei/client.c156
1 files changed, 131 insertions, 25 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 1382d551d7ed..dfbddfe1c7a0 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -27,7 +27,63 @@
27#include "client.h" 27#include "client.h"
28 28
29/** 29/**
30 * mei_me_cl_init - initialize me client
31 *
32 * @me_cl: me client
33 */
34void mei_me_cl_init(struct mei_me_client *me_cl)
35{
36 INIT_LIST_HEAD(&me_cl->list);
37 kref_init(&me_cl->refcnt);
38}
39
40/**
41 * mei_me_cl_get - increases me client refcount
42 *
43 * @me_cl: me client
44 *
45 * Locking: called under "dev->device_lock" lock
46 *
47 * Return: me client or NULL
48 */
49struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl)
50{
51 if (me_cl)
52 kref_get(&me_cl->refcnt);
53
54 return me_cl;
55}
56
57/**
58 * mei_me_cl_release - unlink and free me client
59 *
60 * Locking: called under "dev->device_lock" lock
61 *
62 * @ref: me_client refcount
63 */
64static void mei_me_cl_release(struct kref *ref)
65{
66 struct mei_me_client *me_cl =
67 container_of(ref, struct mei_me_client, refcnt);
68 list_del(&me_cl->list);
69 kfree(me_cl);
70}
71/**
72 * mei_me_cl_put - decrease me client refcount and free client if necessary
73 *
74 * Locking: called under "dev->device_lock" lock
75 *
76 * @me_cl: me client
77 */
78void mei_me_cl_put(struct mei_me_client *me_cl)
79{
80 if (me_cl)
81 kref_put(&me_cl->refcnt, mei_me_cl_release);
82}
83
84/**
30 * mei_me_cl_by_uuid - locate me client by uuid 85 * mei_me_cl_by_uuid - locate me client by uuid
86 * increases ref count
31 * 87 *
32 * @dev: mei device 88 * @dev: mei device
33 * @uuid: me client uuid 89 * @uuid: me client uuid
@@ -43,13 +99,14 @@ struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
43 99
44 list_for_each_entry(me_cl, &dev->me_clients, list) 100 list_for_each_entry(me_cl, &dev->me_clients, list)
45 if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0) 101 if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
46 return me_cl; 102 return mei_me_cl_get(me_cl);
47 103
48 return NULL; 104 return NULL;
49} 105}
50 106
51/** 107/**
52 * mei_me_cl_by_id - locate me client by client id 108 * mei_me_cl_by_id - locate me client by client id
109 * increases ref count
53 * 110 *
54 * @dev: the device structure 111 * @dev: the device structure
55 * @client_id: me client id 112 * @client_id: me client id
@@ -65,12 +122,14 @@ struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
65 122
66 list_for_each_entry(me_cl, &dev->me_clients, list) 123 list_for_each_entry(me_cl, &dev->me_clients, list)
67 if (me_cl->client_id == client_id) 124 if (me_cl->client_id == client_id)
68 return me_cl; 125 return mei_me_cl_get(me_cl);
126
69 return NULL; 127 return NULL;
70} 128}
71 129
72/** 130/**
73 * mei_me_cl_by_uuid_id - locate me client by client id and uuid 131 * mei_me_cl_by_uuid_id - locate me client by client id and uuid
132 * increases ref count
74 * 133 *
75 * @dev: the device structure 134 * @dev: the device structure
76 * @uuid: me client uuid 135 * @uuid: me client uuid
@@ -88,31 +147,67 @@ struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
88 list_for_each_entry(me_cl, &dev->me_clients, list) 147 list_for_each_entry(me_cl, &dev->me_clients, list)
89 if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 && 148 if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
90 me_cl->client_id == client_id) 149 me_cl->client_id == client_id)
91 return me_cl; 150 return mei_me_cl_get(me_cl);
151
92 return NULL; 152 return NULL;
93} 153}
94 154
95/** 155/**
96 * mei_me_cl_remove - remove me client matching uuid and client_id 156 * mei_me_cl_rm_by_uuid - remove all me clients matching uuid
97 * 157 *
98 * @dev: the device structure 158 * @dev: the device structure
99 * @uuid: me client uuid 159 * @uuid: me client uuid
100 * @client_id: me client address 160 *
161 * Locking: called under "dev->device_lock" lock
101 */ 162 */
102void mei_me_cl_remove(struct mei_device *dev, const uuid_le *uuid, u8 client_id) 163void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid)
103{ 164{
104 struct mei_me_client *me_cl, *next; 165 struct mei_me_client *me_cl, *next;
105 166
167 dev_dbg(dev->dev, "remove %pUl\n", uuid);
168 list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
169 if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
170 mei_me_cl_put(me_cl);
171}
172
173/**
174 * mei_me_cl_rm_by_uuid_id - remove all me clients matching client id
175 *
176 * @dev: the device structure
177 * @uuid: me client uuid
178 * @id: me client id
179 *
180 * Locking: called under "dev->device_lock" lock
181 */
182void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 id)
183{
184 struct mei_me_client *me_cl, *next;
185 const uuid_le *pn;
186
187 dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id);
106 list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) { 188 list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
107 if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 && 189 pn = &me_cl->props.protocol_name;
108 me_cl->client_id == client_id) { 190 if (me_cl->client_id == id && uuid_le_cmp(*uuid, *pn) == 0)
109 list_del(&me_cl->list); 191 mei_me_cl_put(me_cl);
110 kfree(me_cl);
111 break;
112 }
113 } 192 }
114} 193}
115 194
195/**
196 * mei_me_cl_rm_all - remove all me clients
197 *
198 * @dev: the device structure
199 *
200 * Locking: called under "dev->device_lock" lock
201 */
202void mei_me_cl_rm_all(struct mei_device *dev)
203{
204 struct mei_me_client *me_cl, *next;
205
206 list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
207 mei_me_cl_put(me_cl);
208}
209
210
116 211
117/** 212/**
118 * mei_cl_cmp_id - tells if the clients are the same 213 * mei_cl_cmp_id - tells if the clients are the same
@@ -695,6 +790,7 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
695{ 790{
696 struct mei_device *dev; 791 struct mei_device *dev;
697 struct mei_me_client *me_cl; 792 struct mei_me_client *me_cl;
793 int rets = 0;
698 794
699 if (WARN_ON(!cl || !cl->dev)) 795 if (WARN_ON(!cl || !cl->dev))
700 return -EINVAL; 796 return -EINVAL;
@@ -704,18 +800,19 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
704 if (cl->mei_flow_ctrl_creds > 0) 800 if (cl->mei_flow_ctrl_creds > 0)
705 return 1; 801 return 1;
706 802
707 me_cl = mei_me_cl_by_id(dev, cl->me_client_id); 803 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
708 if (!me_cl) { 804 if (!me_cl) {
709 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); 805 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
710 return -ENOENT; 806 return -ENOENT;
711 } 807 }
712 808
713 if (me_cl->mei_flow_ctrl_creds) { 809 if (me_cl->mei_flow_ctrl_creds > 0) {
810 rets = 1;
714 if (WARN_ON(me_cl->props.single_recv_buf == 0)) 811 if (WARN_ON(me_cl->props.single_recv_buf == 0))
715 return -EINVAL; 812 rets = -EINVAL;
716 return 1;
717 } 813 }
718 return 0; 814 mei_me_cl_put(me_cl);
815 return rets;
719} 816}
720 817
721/** 818/**
@@ -732,28 +829,36 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
732{ 829{
733 struct mei_device *dev; 830 struct mei_device *dev;
734 struct mei_me_client *me_cl; 831 struct mei_me_client *me_cl;
832 int rets;
735 833
736 if (WARN_ON(!cl || !cl->dev)) 834 if (WARN_ON(!cl || !cl->dev))
737 return -EINVAL; 835 return -EINVAL;
738 836
739 dev = cl->dev; 837 dev = cl->dev;
740 838
741 me_cl = mei_me_cl_by_id(dev, cl->me_client_id); 839 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
742 if (!me_cl) { 840 if (!me_cl) {
743 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); 841 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
744 return -ENOENT; 842 return -ENOENT;
745 } 843 }
746 844
747 if (me_cl->props.single_recv_buf) { 845 if (me_cl->props.single_recv_buf) {
748 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) 846 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
749 return -EINVAL; 847 rets = -EINVAL;
848 goto out;
849 }
750 me_cl->mei_flow_ctrl_creds--; 850 me_cl->mei_flow_ctrl_creds--;
751 } else { 851 } else {
752 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) 852 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
753 return -EINVAL; 853 rets = -EINVAL;
854 goto out;
855 }
754 cl->mei_flow_ctrl_creds--; 856 cl->mei_flow_ctrl_creds--;
755 } 857 }
756 return 0; 858 rets = 0;
859out:
860 mei_me_cl_put(me_cl);
861 return rets;
757} 862}
758 863
759/** 864/**
@@ -788,6 +893,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
788 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); 893 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
789 return -ENOTTY; 894 return -ENOTTY;
790 } 895 }
896 /* always allocate at least client max message */
897 length = max_t(size_t, length, me_cl->props.max_msg_length);
898 mei_me_cl_put(me_cl);
791 899
792 rets = pm_runtime_get(dev->dev); 900 rets = pm_runtime_get(dev->dev);
793 if (rets < 0 && rets != -EINPROGRESS) { 901 if (rets < 0 && rets != -EINPROGRESS) {
@@ -802,8 +910,6 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
802 goto out; 910 goto out;
803 } 911 }
804 912
805 /* always allocate at least client max message */
806 length = max_t(size_t, length, me_cl->props.max_msg_length);
807 rets = mei_io_cb_alloc_resp_buf(cb, length); 913 rets = mei_io_cb_alloc_resp_buf(cb, length);
808 if (rets) 914 if (rets)
809 goto out; 915 goto out;