blob: 5ecb6cc79d70cb1e3c84a476282ddf12025b90c2 [file] [log] [blame]
Tomas Winkler9ca90502013-01-08 23:07:13 +02001/*
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
Tomas Winkler9ca90502013-01-08 23:07:13 +020017#include <linux/sched.h>
18#include <linux/wait.h>
19#include <linux/delay.h>
Tomas Winkler1f180352014-09-29 16:31:46 +030020#include <linux/slab.h>
Tomas Winkler04bb1392014-03-18 22:52:04 +020021#include <linux/pm_runtime.h>
Tomas Winkler9ca90502013-01-08 23:07:13 +020022
23#include <linux/mei.h>
24
25#include "mei_dev.h"
26#include "hbm.h"
Tomas Winkler90e0b5f12013-01-08 23:07:14 +020027#include "client.h"
28
29/**
Tomas Winkler79563db2015-01-11 00:07:16 +020030 * 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{
Tomas Winklerb7d88512015-02-10 10:39:31 +020051 if (me_cl && kref_get_unless_zero(&me_cl->refcnt))
52 return me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +020053
Tomas Winklerb7d88512015-02-10 10:39:31 +020054 return NULL;
Tomas Winkler79563db2015-01-11 00:07:16 +020055}
56
57/**
Tomas Winklerb7d88512015-02-10 10:39:31 +020058 * mei_me_cl_release - free me client
Tomas Winkler79563db2015-01-11 00:07:16 +020059 *
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);
Tomas Winklerb7d88512015-02-10 10:39:31 +020068
Tomas Winkler79563db2015-01-11 00:07:16 +020069 kfree(me_cl);
70}
Tomas Winklerb7d88512015-02-10 10:39:31 +020071
Tomas Winkler79563db2015-01-11 00:07:16 +020072/**
73 * mei_me_cl_put - decrease me client refcount and free client if necessary
74 *
75 * Locking: called under "dev->device_lock" lock
76 *
77 * @me_cl: me client
78 */
79void mei_me_cl_put(struct mei_me_client *me_cl)
80{
81 if (me_cl)
82 kref_put(&me_cl->refcnt, mei_me_cl_release);
83}
84
85/**
Tomas Winklerb7d88512015-02-10 10:39:31 +020086 * __mei_me_cl_del - delete me client form the list and decrease
87 * reference counter
88 *
89 * @dev: mei device
90 * @me_cl: me client
91 *
92 * Locking: dev->me_clients_rwsem
93 */
94static void __mei_me_cl_del(struct mei_device *dev, struct mei_me_client *me_cl)
95{
96 if (!me_cl)
97 return;
98
99 list_del(&me_cl->list);
100 mei_me_cl_put(me_cl);
101}
102
103/**
104 * mei_me_cl_add - add me client to the list
105 *
106 * @dev: mei device
107 * @me_cl: me client
108 */
109void mei_me_cl_add(struct mei_device *dev, struct mei_me_client *me_cl)
110{
111 down_write(&dev->me_clients_rwsem);
112 list_add(&me_cl->list, &dev->me_clients);
113 up_write(&dev->me_clients_rwsem);
114}
115
116/**
117 * __mei_me_cl_by_uuid - locate me client by uuid
118 * increases ref count
119 *
120 * @dev: mei device
121 * @uuid: me client uuid
122 *
123 * Return: me client or NULL if not found
124 *
125 * Locking: dev->me_clients_rwsem
126 */
127static struct mei_me_client *__mei_me_cl_by_uuid(struct mei_device *dev,
128 const uuid_le *uuid)
129{
130 struct mei_me_client *me_cl;
131 const uuid_le *pn;
132
133 WARN_ON(!rwsem_is_locked(&dev->me_clients_rwsem));
134
135 list_for_each_entry(me_cl, &dev->me_clients, list) {
136 pn = &me_cl->props.protocol_name;
137 if (uuid_le_cmp(*uuid, *pn) == 0)
138 return mei_me_cl_get(me_cl);
139 }
140
141 return NULL;
142}
143
144/**
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300145 * mei_me_cl_by_uuid - locate me client by uuid
Tomas Winkler79563db2015-01-11 00:07:16 +0200146 * increases ref count
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200147 *
148 * @dev: mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300149 * @uuid: me client uuid
Alexander Usyskina27a76d2014-02-17 15:13:22 +0200150 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300151 * Return: me client or NULL if not found
Tomas Winklerb7d88512015-02-10 10:39:31 +0200152 *
153 * Locking: dev->me_clients_rwsem
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200154 */
Tomas Winklerb7d88512015-02-10 10:39:31 +0200155struct mei_me_client *mei_me_cl_by_uuid(struct mei_device *dev,
Tomas Winklerd3208322014-08-24 12:08:55 +0300156 const uuid_le *uuid)
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200157{
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300158 struct mei_me_client *me_cl;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200159
Tomas Winklerb7d88512015-02-10 10:39:31 +0200160 down_read(&dev->me_clients_rwsem);
161 me_cl = __mei_me_cl_by_uuid(dev, uuid);
162 up_read(&dev->me_clients_rwsem);
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200163
Tomas Winklerb7d88512015-02-10 10:39:31 +0200164 return me_cl;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200165}
166
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200167/**
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300168 * mei_me_cl_by_id - locate me client by client id
Tomas Winkler79563db2015-01-11 00:07:16 +0200169 * increases ref count
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200170 *
171 * @dev: the device structure
172 * @client_id: me client id
173 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300174 * Return: me client or NULL if not found
Tomas Winklerb7d88512015-02-10 10:39:31 +0200175 *
176 * Locking: dev->me_clients_rwsem
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200177 */
Tomas Winklerd3208322014-08-24 12:08:55 +0300178struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200179{
Alexander Usyskina27a76d2014-02-17 15:13:22 +0200180
Tomas Winklerb7d88512015-02-10 10:39:31 +0200181 struct mei_me_client *__me_cl, *me_cl = NULL;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200182
Tomas Winklerb7d88512015-02-10 10:39:31 +0200183 down_read(&dev->me_clients_rwsem);
184 list_for_each_entry(__me_cl, &dev->me_clients, list) {
185 if (__me_cl->client_id == client_id) {
186 me_cl = mei_me_cl_get(__me_cl);
187 break;
188 }
189 }
190 up_read(&dev->me_clients_rwsem);
191
192 return me_cl;
193}
194
195/**
196 * __mei_me_cl_by_uuid_id - locate me client by client id and uuid
197 * increases ref count
198 *
199 * @dev: the device structure
200 * @uuid: me client uuid
201 * @client_id: me client id
202 *
203 * Return: me client or null if not found
204 *
205 * Locking: dev->me_clients_rwsem
206 */
207static struct mei_me_client *__mei_me_cl_by_uuid_id(struct mei_device *dev,
208 const uuid_le *uuid, u8 client_id)
209{
210 struct mei_me_client *me_cl;
211 const uuid_le *pn;
212
213 WARN_ON(!rwsem_is_locked(&dev->me_clients_rwsem));
214
215 list_for_each_entry(me_cl, &dev->me_clients, list) {
216 pn = &me_cl->props.protocol_name;
217 if (uuid_le_cmp(*uuid, *pn) == 0 &&
218 me_cl->client_id == client_id)
Tomas Winkler79563db2015-01-11 00:07:16 +0200219 return mei_me_cl_get(me_cl);
Tomas Winklerb7d88512015-02-10 10:39:31 +0200220 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200221
Tomas Winklerd3208322014-08-24 12:08:55 +0300222 return NULL;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200223}
Tomas Winkler9ca90502013-01-08 23:07:13 +0200224
Tomas Winklerb7d88512015-02-10 10:39:31 +0200225
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300226/**
227 * mei_me_cl_by_uuid_id - locate me client by client id and uuid
Tomas Winkler79563db2015-01-11 00:07:16 +0200228 * increases ref count
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300229 *
230 * @dev: the device structure
231 * @uuid: me client uuid
232 * @client_id: me client id
233 *
Tomas Winklerb7d88512015-02-10 10:39:31 +0200234 * Return: me client or null if not found
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300235 */
Tomas Winklerd880f322014-08-21 14:29:15 +0300236struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
237 const uuid_le *uuid, u8 client_id)
238{
239 struct mei_me_client *me_cl;
240
Tomas Winklerb7d88512015-02-10 10:39:31 +0200241 down_read(&dev->me_clients_rwsem);
242 me_cl = __mei_me_cl_by_uuid_id(dev, uuid, client_id);
243 up_read(&dev->me_clients_rwsem);
Tomas Winkler79563db2015-01-11 00:07:16 +0200244
Tomas Winklerb7d88512015-02-10 10:39:31 +0200245 return me_cl;
Tomas Winklerd880f322014-08-21 14:29:15 +0300246}
247
Tomas Winkler25ca6472014-08-21 14:29:14 +0300248/**
Tomas Winkler79563db2015-01-11 00:07:16 +0200249 * mei_me_cl_rm_by_uuid - remove all me clients matching uuid
Tomas Winkler25ca6472014-08-21 14:29:14 +0300250 *
251 * @dev: the device structure
252 * @uuid: me client uuid
Tomas Winkler79563db2015-01-11 00:07:16 +0200253 *
254 * Locking: called under "dev->device_lock" lock
Tomas Winkler25ca6472014-08-21 14:29:14 +0300255 */
Tomas Winkler79563db2015-01-11 00:07:16 +0200256void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid)
Tomas Winkler25ca6472014-08-21 14:29:14 +0300257{
Tomas Winklerb7d88512015-02-10 10:39:31 +0200258 struct mei_me_client *me_cl;
Tomas Winkler25ca6472014-08-21 14:29:14 +0300259
Tomas Winkler79563db2015-01-11 00:07:16 +0200260 dev_dbg(dev->dev, "remove %pUl\n", uuid);
Tomas Winklerb7d88512015-02-10 10:39:31 +0200261
262 down_write(&dev->me_clients_rwsem);
263 me_cl = __mei_me_cl_by_uuid(dev, uuid);
264 __mei_me_cl_del(dev, me_cl);
265 up_write(&dev->me_clients_rwsem);
Tomas Winkler79563db2015-01-11 00:07:16 +0200266}
267
268/**
269 * mei_me_cl_rm_by_uuid_id - remove all me clients matching client id
270 *
271 * @dev: the device structure
272 * @uuid: me client uuid
273 * @id: me client id
274 *
275 * Locking: called under "dev->device_lock" lock
276 */
277void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 id)
278{
Tomas Winklerb7d88512015-02-10 10:39:31 +0200279 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200280
281 dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id);
Tomas Winklerb7d88512015-02-10 10:39:31 +0200282
283 down_write(&dev->me_clients_rwsem);
284 me_cl = __mei_me_cl_by_uuid_id(dev, uuid, id);
285 __mei_me_cl_del(dev, me_cl);
286 up_write(&dev->me_clients_rwsem);
Tomas Winkler25ca6472014-08-21 14:29:14 +0300287}
288
Tomas Winkler79563db2015-01-11 00:07:16 +0200289/**
290 * mei_me_cl_rm_all - remove all me clients
291 *
292 * @dev: the device structure
293 *
294 * Locking: called under "dev->device_lock" lock
295 */
296void mei_me_cl_rm_all(struct mei_device *dev)
297{
298 struct mei_me_client *me_cl, *next;
299
Tomas Winklerb7d88512015-02-10 10:39:31 +0200300 down_write(&dev->me_clients_rwsem);
Tomas Winkler79563db2015-01-11 00:07:16 +0200301 list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
Tomas Winklerb7d88512015-02-10 10:39:31 +0200302 __mei_me_cl_del(dev, me_cl);
303 up_write(&dev->me_clients_rwsem);
Tomas Winkler79563db2015-01-11 00:07:16 +0200304}
305
Tomas Winkler9ca90502013-01-08 23:07:13 +0200306/**
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200307 * mei_cl_cmp_id - tells if the clients are the same
308 *
309 * @cl1: host client 1
310 * @cl2: host client 2
311 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300312 * Return: true - if the clients has same host and me ids
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200313 * false - otherwise
314 */
315static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
316 const struct mei_cl *cl2)
317{
318 return cl1 && cl2 &&
319 (cl1->host_client_id == cl2->host_client_id) &&
320 (cl1->me_client_id == cl2->me_client_id);
321}
322
323/**
Alexander Usyskin3908be62015-02-10 10:39:35 +0200324 * __mei_io_list_flush - removes and frees cbs belonging to cl.
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200325 *
326 * @list: an instance of our list structure
327 * @cl: host client, can be NULL for flushing the whole list
328 * @free: whether to free the cbs
329 */
330static void __mei_io_list_flush(struct mei_cl_cb *list,
331 struct mei_cl *cl, bool free)
332{
333 struct mei_cl_cb *cb;
334 struct mei_cl_cb *next;
335
336 /* enable removing everything if no cl is specified */
337 list_for_each_entry_safe(cb, next, &list->list, list) {
Alexander Usyskin140c7552014-10-02 13:39:31 +0300338 if (!cl || mei_cl_cmp_id(cl, cb->cl)) {
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200339 list_del(&cb->list);
340 if (free)
341 mei_io_cb_free(cb);
342 }
343 }
344}
345
346/**
Tomas Winkler9ca90502013-01-08 23:07:13 +0200347 * mei_io_list_flush - removes list entry belonging to cl.
348 *
349 * @list: An instance of our list structure
350 * @cl: host client
351 */
Alexander Usyskin54567962014-08-14 17:22:20 +0300352void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200353{
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200354 __mei_io_list_flush(list, cl, false);
355}
Tomas Winkler9ca90502013-01-08 23:07:13 +0200356
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200357
358/**
359 * mei_io_list_free - removes cb belonging to cl and free them
360 *
361 * @list: An instance of our list structure
362 * @cl: host client
363 */
364static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
365{
366 __mei_io_list_flush(list, cl, true);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200367}
368
369/**
370 * mei_io_cb_free - free mei_cb_private related memory
371 *
372 * @cb: mei callback struct
373 */
374void mei_io_cb_free(struct mei_cl_cb *cb)
375{
376 if (cb == NULL)
377 return;
378
Tomas Winkler5db75142015-02-10 10:39:42 +0200379 kfree(cb->buf.data);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200380 kfree(cb);
381}
382
383/**
384 * mei_io_cb_init - allocate and initialize io callback
385 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300386 * @cl: mei client
Masanari Iida393b1482013-04-05 01:05:05 +0900387 * @fp: pointer to file structure
Tomas Winkler9ca90502013-01-08 23:07:13 +0200388 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300389 * Return: mei_cl_cb pointer or NULL;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200390 */
391struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
392{
393 struct mei_cl_cb *cb;
394
395 cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
396 if (!cb)
397 return NULL;
398
399 mei_io_list_init(cb);
400
401 cb->file_object = fp;
402 cb->cl = cl;
403 cb->buf_idx = 0;
404 return cb;
405}
406
407/**
Tomas Winkler5db75142015-02-10 10:39:42 +0200408 * mei_io_cb_alloc_buf - allocate callback buffer
Tomas Winkler9ca90502013-01-08 23:07:13 +0200409 *
Masanari Iida393b1482013-04-05 01:05:05 +0900410 * @cb: io callback structure
411 * @length: size of the buffer
Tomas Winkler9ca90502013-01-08 23:07:13 +0200412 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300413 * Return: 0 on success
Tomas Winkler9ca90502013-01-08 23:07:13 +0200414 * -EINVAL if cb is NULL
415 * -ENOMEM if allocation failed
416 */
Tomas Winkler5db75142015-02-10 10:39:42 +0200417int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200418{
419 if (!cb)
420 return -EINVAL;
421
422 if (length == 0)
423 return 0;
424
Tomas Winkler5db75142015-02-10 10:39:42 +0200425 cb->buf.data = kmalloc(length, GFP_KERNEL);
426 if (!cb->buf.data)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200427 return -ENOMEM;
Tomas Winkler5db75142015-02-10 10:39:42 +0200428 cb->buf.size = length;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200429 return 0;
430}
Tomas Winkler9ca90502013-01-08 23:07:13 +0200431
432/**
433 * mei_cl_flush_queues - flushes queue lists belonging to cl.
434 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200435 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300436 *
437 * Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200438 */
439int mei_cl_flush_queues(struct mei_cl *cl)
440{
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300441 struct mei_device *dev;
442
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200443 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200444 return -EINVAL;
445
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300446 dev = cl->dev;
447
448 cl_dbg(dev, cl, "remove list entry belonging to cl\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200449 mei_io_list_flush(&cl->dev->read_list, cl);
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200450 mei_io_list_free(&cl->dev->write_list, cl);
451 mei_io_list_free(&cl->dev->write_waiting_list, cl);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200452 mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
453 mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
454 mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
455 mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
456 return 0;
457}
458
Tomas Winkler9ca90502013-01-08 23:07:13 +0200459
460/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200461 * mei_cl_init - initializes cl.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200462 *
463 * @cl: host client to be initialized
464 * @dev: mei device
465 */
466void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
467{
468 memset(cl, 0, sizeof(struct mei_cl));
469 init_waitqueue_head(&cl->wait);
470 init_waitqueue_head(&cl->rx_wait);
471 init_waitqueue_head(&cl->tx_wait);
472 INIT_LIST_HEAD(&cl->link);
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200473 INIT_LIST_HEAD(&cl->device_link);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200474 cl->reading_state = MEI_IDLE;
475 cl->writing_state = MEI_IDLE;
476 cl->dev = dev;
477}
478
479/**
480 * mei_cl_allocate - allocates cl structure and sets it up.
481 *
482 * @dev: mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300483 * Return: The allocated file or NULL on failure
Tomas Winkler9ca90502013-01-08 23:07:13 +0200484 */
485struct mei_cl *mei_cl_allocate(struct mei_device *dev)
486{
487 struct mei_cl *cl;
488
489 cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
490 if (!cl)
491 return NULL;
492
493 mei_cl_init(cl, dev);
494
495 return cl;
496}
497
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200498/**
499 * mei_cl_find_read_cb - find this cl's callback in the read list
500 *
Masanari Iida393b1482013-04-05 01:05:05 +0900501 * @cl: host client
502 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300503 * Return: cb on success, NULL on error
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200504 */
505struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
506{
507 struct mei_device *dev = cl->dev;
Tomas Winkler31f88f52014-02-17 15:13:25 +0200508 struct mei_cl_cb *cb;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200509
Tomas Winkler31f88f52014-02-17 15:13:25 +0200510 list_for_each_entry(cb, &dev->read_list.list, list)
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200511 if (mei_cl_cmp_id(cl, cb->cl))
512 return cb;
513 return NULL;
514}
515
Alexander Usyskin3908be62015-02-10 10:39:35 +0200516/**
517 * mei_cl_link - allocate host id in the host map
Tomas Winkler9ca90502013-01-08 23:07:13 +0200518 *
Alexander Usyskin3908be62015-02-10 10:39:35 +0200519 * @cl: host client
520 * @id: fixed host id or -1 for generic one
Masanari Iida393b1482013-04-05 01:05:05 +0900521 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300522 * Return: 0 on success
Tomas Winkler9ca90502013-01-08 23:07:13 +0200523 * -EINVAL on incorrect values
524 * -ENONET if client not found
525 */
Tomas Winkler781d0d82013-01-08 23:07:22 +0200526int mei_cl_link(struct mei_cl *cl, int id)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200527{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200528 struct mei_device *dev;
Tomas Winkler22f96a02013-09-16 23:44:47 +0300529 long open_handle_count;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200530
Tomas Winkler781d0d82013-01-08 23:07:22 +0200531 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200532 return -EINVAL;
533
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200534 dev = cl->dev;
535
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200536 /* If Id is not assigned get one*/
Tomas Winkler781d0d82013-01-08 23:07:22 +0200537 if (id == MEI_HOST_CLIENT_ID_ANY)
538 id = find_first_zero_bit(dev->host_clients_map,
539 MEI_CLIENTS_MAX);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200540
Tomas Winkler781d0d82013-01-08 23:07:22 +0200541 if (id >= MEI_CLIENTS_MAX) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300542 dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
Tomas Winklere036cc52013-09-16 23:44:46 +0300543 return -EMFILE;
544 }
545
Tomas Winkler22f96a02013-09-16 23:44:47 +0300546 open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
547 if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300548 dev_err(dev->dev, "open_handle_count exceeded %d",
Tomas Winklere036cc52013-09-16 23:44:46 +0300549 MEI_MAX_OPEN_HANDLE_COUNT);
550 return -EMFILE;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200551 }
552
Tomas Winkler781d0d82013-01-08 23:07:22 +0200553 dev->open_handle_count++;
554
555 cl->host_client_id = id;
556 list_add_tail(&cl->link, &dev->file_list);
557
558 set_bit(id, dev->host_clients_map);
559
560 cl->state = MEI_FILE_INITIALIZING;
561
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300562 cl_dbg(dev, cl, "link cl\n");
Tomas Winkler781d0d82013-01-08 23:07:22 +0200563 return 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200564}
Tomas Winkler781d0d82013-01-08 23:07:22 +0200565
Tomas Winkler9ca90502013-01-08 23:07:13 +0200566/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200567 * mei_cl_unlink - remove me_cl from the list
Tomas Winkler9ca90502013-01-08 23:07:13 +0200568 *
Masanari Iida393b1482013-04-05 01:05:05 +0900569 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300570 *
571 * Return: always 0
Tomas Winkler9ca90502013-01-08 23:07:13 +0200572 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200573int mei_cl_unlink(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200574{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200575 struct mei_device *dev;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200576
Tomas Winkler781d0d82013-01-08 23:07:22 +0200577 /* don't shout on error exit path */
578 if (!cl)
579 return 0;
580
Tomas Winkler8e9a4a92013-01-10 17:32:14 +0200581 /* wd and amthif might not be initialized */
582 if (!cl->dev)
583 return 0;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200584
585 dev = cl->dev;
586
Tomas Winklera14c44d2013-09-16 23:44:45 +0300587 cl_dbg(dev, cl, "unlink client");
588
Tomas Winkler22f96a02013-09-16 23:44:47 +0300589 if (dev->open_handle_count > 0)
590 dev->open_handle_count--;
591
592 /* never clear the 0 bit */
593 if (cl->host_client_id)
594 clear_bit(cl->host_client_id, dev->host_clients_map);
595
596 list_del_init(&cl->link);
597
598 cl->state = MEI_FILE_INITIALIZING;
599
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200600 return 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200601}
602
603
604void mei_host_client_init(struct work_struct *work)
605{
Tomas Winklerb7d88512015-02-10 10:39:31 +0200606 struct mei_device *dev =
607 container_of(work, struct mei_device, init_work);
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300608 struct mei_me_client *me_cl;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200609
610 mutex_lock(&dev->device_lock);
611
Tomas Winkler9ca90502013-01-08 23:07:13 +0200612
Tomas Winklerb7d88512015-02-10 10:39:31 +0200613 me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
614 if (me_cl)
615 mei_amthif_host_init(dev);
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200616
Tomas Winklerb7d88512015-02-10 10:39:31 +0200617 me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid);
618 if (me_cl)
619 mei_wd_host_init(dev);
620
621 me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
622 if (me_cl)
623 mei_nfc_host_init(dev);
624
Tomas Winkler9ca90502013-01-08 23:07:13 +0200625
626 dev->dev_state = MEI_DEV_ENABLED;
Tomas Winkler6adb8ef2014-01-12 00:36:10 +0200627 dev->reset_count = 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200628 mutex_unlock(&dev->device_lock);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200629
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300630 pm_runtime_mark_last_busy(dev->dev);
631 dev_dbg(dev->dev, "rpm: autosuspend\n");
632 pm_runtime_autosuspend(dev->dev);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200633}
634
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200635/**
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300636 * mei_hbuf_acquire - try to acquire host buffer
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200637 *
638 * @dev: the device structure
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300639 * Return: true if host buffer was acquired
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200640 */
641bool mei_hbuf_acquire(struct mei_device *dev)
642{
Tomas Winkler04bb1392014-03-18 22:52:04 +0200643 if (mei_pg_state(dev) == MEI_PG_ON ||
644 dev->pg_event == MEI_PG_EVENT_WAIT) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300645 dev_dbg(dev->dev, "device is in pg\n");
Tomas Winkler04bb1392014-03-18 22:52:04 +0200646 return false;
647 }
648
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200649 if (!dev->hbuf_is_ready) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300650 dev_dbg(dev->dev, "hbuf is not ready\n");
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200651 return false;
652 }
653
654 dev->hbuf_is_ready = false;
655
656 return true;
657}
Tomas Winkler9ca90502013-01-08 23:07:13 +0200658
659/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200660 * mei_cl_disconnect - disconnect host client from the me one
Tomas Winkler9ca90502013-01-08 23:07:13 +0200661 *
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200662 * @cl: host client
Tomas Winkler9ca90502013-01-08 23:07:13 +0200663 *
664 * Locking: called under "dev->device_lock" lock
665 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300666 * Return: 0 on success, <0 on failure.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200667 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200668int mei_cl_disconnect(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200669{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200670 struct mei_device *dev;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200671 struct mei_cl_cb *cb;
Alexander Usyskinfe2f17e2014-07-17 10:53:38 +0300672 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200673
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200674 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200675 return -ENODEV;
676
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200677 dev = cl->dev;
678
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300679 cl_dbg(dev, cl, "disconnecting");
680
Tomas Winkler9ca90502013-01-08 23:07:13 +0200681 if (cl->state != MEI_FILE_DISCONNECTING)
682 return 0;
683
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300684 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200685 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300686 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200687 cl_err(dev, cl, "rpm: get failed %d\n", rets);
688 return rets;
689 }
690
Tomas Winkler9ca90502013-01-08 23:07:13 +0200691 cb = mei_io_cb_init(cl, NULL);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200692 if (!cb) {
693 rets = -ENOMEM;
694 goto free;
695 }
Tomas Winkler9ca90502013-01-08 23:07:13 +0200696
Tomas Winkler5a8373f2014-08-21 14:29:17 +0300697 cb->fop_type = MEI_FOP_DISCONNECT;
698
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200699 if (mei_hbuf_acquire(dev)) {
Tomas Winkler9ca90502013-01-08 23:07:13 +0200700 if (mei_hbm_cl_disconnect_req(dev, cl)) {
701 rets = -ENODEV;
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300702 cl_err(dev, cl, "failed to disconnect.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200703 goto free;
704 }
Alexander Usyskin22b987a2014-07-17 10:53:35 +0300705 cl->timer_count = MEI_CONNECT_TIMEOUT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200706 mdelay(10); /* Wait for hardware disconnection ready */
707 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
708 } else {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300709 cl_dbg(dev, cl, "add disconnect cb to control write list\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200710 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
711
712 }
713 mutex_unlock(&dev->device_lock);
714
Tomas Winkler12f45ed2014-08-21 14:29:18 +0300715 wait_event_timeout(cl->wait,
Tomas Winkler9ca90502013-01-08 23:07:13 +0200716 MEI_FILE_DISCONNECTED == cl->state,
717 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
718
719 mutex_lock(&dev->device_lock);
Alexander Usyskinfe2f17e2014-07-17 10:53:38 +0300720
Tomas Winkler9ca90502013-01-08 23:07:13 +0200721 if (MEI_FILE_DISCONNECTED == cl->state) {
722 rets = 0;
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300723 cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200724 } else {
Alexander Usyskinfe2f17e2014-07-17 10:53:38 +0300725 cl_dbg(dev, cl, "timeout on disconnect from FW client.\n");
726 rets = -ETIME;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200727 }
728
729 mei_io_list_flush(&dev->ctrl_rd_list, cl);
730 mei_io_list_flush(&dev->ctrl_wr_list, cl);
731free:
Tomas Winkler04bb1392014-03-18 22:52:04 +0200732 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300733 pm_runtime_mark_last_busy(dev->dev);
734 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200735
Tomas Winkler9ca90502013-01-08 23:07:13 +0200736 mei_io_cb_free(cb);
737 return rets;
738}
739
740
741/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200742 * mei_cl_is_other_connecting - checks if other
743 * client with the same me client id is connecting
Tomas Winkler9ca90502013-01-08 23:07:13 +0200744 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200745 * @cl: private data of the file object
746 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300747 * Return: true if other client is connected, false - otherwise.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200748 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200749bool mei_cl_is_other_connecting(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200750{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200751 struct mei_device *dev;
Tomas Winkler31f88f52014-02-17 15:13:25 +0200752 struct mei_cl *ocl; /* the other client */
Tomas Winkler9ca90502013-01-08 23:07:13 +0200753
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200754 if (WARN_ON(!cl || !cl->dev))
755 return false;
756
757 dev = cl->dev;
758
Tomas Winkler31f88f52014-02-17 15:13:25 +0200759 list_for_each_entry(ocl, &dev->file_list, link) {
760 if (ocl->state == MEI_FILE_CONNECTING &&
761 ocl != cl &&
762 cl->me_client_id == ocl->me_client_id)
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200763 return true;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200764
765 }
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200766
767 return false;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200768}
769
770/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200771 * mei_cl_connect - connect host client to the me one
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200772 *
773 * @cl: host client
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300774 * @file: pointer to file structure
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200775 *
776 * Locking: called under "dev->device_lock" lock
777 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300778 * Return: 0 on success, <0 on failure.
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200779 */
780int mei_cl_connect(struct mei_cl *cl, struct file *file)
781{
782 struct mei_device *dev;
783 struct mei_cl_cb *cb;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200784 int rets;
785
786 if (WARN_ON(!cl || !cl->dev))
787 return -ENODEV;
788
789 dev = cl->dev;
790
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300791 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200792 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300793 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200794 cl_err(dev, cl, "rpm: get failed %d\n", rets);
795 return rets;
796 }
797
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200798 cb = mei_io_cb_init(cl, file);
799 if (!cb) {
800 rets = -ENOMEM;
801 goto out;
802 }
803
Tomas Winkler02a7eec2014-02-12 21:41:51 +0200804 cb->fop_type = MEI_FOP_CONNECT;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200805
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200806 /* run hbuf acquire last so we don't have to undo */
807 if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
Alexander Usyskine4d82702014-04-27 15:42:21 +0300808 cl->state = MEI_FILE_CONNECTING;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200809 if (mei_hbm_cl_connect_req(dev, cl)) {
810 rets = -ENODEV;
811 goto out;
812 }
813 cl->timer_count = MEI_CONNECT_TIMEOUT;
814 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
815 } else {
Alexander Usyskin73ab4232014-08-12 18:07:56 +0300816 cl->state = MEI_FILE_INITIALIZING;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200817 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
818 }
819
820 mutex_unlock(&dev->device_lock);
Tomas Winkler12f45ed2014-08-21 14:29:18 +0300821 wait_event_timeout(cl->wait,
Alexander Usyskin285e2992014-02-17 15:13:20 +0200822 (cl->state == MEI_FILE_CONNECTED ||
823 cl->state == MEI_FILE_DISCONNECTED),
824 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200825 mutex_lock(&dev->device_lock);
826
827 if (cl->state != MEI_FILE_CONNECTED) {
Alexander Usyskin3e37ebb2014-07-17 10:53:34 +0300828 cl->state = MEI_FILE_DISCONNECTED;
Alexander Usyskin285e2992014-02-17 15:13:20 +0200829 /* something went really wrong */
830 if (!cl->status)
831 cl->status = -EFAULT;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200832
833 mei_io_list_flush(&dev->ctrl_rd_list, cl);
834 mei_io_list_flush(&dev->ctrl_wr_list, cl);
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200835 }
836
837 rets = cl->status;
838
839out:
Tomas Winkler04bb1392014-03-18 22:52:04 +0200840 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300841 pm_runtime_mark_last_busy(dev->dev);
842 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200843
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200844 mei_io_cb_free(cb);
845 return rets;
846}
847
848/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200849 * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200850 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200851 * @cl: private data of the file object
852 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300853 * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200854 * -ENOENT if mei_cl is not present
855 * -EINVAL if single_recv_buf == 0
856 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200857int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200858{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200859 struct mei_device *dev;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200860 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200861 int rets = 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200862
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200863 if (WARN_ON(!cl || !cl->dev))
864 return -EINVAL;
865
866 dev = cl->dev;
867
Tomas Winkler9ca90502013-01-08 23:07:13 +0200868 if (cl->mei_flow_ctrl_creds > 0)
869 return 1;
870
Tomas Winkler2e5df412014-12-07 16:40:14 +0200871 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300872 if (!me_cl) {
Alexander Usyskin12d00662014-02-17 15:13:23 +0200873 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300874 return -ENOENT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200875 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200876
Tomas Winkler79563db2015-01-11 00:07:16 +0200877 if (me_cl->mei_flow_ctrl_creds > 0) {
878 rets = 1;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200879 if (WARN_ON(me_cl->props.single_recv_buf == 0))
Tomas Winkler79563db2015-01-11 00:07:16 +0200880 rets = -EINVAL;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200881 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200882 mei_me_cl_put(me_cl);
883 return rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200884}
885
886/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200887 * mei_cl_flow_ctrl_reduce - reduces flow_control.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200888 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200889 * @cl: private data of the file object
Masanari Iida393b1482013-04-05 01:05:05 +0900890 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300891 * Return:
Tomas Winkler9ca90502013-01-08 23:07:13 +0200892 * 0 on success
893 * -ENOENT when me client is not found
894 * -EINVAL when ctrl credits are <= 0
895 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200896int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200897{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200898 struct mei_device *dev;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200899 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200900 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200901
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200902 if (WARN_ON(!cl || !cl->dev))
903 return -EINVAL;
904
905 dev = cl->dev;
906
Tomas Winkler2e5df412014-12-07 16:40:14 +0200907 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300908 if (!me_cl) {
Alexander Usyskin12d00662014-02-17 15:13:23 +0200909 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300910 return -ENOENT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200911 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200912
Tomas Winklerd3208322014-08-24 12:08:55 +0300913 if (me_cl->props.single_recv_buf) {
Tomas Winkler79563db2015-01-11 00:07:16 +0200914 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
915 rets = -EINVAL;
916 goto out;
917 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200918 me_cl->mei_flow_ctrl_creds--;
919 } else {
Tomas Winkler79563db2015-01-11 00:07:16 +0200920 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
921 rets = -EINVAL;
922 goto out;
923 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200924 cl->mei_flow_ctrl_creds--;
925 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200926 rets = 0;
927out:
928 mei_me_cl_put(me_cl);
929 return rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200930}
931
Tomas Winkler9ca90502013-01-08 23:07:13 +0200932/**
Masanari Iida393b1482013-04-05 01:05:05 +0900933 * mei_cl_read_start - the start read client message function.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200934 *
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200935 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300936 * @length: number of bytes to read
Tomas Winkler9ca90502013-01-08 23:07:13 +0200937 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300938 * Return: 0 on success, <0 on failure.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200939 */
Tomas Winklerfcb136e2013-04-19 22:01:35 +0300940int mei_cl_read_start(struct mei_cl *cl, size_t length)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200941{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200942 struct mei_device *dev;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200943 struct mei_cl_cb *cb;
Tomas Winklerd3208322014-08-24 12:08:55 +0300944 struct mei_me_client *me_cl;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200945 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200946
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200947 if (WARN_ON(!cl || !cl->dev))
948 return -ENODEV;
949
950 dev = cl->dev;
951
Tomas Winklerb950ac12013-07-25 20:15:53 +0300952 if (!mei_cl_is_connected(cl))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200953 return -ENODEV;
954
Tomas Winklerd91aaed2013-01-08 23:07:18 +0200955 if (cl->read_cb) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300956 cl_dbg(dev, cl, "read is pending.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200957 return -EBUSY;
958 }
Tomas Winklerd880f322014-08-21 14:29:15 +0300959 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300960 if (!me_cl) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300961 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +0200962 return -ENOTTY;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200963 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200964 /* always allocate at least client max message */
965 length = max_t(size_t, length, me_cl->props.max_msg_length);
966 mei_me_cl_put(me_cl);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200967
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300968 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200969 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300970 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200971 cl_err(dev, cl, "rpm: get failed %d\n", rets);
972 return rets;
973 }
974
Tomas Winkler9ca90502013-01-08 23:07:13 +0200975 cb = mei_io_cb_init(cl, NULL);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200976 if (!cb) {
977 rets = -ENOMEM;
978 goto out;
979 }
Tomas Winkler9ca90502013-01-08 23:07:13 +0200980
Tomas Winkler5db75142015-02-10 10:39:42 +0200981 rets = mei_io_cb_alloc_buf(cb, length);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200982 if (rets)
Tomas Winkler04bb1392014-03-18 22:52:04 +0200983 goto out;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200984
985 cb->fop_type = MEI_FOP_READ;
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200986 if (mei_hbuf_acquire(dev)) {
Alexander Usyskin86113502014-03-31 17:59:24 +0300987 rets = mei_hbm_cl_flow_control_req(dev, cl);
988 if (rets < 0)
Tomas Winkler04bb1392014-03-18 22:52:04 +0200989 goto out;
Tomas Winkler04bb1392014-03-18 22:52:04 +0200990
Tomas Winkler9ca90502013-01-08 23:07:13 +0200991 list_add_tail(&cb->list, &dev->read_list.list);
992 } else {
993 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
994 }
Chao Biaccb8842014-02-12 21:27:25 +0200995
996 cl->read_cb = cb;
997
Tomas Winkler04bb1392014-03-18 22:52:04 +0200998out:
999 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001000 pm_runtime_mark_last_busy(dev->dev);
1001 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001002
1003 if (rets)
1004 mei_io_cb_free(cb);
1005
Tomas Winkler9ca90502013-01-08 23:07:13 +02001006 return rets;
1007}
1008
Tomas Winkler074b4c02013-02-06 14:06:44 +02001009/**
Tomas Winkler9d098192014-02-19 17:35:48 +02001010 * mei_cl_irq_write - write a message to device
Tomas Winkler21767542013-06-23 09:36:59 +03001011 * from the interrupt thread context
1012 *
1013 * @cl: client
1014 * @cb: callback block.
Tomas Winkler21767542013-06-23 09:36:59 +03001015 * @cmpl_list: complete list.
1016 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001017 * Return: 0, OK; otherwise error.
Tomas Winkler21767542013-06-23 09:36:59 +03001018 */
Tomas Winkler9d098192014-02-19 17:35:48 +02001019int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
1020 struct mei_cl_cb *cmpl_list)
Tomas Winkler21767542013-06-23 09:36:59 +03001021{
Tomas Winkler136698e2013-09-16 23:44:44 +03001022 struct mei_device *dev;
1023 struct mei_msg_data *buf;
Tomas Winkler21767542013-06-23 09:36:59 +03001024 struct mei_msg_hdr mei_hdr;
Tomas Winkler136698e2013-09-16 23:44:44 +03001025 size_t len;
1026 u32 msg_slots;
Tomas Winkler9d098192014-02-19 17:35:48 +02001027 int slots;
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001028 int rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001029
Tomas Winkler136698e2013-09-16 23:44:44 +03001030 if (WARN_ON(!cl || !cl->dev))
1031 return -ENODEV;
1032
1033 dev = cl->dev;
1034
Tomas Winkler5db75142015-02-10 10:39:42 +02001035 buf = &cb->buf;
Tomas Winkler136698e2013-09-16 23:44:44 +03001036
1037 rets = mei_cl_flow_ctrl_creds(cl);
1038 if (rets < 0)
1039 return rets;
1040
1041 if (rets == 0) {
Tomas Winkler04bb1392014-03-18 22:52:04 +02001042 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
Tomas Winkler136698e2013-09-16 23:44:44 +03001043 return 0;
1044 }
1045
Tomas Winkler9d098192014-02-19 17:35:48 +02001046 slots = mei_hbuf_empty_slots(dev);
Tomas Winkler136698e2013-09-16 23:44:44 +03001047 len = buf->size - cb->buf_idx;
1048 msg_slots = mei_data2slots(len);
1049
Tomas Winkler21767542013-06-23 09:36:59 +03001050 mei_hdr.host_addr = cl->host_client_id;
1051 mei_hdr.me_addr = cl->me_client_id;
1052 mei_hdr.reserved = 0;
Tomas Winkler479327f2013-12-17 15:56:56 +02001053 mei_hdr.internal = cb->internal;
Tomas Winkler21767542013-06-23 09:36:59 +03001054
Tomas Winkler9d098192014-02-19 17:35:48 +02001055 if (slots >= msg_slots) {
Tomas Winkler21767542013-06-23 09:36:59 +03001056 mei_hdr.length = len;
1057 mei_hdr.msg_complete = 1;
1058 /* Split the message only if we can write the whole host buffer */
Tomas Winkler9d098192014-02-19 17:35:48 +02001059 } else if (slots == dev->hbuf_depth) {
1060 msg_slots = slots;
1061 len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
Tomas Winkler21767542013-06-23 09:36:59 +03001062 mei_hdr.length = len;
1063 mei_hdr.msg_complete = 0;
1064 } else {
1065 /* wait for next time the host buffer is empty */
1066 return 0;
1067 }
1068
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001069 cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
Tomas Winkler5db75142015-02-10 10:39:42 +02001070 cb->buf.size, cb->buf_idx);
Tomas Winkler21767542013-06-23 09:36:59 +03001071
Tomas Winkler136698e2013-09-16 23:44:44 +03001072 rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001073 if (rets) {
1074 cl->status = rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001075 list_move_tail(&cb->list, &cmpl_list->list);
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001076 return rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001077 }
1078
1079 cl->status = 0;
Tomas Winkler4dfaa9f2013-06-23 09:37:00 +03001080 cl->writing_state = MEI_WRITING;
Tomas Winkler21767542013-06-23 09:36:59 +03001081 cb->buf_idx += mei_hdr.length;
Tomas Winkler86601722015-02-10 10:39:40 +02001082 cb->completed = mei_hdr.msg_complete == 1;
Tomas Winkler4dfaa9f2013-06-23 09:37:00 +03001083
Tomas Winkler21767542013-06-23 09:36:59 +03001084 if (mei_hdr.msg_complete) {
1085 if (mei_cl_flow_ctrl_reduce(cl))
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001086 return -EIO;
Tomas Winkler21767542013-06-23 09:36:59 +03001087 list_move_tail(&cb->list, &dev->write_waiting_list.list);
1088 }
1089
1090 return 0;
1091}
1092
1093/**
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001094 * mei_cl_write - submit a write cb to mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001095 * assumes device_lock is locked
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001096 *
1097 * @cl: host client
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001098 * @cb: write callback with filled data
Alexander Usyskince231392014-09-29 16:31:50 +03001099 * @blocking: block until completed
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001100 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001101 * Return: number of bytes sent on success, <0 on failure.
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001102 */
1103int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
1104{
1105 struct mei_device *dev;
1106 struct mei_msg_data *buf;
1107 struct mei_msg_hdr mei_hdr;
1108 int rets;
1109
1110
1111 if (WARN_ON(!cl || !cl->dev))
1112 return -ENODEV;
1113
1114 if (WARN_ON(!cb))
1115 return -EINVAL;
1116
1117 dev = cl->dev;
1118
1119
Tomas Winkler5db75142015-02-10 10:39:42 +02001120 buf = &cb->buf;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001121
Alexander Usyskin0a01e972014-09-29 16:31:47 +03001122 cl_dbg(dev, cl, "size=%d\n", buf->size);
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001123
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001124 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001125 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001126 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001127 cl_err(dev, cl, "rpm: get failed %d\n", rets);
1128 return rets;
1129 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001130
1131 cb->fop_type = MEI_FOP_WRITE;
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001132 cb->buf_idx = 0;
1133 cl->writing_state = MEI_IDLE;
1134
1135 mei_hdr.host_addr = cl->host_client_id;
1136 mei_hdr.me_addr = cl->me_client_id;
1137 mei_hdr.reserved = 0;
1138 mei_hdr.msg_complete = 0;
1139 mei_hdr.internal = cb->internal;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001140
1141 rets = mei_cl_flow_ctrl_creds(cl);
1142 if (rets < 0)
1143 goto err;
1144
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001145 if (rets == 0) {
1146 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001147 rets = buf->size;
1148 goto out;
1149 }
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001150 if (!mei_hbuf_acquire(dev)) {
1151 cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
1152 rets = buf->size;
1153 goto out;
1154 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001155
1156 /* Check for a maximum length */
1157 if (buf->size > mei_hbuf_max_len(dev)) {
1158 mei_hdr.length = mei_hbuf_max_len(dev);
1159 mei_hdr.msg_complete = 0;
1160 } else {
1161 mei_hdr.length = buf->size;
1162 mei_hdr.msg_complete = 1;
1163 }
1164
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001165 rets = mei_write_message(dev, &mei_hdr, buf->data);
1166 if (rets)
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001167 goto err;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001168
1169 cl->writing_state = MEI_WRITING;
1170 cb->buf_idx = mei_hdr.length;
Tomas Winkler86601722015-02-10 10:39:40 +02001171 cb->completed = mei_hdr.msg_complete == 1;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001172
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001173out:
1174 if (mei_hdr.msg_complete) {
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001175 rets = mei_cl_flow_ctrl_reduce(cl);
1176 if (rets < 0)
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001177 goto err;
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001178
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001179 list_add_tail(&cb->list, &dev->write_waiting_list.list);
1180 } else {
1181 list_add_tail(&cb->list, &dev->write_list.list);
1182 }
1183
1184
1185 if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
1186
1187 mutex_unlock(&dev->device_lock);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001188 rets = wait_event_interruptible(cl->tx_wait,
1189 cl->writing_state == MEI_WRITE_COMPLETE);
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001190 mutex_lock(&dev->device_lock);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001191 /* wait_event_interruptible returns -ERESTARTSYS */
1192 if (rets) {
1193 if (signal_pending(current))
1194 rets = -EINTR;
1195 goto err;
1196 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001197 }
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001198
1199 rets = buf->size;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001200err:
Tomas Winkler04bb1392014-03-18 22:52:04 +02001201 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001202 pm_runtime_mark_last_busy(dev->dev);
1203 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001204
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001205 return rets;
1206}
1207
1208
Tomas Winklerdb086fa2013-05-12 15:34:45 +03001209/**
1210 * mei_cl_complete - processes completed operation for a client
1211 *
1212 * @cl: private data of the file object.
1213 * @cb: callback block.
1214 */
1215void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
1216{
1217 if (cb->fop_type == MEI_FOP_WRITE) {
1218 mei_io_cb_free(cb);
1219 cb = NULL;
1220 cl->writing_state = MEI_WRITE_COMPLETE;
1221 if (waitqueue_active(&cl->tx_wait))
1222 wake_up_interruptible(&cl->tx_wait);
1223
1224 } else if (cb->fop_type == MEI_FOP_READ &&
1225 MEI_READING == cl->reading_state) {
1226 cl->reading_state = MEI_READ_COMPLETE;
1227 if (waitqueue_active(&cl->rx_wait))
1228 wake_up_interruptible(&cl->rx_wait);
1229 else
1230 mei_cl_bus_rx_event(cl);
1231
1232 }
1233}
1234
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001235
1236/**
Tomas Winkler074b4c02013-02-06 14:06:44 +02001237 * mei_cl_all_disconnect - disconnect forcefully all connected clients
1238 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001239 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001240 */
1241
1242void mei_cl_all_disconnect(struct mei_device *dev)
1243{
Tomas Winkler31f88f52014-02-17 15:13:25 +02001244 struct mei_cl *cl;
Tomas Winkler074b4c02013-02-06 14:06:44 +02001245
Tomas Winkler31f88f52014-02-17 15:13:25 +02001246 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winkler074b4c02013-02-06 14:06:44 +02001247 cl->state = MEI_FILE_DISCONNECTED;
1248 cl->mei_flow_ctrl_creds = 0;
Tomas Winkler074b4c02013-02-06 14:06:44 +02001249 cl->timer_count = 0;
1250 }
1251}
1252
1253
1254/**
Tomas Winkler52908012013-07-24 16:22:57 +03001255 * mei_cl_all_wakeup - wake up all readers and writers they can be interrupted
Tomas Winkler074b4c02013-02-06 14:06:44 +02001256 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001257 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001258 */
Tomas Winkler52908012013-07-24 16:22:57 +03001259void mei_cl_all_wakeup(struct mei_device *dev)
Tomas Winkler074b4c02013-02-06 14:06:44 +02001260{
Tomas Winkler31f88f52014-02-17 15:13:25 +02001261 struct mei_cl *cl;
Tomas Winkler92db1552014-09-29 16:31:37 +03001262
Tomas Winkler31f88f52014-02-17 15:13:25 +02001263 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winkler074b4c02013-02-06 14:06:44 +02001264 if (waitqueue_active(&cl->rx_wait)) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001265 cl_dbg(dev, cl, "Waking up reading client!\n");
Tomas Winkler074b4c02013-02-06 14:06:44 +02001266 wake_up_interruptible(&cl->rx_wait);
1267 }
Tomas Winkler52908012013-07-24 16:22:57 +03001268 if (waitqueue_active(&cl->tx_wait)) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001269 cl_dbg(dev, cl, "Waking up writing client!\n");
Tomas Winkler52908012013-07-24 16:22:57 +03001270 wake_up_interruptible(&cl->tx_wait);
1271 }
Tomas Winkler074b4c02013-02-06 14:06:44 +02001272 }
1273}
1274
1275/**
1276 * mei_cl_all_write_clear - clear all pending writes
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001277 *
1278 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001279 */
1280void mei_cl_all_write_clear(struct mei_device *dev)
1281{
Tomas Winklercc99ecf2014-03-10 15:10:40 +02001282 mei_io_list_free(&dev->write_list, NULL);
1283 mei_io_list_free(&dev->write_waiting_list, NULL);
Tomas Winkler074b4c02013-02-06 14:06:44 +02001284}
1285
1286