blob: 48813c27a47c9ce036f8c9c58cfa96bd47f1ce01 [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 Winkler90e0b5f2013-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 Winkler90e0b5f2013-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 Winkler90e0b5f2013-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 Winkler90e0b5f2013-01-08 23:07:14 +0200157{
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300158 struct mei_me_client *me_cl;
Tomas Winkler90e0b5f2013-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 Winkler90e0b5f2013-01-08 23:07:14 +0200163
Tomas Winklerb7d88512015-02-10 10:39:31 +0200164 return me_cl;
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200165}
166
Tomas Winkler90e0b5f2013-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 Winkler90e0b5f2013-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 Winkler90e0b5f2013-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 Winkler90e0b5f2013-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 Winkler90e0b5f2013-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 Winkler90e0b5f2013-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/**
324 * mei_io_list_flush - removes cbs belonging to cl.
325 *
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
379 kfree(cb->request_buffer.data);
380 kfree(cb->response_buffer.data);
381 kfree(cb);
382}
383
384/**
385 * mei_io_cb_init - allocate and initialize io callback
386 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300387 * @cl: mei client
Masanari Iida393b1482013-04-05 01:05:05 +0900388 * @fp: pointer to file structure
Tomas Winkler9ca90502013-01-08 23:07:13 +0200389 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300390 * Return: mei_cl_cb pointer or NULL;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200391 */
392struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
393{
394 struct mei_cl_cb *cb;
395
396 cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
397 if (!cb)
398 return NULL;
399
400 mei_io_list_init(cb);
401
402 cb->file_object = fp;
403 cb->cl = cl;
404 cb->buf_idx = 0;
405 return cb;
406}
407
408/**
409 * mei_io_cb_alloc_req_buf - allocate request buffer
410 *
Masanari Iida393b1482013-04-05 01:05:05 +0900411 * @cb: io callback structure
412 * @length: size of the buffer
Tomas Winkler9ca90502013-01-08 23:07:13 +0200413 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300414 * Return: 0 on success
Tomas Winkler9ca90502013-01-08 23:07:13 +0200415 * -EINVAL if cb is NULL
416 * -ENOMEM if allocation failed
417 */
418int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
419{
420 if (!cb)
421 return -EINVAL;
422
423 if (length == 0)
424 return 0;
425
426 cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
427 if (!cb->request_buffer.data)
428 return -ENOMEM;
429 cb->request_buffer.size = length;
430 return 0;
431}
432/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200433 * mei_io_cb_alloc_resp_buf - allocate response buffer
Tomas Winkler9ca90502013-01-08 23:07:13 +0200434 *
Masanari Iida393b1482013-04-05 01:05:05 +0900435 * @cb: io callback structure
436 * @length: size of the buffer
Tomas Winkler9ca90502013-01-08 23:07:13 +0200437 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300438 * Return: 0 on success
Tomas Winkler9ca90502013-01-08 23:07:13 +0200439 * -EINVAL if cb is NULL
440 * -ENOMEM if allocation failed
441 */
442int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
443{
444 if (!cb)
445 return -EINVAL;
446
447 if (length == 0)
448 return 0;
449
450 cb->response_buffer.data = kmalloc(length, GFP_KERNEL);
451 if (!cb->response_buffer.data)
452 return -ENOMEM;
453 cb->response_buffer.size = length;
454 return 0;
455}
456
457
458
459/**
460 * mei_cl_flush_queues - flushes queue lists belonging to cl.
461 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200462 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300463 *
464 * Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200465 */
466int mei_cl_flush_queues(struct mei_cl *cl)
467{
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300468 struct mei_device *dev;
469
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200470 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200471 return -EINVAL;
472
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300473 dev = cl->dev;
474
475 cl_dbg(dev, cl, "remove list entry belonging to cl\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200476 mei_io_list_flush(&cl->dev->read_list, cl);
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200477 mei_io_list_free(&cl->dev->write_list, cl);
478 mei_io_list_free(&cl->dev->write_waiting_list, cl);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200479 mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
480 mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
481 mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
482 mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
483 return 0;
484}
485
Tomas Winkler9ca90502013-01-08 23:07:13 +0200486
487/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200488 * mei_cl_init - initializes cl.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200489 *
490 * @cl: host client to be initialized
491 * @dev: mei device
492 */
493void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
494{
495 memset(cl, 0, sizeof(struct mei_cl));
496 init_waitqueue_head(&cl->wait);
497 init_waitqueue_head(&cl->rx_wait);
498 init_waitqueue_head(&cl->tx_wait);
499 INIT_LIST_HEAD(&cl->link);
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200500 INIT_LIST_HEAD(&cl->device_link);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200501 cl->reading_state = MEI_IDLE;
502 cl->writing_state = MEI_IDLE;
503 cl->dev = dev;
504}
505
506/**
507 * mei_cl_allocate - allocates cl structure and sets it up.
508 *
509 * @dev: mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300510 * Return: The allocated file or NULL on failure
Tomas Winkler9ca90502013-01-08 23:07:13 +0200511 */
512struct mei_cl *mei_cl_allocate(struct mei_device *dev)
513{
514 struct mei_cl *cl;
515
516 cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
517 if (!cl)
518 return NULL;
519
520 mei_cl_init(cl, dev);
521
522 return cl;
523}
524
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200525/**
526 * mei_cl_find_read_cb - find this cl's callback in the read list
527 *
Masanari Iida393b1482013-04-05 01:05:05 +0900528 * @cl: host client
529 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300530 * Return: cb on success, NULL on error
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200531 */
532struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
533{
534 struct mei_device *dev = cl->dev;
Tomas Winkler31f88f52014-02-17 15:13:25 +0200535 struct mei_cl_cb *cb;
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200536
Tomas Winkler31f88f52014-02-17 15:13:25 +0200537 list_for_each_entry(cb, &dev->read_list.list, list)
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200538 if (mei_cl_cmp_id(cl, cb->cl))
539 return cb;
540 return NULL;
541}
542
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200543/** mei_cl_link: allocate host id in the host map
Tomas Winkler9ca90502013-01-08 23:07:13 +0200544 *
Tomas Winkler781d0d82013-01-08 23:07:22 +0200545 * @cl - host client
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200546 * @id - fixed host id or -1 for generic one
Masanari Iida393b1482013-04-05 01:05:05 +0900547 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300548 * Return: 0 on success
Tomas Winkler9ca90502013-01-08 23:07:13 +0200549 * -EINVAL on incorrect values
550 * -ENONET if client not found
551 */
Tomas Winkler781d0d82013-01-08 23:07:22 +0200552int mei_cl_link(struct mei_cl *cl, int id)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200553{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200554 struct mei_device *dev;
Tomas Winkler22f96a02013-09-16 23:44:47 +0300555 long open_handle_count;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200556
Tomas Winkler781d0d82013-01-08 23:07:22 +0200557 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200558 return -EINVAL;
559
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200560 dev = cl->dev;
561
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200562 /* If Id is not assigned get one*/
Tomas Winkler781d0d82013-01-08 23:07:22 +0200563 if (id == MEI_HOST_CLIENT_ID_ANY)
564 id = find_first_zero_bit(dev->host_clients_map,
565 MEI_CLIENTS_MAX);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200566
Tomas Winkler781d0d82013-01-08 23:07:22 +0200567 if (id >= MEI_CLIENTS_MAX) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300568 dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
Tomas Winklere036cc52013-09-16 23:44:46 +0300569 return -EMFILE;
570 }
571
Tomas Winkler22f96a02013-09-16 23:44:47 +0300572 open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
573 if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300574 dev_err(dev->dev, "open_handle_count exceeded %d",
Tomas Winklere036cc52013-09-16 23:44:46 +0300575 MEI_MAX_OPEN_HANDLE_COUNT);
576 return -EMFILE;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200577 }
578
Tomas Winkler781d0d82013-01-08 23:07:22 +0200579 dev->open_handle_count++;
580
581 cl->host_client_id = id;
582 list_add_tail(&cl->link, &dev->file_list);
583
584 set_bit(id, dev->host_clients_map);
585
586 cl->state = MEI_FILE_INITIALIZING;
587
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300588 cl_dbg(dev, cl, "link cl\n");
Tomas Winkler781d0d82013-01-08 23:07:22 +0200589 return 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200590}
Tomas Winkler781d0d82013-01-08 23:07:22 +0200591
Tomas Winkler9ca90502013-01-08 23:07:13 +0200592/**
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200593 * mei_cl_unlink - remove me_cl from the list
Tomas Winkler9ca90502013-01-08 23:07:13 +0200594 *
Masanari Iida393b1482013-04-05 01:05:05 +0900595 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300596 *
597 * Return: always 0
Tomas Winkler9ca90502013-01-08 23:07:13 +0200598 */
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200599int mei_cl_unlink(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200600{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200601 struct mei_device *dev;
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200602
Tomas Winkler781d0d82013-01-08 23:07:22 +0200603 /* don't shout on error exit path */
604 if (!cl)
605 return 0;
606
Tomas Winkler8e9a4a92013-01-10 17:32:14 +0200607 /* wd and amthif might not be initialized */
608 if (!cl->dev)
609 return 0;
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200610
611 dev = cl->dev;
612
Tomas Winklera14c44d2013-09-16 23:44:45 +0300613 cl_dbg(dev, cl, "unlink client");
614
Tomas Winkler22f96a02013-09-16 23:44:47 +0300615 if (dev->open_handle_count > 0)
616 dev->open_handle_count--;
617
618 /* never clear the 0 bit */
619 if (cl->host_client_id)
620 clear_bit(cl->host_client_id, dev->host_clients_map);
621
622 list_del_init(&cl->link);
623
624 cl->state = MEI_FILE_INITIALIZING;
625
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200626 return 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200627}
628
629
630void mei_host_client_init(struct work_struct *work)
631{
Tomas Winklerb7d88512015-02-10 10:39:31 +0200632 struct mei_device *dev =
633 container_of(work, struct mei_device, init_work);
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300634 struct mei_me_client *me_cl;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200635
636 mutex_lock(&dev->device_lock);
637
Tomas Winkler9ca90502013-01-08 23:07:13 +0200638
Tomas Winklerb7d88512015-02-10 10:39:31 +0200639 me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
640 if (me_cl)
641 mei_amthif_host_init(dev);
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200642
Tomas Winklerb7d88512015-02-10 10:39:31 +0200643 me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid);
644 if (me_cl)
645 mei_wd_host_init(dev);
646
647 me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
648 if (me_cl)
649 mei_nfc_host_init(dev);
650
Tomas Winkler9ca90502013-01-08 23:07:13 +0200651
652 dev->dev_state = MEI_DEV_ENABLED;
Tomas Winkler6adb8ef2014-01-12 00:36:10 +0200653 dev->reset_count = 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200654 mutex_unlock(&dev->device_lock);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200655
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300656 pm_runtime_mark_last_busy(dev->dev);
657 dev_dbg(dev->dev, "rpm: autosuspend\n");
658 pm_runtime_autosuspend(dev->dev);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200659}
660
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200661/**
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300662 * mei_hbuf_acquire - try to acquire host buffer
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200663 *
664 * @dev: the device structure
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300665 * Return: true if host buffer was acquired
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200666 */
667bool mei_hbuf_acquire(struct mei_device *dev)
668{
Tomas Winkler04bb1392014-03-18 22:52:04 +0200669 if (mei_pg_state(dev) == MEI_PG_ON ||
670 dev->pg_event == MEI_PG_EVENT_WAIT) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300671 dev_dbg(dev->dev, "device is in pg\n");
Tomas Winkler04bb1392014-03-18 22:52:04 +0200672 return false;
673 }
674
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200675 if (!dev->hbuf_is_ready) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300676 dev_dbg(dev->dev, "hbuf is not ready\n");
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200677 return false;
678 }
679
680 dev->hbuf_is_ready = false;
681
682 return true;
683}
Tomas Winkler9ca90502013-01-08 23:07:13 +0200684
685/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200686 * mei_cl_disconnect - disconnect host client from the me one
Tomas Winkler9ca90502013-01-08 23:07:13 +0200687 *
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200688 * @cl: host client
Tomas Winkler9ca90502013-01-08 23:07:13 +0200689 *
690 * Locking: called under "dev->device_lock" lock
691 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300692 * Return: 0 on success, <0 on failure.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200693 */
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200694int mei_cl_disconnect(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200695{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200696 struct mei_device *dev;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200697 struct mei_cl_cb *cb;
Alexander Usyskinfe2f17eb32014-07-17 10:53:38 +0300698 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200699
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200700 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200701 return -ENODEV;
702
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200703 dev = cl->dev;
704
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300705 cl_dbg(dev, cl, "disconnecting");
706
Tomas Winkler9ca90502013-01-08 23:07:13 +0200707 if (cl->state != MEI_FILE_DISCONNECTING)
708 return 0;
709
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300710 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200711 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300712 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200713 cl_err(dev, cl, "rpm: get failed %d\n", rets);
714 return rets;
715 }
716
Tomas Winkler9ca90502013-01-08 23:07:13 +0200717 cb = mei_io_cb_init(cl, NULL);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200718 if (!cb) {
719 rets = -ENOMEM;
720 goto free;
721 }
Tomas Winkler9ca90502013-01-08 23:07:13 +0200722
Tomas Winkler5a8373f2014-08-21 14:29:17 +0300723 cb->fop_type = MEI_FOP_DISCONNECT;
724
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200725 if (mei_hbuf_acquire(dev)) {
Tomas Winkler9ca90502013-01-08 23:07:13 +0200726 if (mei_hbm_cl_disconnect_req(dev, cl)) {
727 rets = -ENODEV;
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300728 cl_err(dev, cl, "failed to disconnect.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200729 goto free;
730 }
Alexander Usyskin22b987a2014-07-17 10:53:35 +0300731 cl->timer_count = MEI_CONNECT_TIMEOUT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200732 mdelay(10); /* Wait for hardware disconnection ready */
733 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
734 } else {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300735 cl_dbg(dev, cl, "add disconnect cb to control write list\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200736 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
737
738 }
739 mutex_unlock(&dev->device_lock);
740
Tomas Winkler12f45ed2014-08-21 14:29:18 +0300741 wait_event_timeout(cl->wait,
Tomas Winkler9ca90502013-01-08 23:07:13 +0200742 MEI_FILE_DISCONNECTED == cl->state,
743 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
744
745 mutex_lock(&dev->device_lock);
Alexander Usyskinfe2f17eb32014-07-17 10:53:38 +0300746
Tomas Winkler9ca90502013-01-08 23:07:13 +0200747 if (MEI_FILE_DISCONNECTED == cl->state) {
748 rets = 0;
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300749 cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200750 } else {
Alexander Usyskinfe2f17eb32014-07-17 10:53:38 +0300751 cl_dbg(dev, cl, "timeout on disconnect from FW client.\n");
752 rets = -ETIME;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200753 }
754
755 mei_io_list_flush(&dev->ctrl_rd_list, cl);
756 mei_io_list_flush(&dev->ctrl_wr_list, cl);
757free:
Tomas Winkler04bb1392014-03-18 22:52:04 +0200758 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300759 pm_runtime_mark_last_busy(dev->dev);
760 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200761
Tomas Winkler9ca90502013-01-08 23:07:13 +0200762 mei_io_cb_free(cb);
763 return rets;
764}
765
766
767/**
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200768 * mei_cl_is_other_connecting - checks if other
769 * client with the same me client id is connecting
Tomas Winkler9ca90502013-01-08 23:07:13 +0200770 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200771 * @cl: private data of the file object
772 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300773 * Return: true if other client is connected, false - otherwise.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200774 */
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200775bool mei_cl_is_other_connecting(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200776{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200777 struct mei_device *dev;
Tomas Winkler31f88f52014-02-17 15:13:25 +0200778 struct mei_cl *ocl; /* the other client */
Tomas Winkler9ca90502013-01-08 23:07:13 +0200779
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200780 if (WARN_ON(!cl || !cl->dev))
781 return false;
782
783 dev = cl->dev;
784
Tomas Winkler31f88f52014-02-17 15:13:25 +0200785 list_for_each_entry(ocl, &dev->file_list, link) {
786 if (ocl->state == MEI_FILE_CONNECTING &&
787 ocl != cl &&
788 cl->me_client_id == ocl->me_client_id)
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200789 return true;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200790
791 }
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200792
793 return false;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200794}
795
796/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200797 * mei_cl_connect - connect host client to the me one
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200798 *
799 * @cl: host client
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300800 * @file: pointer to file structure
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200801 *
802 * Locking: called under "dev->device_lock" lock
803 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300804 * Return: 0 on success, <0 on failure.
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200805 */
806int mei_cl_connect(struct mei_cl *cl, struct file *file)
807{
808 struct mei_device *dev;
809 struct mei_cl_cb *cb;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200810 int rets;
811
812 if (WARN_ON(!cl || !cl->dev))
813 return -ENODEV;
814
815 dev = cl->dev;
816
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300817 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200818 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300819 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200820 cl_err(dev, cl, "rpm: get failed %d\n", rets);
821 return rets;
822 }
823
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200824 cb = mei_io_cb_init(cl, file);
825 if (!cb) {
826 rets = -ENOMEM;
827 goto out;
828 }
829
Tomas Winkler02a7eec2014-02-12 21:41:51 +0200830 cb->fop_type = MEI_FOP_CONNECT;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200831
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200832 /* run hbuf acquire last so we don't have to undo */
833 if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
Alexander Usyskine4d82702014-04-27 15:42:21 +0300834 cl->state = MEI_FILE_CONNECTING;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200835 if (mei_hbm_cl_connect_req(dev, cl)) {
836 rets = -ENODEV;
837 goto out;
838 }
839 cl->timer_count = MEI_CONNECT_TIMEOUT;
840 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
841 } else {
Alexander Usyskin73ab4232014-08-12 18:07:56 +0300842 cl->state = MEI_FILE_INITIALIZING;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200843 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
844 }
845
846 mutex_unlock(&dev->device_lock);
Tomas Winkler12f45ed2014-08-21 14:29:18 +0300847 wait_event_timeout(cl->wait,
Alexander Usyskin285e2992014-02-17 15:13:20 +0200848 (cl->state == MEI_FILE_CONNECTED ||
849 cl->state == MEI_FILE_DISCONNECTED),
850 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200851 mutex_lock(&dev->device_lock);
852
853 if (cl->state != MEI_FILE_CONNECTED) {
Alexander Usyskin3e37ebb2014-07-17 10:53:34 +0300854 cl->state = MEI_FILE_DISCONNECTED;
Alexander Usyskin285e2992014-02-17 15:13:20 +0200855 /* something went really wrong */
856 if (!cl->status)
857 cl->status = -EFAULT;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200858
859 mei_io_list_flush(&dev->ctrl_rd_list, cl);
860 mei_io_list_flush(&dev->ctrl_wr_list, cl);
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200861 }
862
863 rets = cl->status;
864
865out:
Tomas Winkler04bb1392014-03-18 22:52:04 +0200866 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300867 pm_runtime_mark_last_busy(dev->dev);
868 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200869
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200870 mei_io_cb_free(cb);
871 return rets;
872}
873
874/**
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200875 * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200876 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200877 * @cl: private data of the file object
878 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300879 * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200880 * -ENOENT if mei_cl is not present
881 * -EINVAL if single_recv_buf == 0
882 */
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200883int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200884{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200885 struct mei_device *dev;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200886 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200887 int rets = 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200888
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200889 if (WARN_ON(!cl || !cl->dev))
890 return -EINVAL;
891
892 dev = cl->dev;
893
Tomas Winkler9ca90502013-01-08 23:07:13 +0200894 if (cl->mei_flow_ctrl_creds > 0)
895 return 1;
896
Tomas Winkler2e5df412014-12-07 16:40:14 +0200897 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300898 if (!me_cl) {
Alexander Usyskin12d00662014-02-17 15:13:23 +0200899 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300900 return -ENOENT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200901 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200902
Tomas Winkler79563db2015-01-11 00:07:16 +0200903 if (me_cl->mei_flow_ctrl_creds > 0) {
904 rets = 1;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200905 if (WARN_ON(me_cl->props.single_recv_buf == 0))
Tomas Winkler79563db2015-01-11 00:07:16 +0200906 rets = -EINVAL;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200907 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200908 mei_me_cl_put(me_cl);
909 return rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200910}
911
912/**
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200913 * mei_cl_flow_ctrl_reduce - reduces flow_control.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200914 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200915 * @cl: private data of the file object
Masanari Iida393b1482013-04-05 01:05:05 +0900916 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300917 * Return:
Tomas Winkler9ca90502013-01-08 23:07:13 +0200918 * 0 on success
919 * -ENOENT when me client is not found
920 * -EINVAL when ctrl credits are <= 0
921 */
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200922int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200923{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200924 struct mei_device *dev;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200925 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200926 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200927
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200928 if (WARN_ON(!cl || !cl->dev))
929 return -EINVAL;
930
931 dev = cl->dev;
932
Tomas Winkler2e5df412014-12-07 16:40:14 +0200933 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300934 if (!me_cl) {
Alexander Usyskin12d00662014-02-17 15:13:23 +0200935 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300936 return -ENOENT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200937 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200938
Tomas Winklerd3208322014-08-24 12:08:55 +0300939 if (me_cl->props.single_recv_buf) {
Tomas Winkler79563db2015-01-11 00:07:16 +0200940 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
941 rets = -EINVAL;
942 goto out;
943 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200944 me_cl->mei_flow_ctrl_creds--;
945 } else {
Tomas Winkler79563db2015-01-11 00:07:16 +0200946 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
947 rets = -EINVAL;
948 goto out;
949 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200950 cl->mei_flow_ctrl_creds--;
951 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200952 rets = 0;
953out:
954 mei_me_cl_put(me_cl);
955 return rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200956}
957
Tomas Winkler9ca90502013-01-08 23:07:13 +0200958/**
Masanari Iida393b1482013-04-05 01:05:05 +0900959 * mei_cl_read_start - the start read client message function.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200960 *
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200961 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300962 * @length: number of bytes to read
Tomas Winkler9ca90502013-01-08 23:07:13 +0200963 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300964 * Return: 0 on success, <0 on failure.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200965 */
Tomas Winklerfcb136e2013-04-19 22:01:35 +0300966int mei_cl_read_start(struct mei_cl *cl, size_t length)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200967{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200968 struct mei_device *dev;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200969 struct mei_cl_cb *cb;
Tomas Winklerd3208322014-08-24 12:08:55 +0300970 struct mei_me_client *me_cl;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200971 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200972
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200973 if (WARN_ON(!cl || !cl->dev))
974 return -ENODEV;
975
976 dev = cl->dev;
977
Tomas Winklerb950ac12013-07-25 20:15:53 +0300978 if (!mei_cl_is_connected(cl))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200979 return -ENODEV;
980
Tomas Winklerd91aaed2013-01-08 23:07:18 +0200981 if (cl->read_cb) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300982 cl_dbg(dev, cl, "read is pending.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200983 return -EBUSY;
984 }
Tomas Winklerd880f322014-08-21 14:29:15 +0300985 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300986 if (!me_cl) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300987 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +0200988 return -ENOTTY;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200989 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200990 /* always allocate at least client max message */
991 length = max_t(size_t, length, me_cl->props.max_msg_length);
992 mei_me_cl_put(me_cl);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200993
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300994 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200995 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300996 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200997 cl_err(dev, cl, "rpm: get failed %d\n", rets);
998 return rets;
999 }
1000
Tomas Winkler9ca90502013-01-08 23:07:13 +02001001 cb = mei_io_cb_init(cl, NULL);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001002 if (!cb) {
1003 rets = -ENOMEM;
1004 goto out;
1005 }
Tomas Winkler9ca90502013-01-08 23:07:13 +02001006
Tomas Winklerfcb136e2013-04-19 22:01:35 +03001007 rets = mei_io_cb_alloc_resp_buf(cb, length);
Tomas Winkler9ca90502013-01-08 23:07:13 +02001008 if (rets)
Tomas Winkler04bb1392014-03-18 22:52:04 +02001009 goto out;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001010
1011 cb->fop_type = MEI_FOP_READ;
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001012 if (mei_hbuf_acquire(dev)) {
Alexander Usyskin86113502014-03-31 17:59:24 +03001013 rets = mei_hbm_cl_flow_control_req(dev, cl);
1014 if (rets < 0)
Tomas Winkler04bb1392014-03-18 22:52:04 +02001015 goto out;
Tomas Winkler04bb1392014-03-18 22:52:04 +02001016
Tomas Winkler9ca90502013-01-08 23:07:13 +02001017 list_add_tail(&cb->list, &dev->read_list.list);
1018 } else {
1019 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
1020 }
Chao Biaccb8842014-02-12 21:27:25 +02001021
1022 cl->read_cb = cb;
1023
Tomas Winkler04bb1392014-03-18 22:52:04 +02001024out:
1025 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001026 pm_runtime_mark_last_busy(dev->dev);
1027 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001028
1029 if (rets)
1030 mei_io_cb_free(cb);
1031
Tomas Winkler9ca90502013-01-08 23:07:13 +02001032 return rets;
1033}
1034
Tomas Winkler074b4c02013-02-06 14:06:44 +02001035/**
Tomas Winkler9d098192014-02-19 17:35:48 +02001036 * mei_cl_irq_write - write a message to device
Tomas Winkler21767542013-06-23 09:36:59 +03001037 * from the interrupt thread context
1038 *
1039 * @cl: client
1040 * @cb: callback block.
Tomas Winkler21767542013-06-23 09:36:59 +03001041 * @cmpl_list: complete list.
1042 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001043 * Return: 0, OK; otherwise error.
Tomas Winkler21767542013-06-23 09:36:59 +03001044 */
Tomas Winkler9d098192014-02-19 17:35:48 +02001045int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
1046 struct mei_cl_cb *cmpl_list)
Tomas Winkler21767542013-06-23 09:36:59 +03001047{
Tomas Winkler136698e2013-09-16 23:44:44 +03001048 struct mei_device *dev;
1049 struct mei_msg_data *buf;
Tomas Winkler21767542013-06-23 09:36:59 +03001050 struct mei_msg_hdr mei_hdr;
Tomas Winkler136698e2013-09-16 23:44:44 +03001051 size_t len;
1052 u32 msg_slots;
Tomas Winkler9d098192014-02-19 17:35:48 +02001053 int slots;
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001054 int rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001055
Tomas Winkler136698e2013-09-16 23:44:44 +03001056 if (WARN_ON(!cl || !cl->dev))
1057 return -ENODEV;
1058
1059 dev = cl->dev;
1060
1061 buf = &cb->request_buffer;
1062
1063 rets = mei_cl_flow_ctrl_creds(cl);
1064 if (rets < 0)
1065 return rets;
1066
1067 if (rets == 0) {
Tomas Winkler04bb1392014-03-18 22:52:04 +02001068 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
Tomas Winkler136698e2013-09-16 23:44:44 +03001069 return 0;
1070 }
1071
Tomas Winkler9d098192014-02-19 17:35:48 +02001072 slots = mei_hbuf_empty_slots(dev);
Tomas Winkler136698e2013-09-16 23:44:44 +03001073 len = buf->size - cb->buf_idx;
1074 msg_slots = mei_data2slots(len);
1075
Tomas Winkler21767542013-06-23 09:36:59 +03001076 mei_hdr.host_addr = cl->host_client_id;
1077 mei_hdr.me_addr = cl->me_client_id;
1078 mei_hdr.reserved = 0;
Tomas Winkler479327f2013-12-17 15:56:56 +02001079 mei_hdr.internal = cb->internal;
Tomas Winkler21767542013-06-23 09:36:59 +03001080
Tomas Winkler9d098192014-02-19 17:35:48 +02001081 if (slots >= msg_slots) {
Tomas Winkler21767542013-06-23 09:36:59 +03001082 mei_hdr.length = len;
1083 mei_hdr.msg_complete = 1;
1084 /* Split the message only if we can write the whole host buffer */
Tomas Winkler9d098192014-02-19 17:35:48 +02001085 } else if (slots == dev->hbuf_depth) {
1086 msg_slots = slots;
1087 len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
Tomas Winkler21767542013-06-23 09:36:59 +03001088 mei_hdr.length = len;
1089 mei_hdr.msg_complete = 0;
1090 } else {
1091 /* wait for next time the host buffer is empty */
1092 return 0;
1093 }
1094
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001095 cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
Tomas Winkler21767542013-06-23 09:36:59 +03001096 cb->request_buffer.size, cb->buf_idx);
Tomas Winkler21767542013-06-23 09:36:59 +03001097
Tomas Winkler136698e2013-09-16 23:44:44 +03001098 rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001099 if (rets) {
1100 cl->status = rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001101 list_move_tail(&cb->list, &cmpl_list->list);
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001102 return rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001103 }
1104
1105 cl->status = 0;
Tomas Winkler4dfaa9f2013-06-23 09:37:00 +03001106 cl->writing_state = MEI_WRITING;
Tomas Winkler21767542013-06-23 09:36:59 +03001107 cb->buf_idx += mei_hdr.length;
Tomas Winkler4dfaa9f2013-06-23 09:37:00 +03001108
Tomas Winkler21767542013-06-23 09:36:59 +03001109 if (mei_hdr.msg_complete) {
1110 if (mei_cl_flow_ctrl_reduce(cl))
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001111 return -EIO;
Tomas Winkler21767542013-06-23 09:36:59 +03001112 list_move_tail(&cb->list, &dev->write_waiting_list.list);
1113 }
1114
1115 return 0;
1116}
1117
1118/**
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001119 * mei_cl_write - submit a write cb to mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001120 * assumes device_lock is locked
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001121 *
1122 * @cl: host client
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001123 * @cb: write callback with filled data
Alexander Usyskince231392014-09-29 16:31:50 +03001124 * @blocking: block until completed
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001125 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001126 * Return: number of bytes sent on success, <0 on failure.
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001127 */
1128int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
1129{
1130 struct mei_device *dev;
1131 struct mei_msg_data *buf;
1132 struct mei_msg_hdr mei_hdr;
1133 int rets;
1134
1135
1136 if (WARN_ON(!cl || !cl->dev))
1137 return -ENODEV;
1138
1139 if (WARN_ON(!cb))
1140 return -EINVAL;
1141
1142 dev = cl->dev;
1143
1144
1145 buf = &cb->request_buffer;
1146
Alexander Usyskin0a01e972014-09-29 16:31:47 +03001147 cl_dbg(dev, cl, "size=%d\n", buf->size);
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001148
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001149 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001150 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001151 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001152 cl_err(dev, cl, "rpm: get failed %d\n", rets);
1153 return rets;
1154 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001155
1156 cb->fop_type = MEI_FOP_WRITE;
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001157 cb->buf_idx = 0;
1158 cl->writing_state = MEI_IDLE;
1159
1160 mei_hdr.host_addr = cl->host_client_id;
1161 mei_hdr.me_addr = cl->me_client_id;
1162 mei_hdr.reserved = 0;
1163 mei_hdr.msg_complete = 0;
1164 mei_hdr.internal = cb->internal;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001165
1166 rets = mei_cl_flow_ctrl_creds(cl);
1167 if (rets < 0)
1168 goto err;
1169
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001170 if (rets == 0) {
1171 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001172 rets = buf->size;
1173 goto out;
1174 }
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001175 if (!mei_hbuf_acquire(dev)) {
1176 cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
1177 rets = buf->size;
1178 goto out;
1179 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001180
1181 /* Check for a maximum length */
1182 if (buf->size > mei_hbuf_max_len(dev)) {
1183 mei_hdr.length = mei_hbuf_max_len(dev);
1184 mei_hdr.msg_complete = 0;
1185 } else {
1186 mei_hdr.length = buf->size;
1187 mei_hdr.msg_complete = 1;
1188 }
1189
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001190 rets = mei_write_message(dev, &mei_hdr, buf->data);
1191 if (rets)
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001192 goto err;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001193
1194 cl->writing_state = MEI_WRITING;
1195 cb->buf_idx = mei_hdr.length;
1196
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001197out:
1198 if (mei_hdr.msg_complete) {
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001199 rets = mei_cl_flow_ctrl_reduce(cl);
1200 if (rets < 0)
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001201 goto err;
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001202
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001203 list_add_tail(&cb->list, &dev->write_waiting_list.list);
1204 } else {
1205 list_add_tail(&cb->list, &dev->write_list.list);
1206 }
1207
1208
1209 if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
1210
1211 mutex_unlock(&dev->device_lock);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001212 rets = wait_event_interruptible(cl->tx_wait,
1213 cl->writing_state == MEI_WRITE_COMPLETE);
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001214 mutex_lock(&dev->device_lock);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001215 /* wait_event_interruptible returns -ERESTARTSYS */
1216 if (rets) {
1217 if (signal_pending(current))
1218 rets = -EINTR;
1219 goto err;
1220 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001221 }
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001222
1223 rets = buf->size;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001224err:
Tomas Winkler04bb1392014-03-18 22:52:04 +02001225 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001226 pm_runtime_mark_last_busy(dev->dev);
1227 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001228
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001229 return rets;
1230}
1231
1232
Tomas Winklerdb086fa2013-05-12 15:34:45 +03001233/**
1234 * mei_cl_complete - processes completed operation for a client
1235 *
1236 * @cl: private data of the file object.
1237 * @cb: callback block.
1238 */
1239void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
1240{
1241 if (cb->fop_type == MEI_FOP_WRITE) {
1242 mei_io_cb_free(cb);
1243 cb = NULL;
1244 cl->writing_state = MEI_WRITE_COMPLETE;
1245 if (waitqueue_active(&cl->tx_wait))
1246 wake_up_interruptible(&cl->tx_wait);
1247
1248 } else if (cb->fop_type == MEI_FOP_READ &&
1249 MEI_READING == cl->reading_state) {
1250 cl->reading_state = MEI_READ_COMPLETE;
1251 if (waitqueue_active(&cl->rx_wait))
1252 wake_up_interruptible(&cl->rx_wait);
1253 else
1254 mei_cl_bus_rx_event(cl);
1255
1256 }
1257}
1258
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001259
1260/**
Tomas Winkler074b4c02013-02-06 14:06:44 +02001261 * mei_cl_all_disconnect - disconnect forcefully all connected clients
1262 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001263 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001264 */
1265
1266void mei_cl_all_disconnect(struct mei_device *dev)
1267{
Tomas Winkler31f88f52014-02-17 15:13:25 +02001268 struct mei_cl *cl;
Tomas Winkler074b4c02013-02-06 14:06:44 +02001269
Tomas Winkler31f88f52014-02-17 15:13:25 +02001270 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winkler074b4c02013-02-06 14:06:44 +02001271 cl->state = MEI_FILE_DISCONNECTED;
1272 cl->mei_flow_ctrl_creds = 0;
Tomas Winkler074b4c02013-02-06 14:06:44 +02001273 cl->timer_count = 0;
1274 }
1275}
1276
1277
1278/**
Tomas Winkler52908012013-07-24 16:22:57 +03001279 * mei_cl_all_wakeup - wake up all readers and writers they can be interrupted
Tomas Winkler074b4c02013-02-06 14:06:44 +02001280 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001281 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001282 */
Tomas Winkler52908012013-07-24 16:22:57 +03001283void mei_cl_all_wakeup(struct mei_device *dev)
Tomas Winkler074b4c02013-02-06 14:06:44 +02001284{
Tomas Winkler31f88f52014-02-17 15:13:25 +02001285 struct mei_cl *cl;
Tomas Winkler92db1552014-09-29 16:31:37 +03001286
Tomas Winkler31f88f52014-02-17 15:13:25 +02001287 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winkler074b4c02013-02-06 14:06:44 +02001288 if (waitqueue_active(&cl->rx_wait)) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001289 cl_dbg(dev, cl, "Waking up reading client!\n");
Tomas Winkler074b4c02013-02-06 14:06:44 +02001290 wake_up_interruptible(&cl->rx_wait);
1291 }
Tomas Winkler52908012013-07-24 16:22:57 +03001292 if (waitqueue_active(&cl->tx_wait)) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001293 cl_dbg(dev, cl, "Waking up writing client!\n");
Tomas Winkler52908012013-07-24 16:22:57 +03001294 wake_up_interruptible(&cl->tx_wait);
1295 }
Tomas Winkler074b4c02013-02-06 14:06:44 +02001296 }
1297}
1298
1299/**
1300 * mei_cl_all_write_clear - clear all pending writes
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001301 *
1302 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001303 */
1304void mei_cl_all_write_clear(struct mei_device *dev)
1305{
Tomas Winklercc99ecf2014-03-10 15:10:40 +02001306 mei_io_list_free(&dev->write_list, NULL);
1307 mei_io_list_free(&dev->write_waiting_list, NULL);
Tomas Winkler074b4c02013-02-06 14:06:44 +02001308}
1309
1310