blob: 57461016f1ff3b63b640e1181aae758c24d10b2a [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/**
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
Tomas Winklerbca67d62015-02-10 10:39:43 +0200387 * @type: operation type
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 */
Tomas Winklerbca67d62015-02-10 10:39:43 +0200392struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
393 struct file *fp)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200394{
395 struct mei_cl_cb *cb;
396
397 cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
398 if (!cb)
399 return NULL;
400
401 mei_io_list_init(cb);
402
403 cb->file_object = fp;
404 cb->cl = cl;
405 cb->buf_idx = 0;
Tomas Winklerbca67d62015-02-10 10:39:43 +0200406 cb->fop_type = type;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200407 return cb;
408}
409
410/**
Tomas Winkler5db75142015-02-10 10:39:42 +0200411 * mei_io_cb_alloc_buf - allocate callback buffer
Tomas Winkler9ca90502013-01-08 23:07:13 +0200412 *
Masanari Iida393b1482013-04-05 01:05:05 +0900413 * @cb: io callback structure
414 * @length: size of the buffer
Tomas Winkler9ca90502013-01-08 23:07:13 +0200415 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300416 * Return: 0 on success
Tomas Winkler9ca90502013-01-08 23:07:13 +0200417 * -EINVAL if cb is NULL
418 * -ENOMEM if allocation failed
419 */
Tomas Winkler5db75142015-02-10 10:39:42 +0200420int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200421{
422 if (!cb)
423 return -EINVAL;
424
425 if (length == 0)
426 return 0;
427
Tomas Winkler5db75142015-02-10 10:39:42 +0200428 cb->buf.data = kmalloc(length, GFP_KERNEL);
429 if (!cb->buf.data)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200430 return -ENOMEM;
Tomas Winkler5db75142015-02-10 10:39:42 +0200431 cb->buf.size = length;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200432 return 0;
433}
Tomas Winkler9ca90502013-01-08 23:07:13 +0200434
435/**
Tomas Winklerbca67d62015-02-10 10:39:43 +0200436 * mei_cl_alloc_cb - a convenient wrapper for allocating read cb
437 *
438 * @cl: host client
439 * @length: size of the buffer
440 * @type: operation type
441 * @fp: associated file pointer (might be NULL)
442 *
443 * Return: cb on success and NULL on failure
444 */
445struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
446 enum mei_cb_file_ops type, struct file *fp)
447{
448 struct mei_cl_cb *cb;
449
450 cb = mei_io_cb_init(cl, type, fp);
451 if (!cb)
452 return NULL;
453
454 if (mei_io_cb_alloc_buf(cb, length)) {
455 mei_io_cb_free(cb);
456 return NULL;
457 }
458
459 return cb;
460}
461
462/**
Tomas Winkler9ca90502013-01-08 23:07:13 +0200463 * mei_cl_flush_queues - flushes queue lists belonging to cl.
464 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200465 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300466 *
467 * Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200468 */
469int mei_cl_flush_queues(struct mei_cl *cl)
470{
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300471 struct mei_device *dev;
472
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200473 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200474 return -EINVAL;
475
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300476 dev = cl->dev;
477
478 cl_dbg(dev, cl, "remove list entry belonging to cl\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200479 mei_io_list_flush(&cl->dev->read_list, cl);
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200480 mei_io_list_free(&cl->dev->write_list, cl);
481 mei_io_list_free(&cl->dev->write_waiting_list, cl);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200482 mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
483 mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
484 mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
485 mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
486 return 0;
487}
488
Tomas Winkler9ca90502013-01-08 23:07:13 +0200489
490/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200491 * mei_cl_init - initializes cl.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200492 *
493 * @cl: host client to be initialized
494 * @dev: mei device
495 */
496void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
497{
498 memset(cl, 0, sizeof(struct mei_cl));
499 init_waitqueue_head(&cl->wait);
500 init_waitqueue_head(&cl->rx_wait);
501 init_waitqueue_head(&cl->tx_wait);
502 INIT_LIST_HEAD(&cl->link);
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200503 INIT_LIST_HEAD(&cl->device_link);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200504 cl->reading_state = MEI_IDLE;
505 cl->writing_state = MEI_IDLE;
506 cl->dev = dev;
507}
508
509/**
510 * mei_cl_allocate - allocates cl structure and sets it up.
511 *
512 * @dev: mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300513 * Return: The allocated file or NULL on failure
Tomas Winkler9ca90502013-01-08 23:07:13 +0200514 */
515struct mei_cl *mei_cl_allocate(struct mei_device *dev)
516{
517 struct mei_cl *cl;
518
519 cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
520 if (!cl)
521 return NULL;
522
523 mei_cl_init(cl, dev);
524
525 return cl;
526}
527
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200528/**
529 * mei_cl_find_read_cb - find this cl's callback in the read list
530 *
Masanari Iida393b1482013-04-05 01:05:05 +0900531 * @cl: host client
532 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300533 * Return: cb on success, NULL on error
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200534 */
535struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
536{
537 struct mei_device *dev = cl->dev;
Tomas Winkler31f88f52014-02-17 15:13:25 +0200538 struct mei_cl_cb *cb;
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200539
Tomas Winkler31f88f52014-02-17 15:13:25 +0200540 list_for_each_entry(cb, &dev->read_list.list, list)
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200541 if (mei_cl_cmp_id(cl, cb->cl))
542 return cb;
543 return NULL;
544}
545
Alexander Usyskin3908be62015-02-10 10:39:35 +0200546/**
547 * mei_cl_link - allocate host id in the host map
Tomas Winkler9ca90502013-01-08 23:07:13 +0200548 *
Alexander Usyskin3908be62015-02-10 10:39:35 +0200549 * @cl: host client
550 * @id: fixed host id or -1 for generic one
Masanari Iida393b1482013-04-05 01:05:05 +0900551 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300552 * Return: 0 on success
Tomas Winkler9ca90502013-01-08 23:07:13 +0200553 * -EINVAL on incorrect values
554 * -ENONET if client not found
555 */
Tomas Winkler781d0d82013-01-08 23:07:22 +0200556int mei_cl_link(struct mei_cl *cl, int id)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200557{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200558 struct mei_device *dev;
Tomas Winkler22f96a02013-09-16 23:44:47 +0300559 long open_handle_count;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200560
Tomas Winkler781d0d82013-01-08 23:07:22 +0200561 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200562 return -EINVAL;
563
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200564 dev = cl->dev;
565
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200566 /* If Id is not assigned get one*/
Tomas Winkler781d0d82013-01-08 23:07:22 +0200567 if (id == MEI_HOST_CLIENT_ID_ANY)
568 id = find_first_zero_bit(dev->host_clients_map,
569 MEI_CLIENTS_MAX);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200570
Tomas Winkler781d0d82013-01-08 23:07:22 +0200571 if (id >= MEI_CLIENTS_MAX) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300572 dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
Tomas Winklere036cc52013-09-16 23:44:46 +0300573 return -EMFILE;
574 }
575
Tomas Winkler22f96a02013-09-16 23:44:47 +0300576 open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
577 if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300578 dev_err(dev->dev, "open_handle_count exceeded %d",
Tomas Winklere036cc52013-09-16 23:44:46 +0300579 MEI_MAX_OPEN_HANDLE_COUNT);
580 return -EMFILE;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200581 }
582
Tomas Winkler781d0d82013-01-08 23:07:22 +0200583 dev->open_handle_count++;
584
585 cl->host_client_id = id;
586 list_add_tail(&cl->link, &dev->file_list);
587
588 set_bit(id, dev->host_clients_map);
589
590 cl->state = MEI_FILE_INITIALIZING;
591
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300592 cl_dbg(dev, cl, "link cl\n");
Tomas Winkler781d0d82013-01-08 23:07:22 +0200593 return 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200594}
Tomas Winkler781d0d82013-01-08 23:07:22 +0200595
Tomas Winkler9ca90502013-01-08 23:07:13 +0200596/**
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200597 * mei_cl_unlink - remove me_cl from the list
Tomas Winkler9ca90502013-01-08 23:07:13 +0200598 *
Masanari Iida393b1482013-04-05 01:05:05 +0900599 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300600 *
601 * Return: always 0
Tomas Winkler9ca90502013-01-08 23:07:13 +0200602 */
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200603int mei_cl_unlink(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200604{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200605 struct mei_device *dev;
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200606
Tomas Winkler781d0d82013-01-08 23:07:22 +0200607 /* don't shout on error exit path */
608 if (!cl)
609 return 0;
610
Tomas Winkler8e9a4a92013-01-10 17:32:14 +0200611 /* wd and amthif might not be initialized */
612 if (!cl->dev)
613 return 0;
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200614
615 dev = cl->dev;
616
Tomas Winklera14c44d2013-09-16 23:44:45 +0300617 cl_dbg(dev, cl, "unlink client");
618
Tomas Winkler22f96a02013-09-16 23:44:47 +0300619 if (dev->open_handle_count > 0)
620 dev->open_handle_count--;
621
622 /* never clear the 0 bit */
623 if (cl->host_client_id)
624 clear_bit(cl->host_client_id, dev->host_clients_map);
625
626 list_del_init(&cl->link);
627
628 cl->state = MEI_FILE_INITIALIZING;
629
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200630 return 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200631}
632
633
634void mei_host_client_init(struct work_struct *work)
635{
Tomas Winklerb7d88512015-02-10 10:39:31 +0200636 struct mei_device *dev =
637 container_of(work, struct mei_device, init_work);
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300638 struct mei_me_client *me_cl;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200639
640 mutex_lock(&dev->device_lock);
641
Tomas Winkler9ca90502013-01-08 23:07:13 +0200642
Tomas Winklerb7d88512015-02-10 10:39:31 +0200643 me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
644 if (me_cl)
645 mei_amthif_host_init(dev);
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200646
Tomas Winklerb7d88512015-02-10 10:39:31 +0200647 me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid);
648 if (me_cl)
649 mei_wd_host_init(dev);
650
651 me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
652 if (me_cl)
653 mei_nfc_host_init(dev);
654
Tomas Winkler9ca90502013-01-08 23:07:13 +0200655
656 dev->dev_state = MEI_DEV_ENABLED;
Tomas Winkler6adb8ef2014-01-12 00:36:10 +0200657 dev->reset_count = 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200658 mutex_unlock(&dev->device_lock);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200659
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300660 pm_runtime_mark_last_busy(dev->dev);
661 dev_dbg(dev->dev, "rpm: autosuspend\n");
662 pm_runtime_autosuspend(dev->dev);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200663}
664
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200665/**
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300666 * mei_hbuf_acquire - try to acquire host buffer
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200667 *
668 * @dev: the device structure
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300669 * Return: true if host buffer was acquired
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200670 */
671bool mei_hbuf_acquire(struct mei_device *dev)
672{
Tomas Winkler04bb1392014-03-18 22:52:04 +0200673 if (mei_pg_state(dev) == MEI_PG_ON ||
674 dev->pg_event == MEI_PG_EVENT_WAIT) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300675 dev_dbg(dev->dev, "device is in pg\n");
Tomas Winkler04bb1392014-03-18 22:52:04 +0200676 return false;
677 }
678
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200679 if (!dev->hbuf_is_ready) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300680 dev_dbg(dev->dev, "hbuf is not ready\n");
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200681 return false;
682 }
683
684 dev->hbuf_is_ready = false;
685
686 return true;
687}
Tomas Winkler9ca90502013-01-08 23:07:13 +0200688
689/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200690 * mei_cl_disconnect - disconnect host client from the me one
Tomas Winkler9ca90502013-01-08 23:07:13 +0200691 *
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200692 * @cl: host client
Tomas Winkler9ca90502013-01-08 23:07:13 +0200693 *
694 * Locking: called under "dev->device_lock" lock
695 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300696 * Return: 0 on success, <0 on failure.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200697 */
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200698int mei_cl_disconnect(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200699{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200700 struct mei_device *dev;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200701 struct mei_cl_cb *cb;
Alexander Usyskinfe2f17eb32014-07-17 10:53:38 +0300702 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200703
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200704 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200705 return -ENODEV;
706
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200707 dev = cl->dev;
708
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300709 cl_dbg(dev, cl, "disconnecting");
710
Tomas Winkler9ca90502013-01-08 23:07:13 +0200711 if (cl->state != MEI_FILE_DISCONNECTING)
712 return 0;
713
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300714 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200715 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300716 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200717 cl_err(dev, cl, "rpm: get failed %d\n", rets);
718 return rets;
719 }
720
Tomas Winklerbca67d62015-02-10 10:39:43 +0200721 cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT, NULL);
722 rets = cb ? 0 : -ENOMEM;
723 if (rets)
Tomas Winkler04bb1392014-03-18 22:52:04 +0200724 goto free;
Tomas Winkler5a8373f2014-08-21 14:29:17 +0300725
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200726 if (mei_hbuf_acquire(dev)) {
Tomas Winkler9ca90502013-01-08 23:07:13 +0200727 if (mei_hbm_cl_disconnect_req(dev, cl)) {
728 rets = -ENODEV;
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300729 cl_err(dev, cl, "failed to disconnect.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200730 goto free;
731 }
Alexander Usyskin22b987a2014-07-17 10:53:35 +0300732 cl->timer_count = MEI_CONNECT_TIMEOUT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200733 mdelay(10); /* Wait for hardware disconnection ready */
734 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
735 } else {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300736 cl_dbg(dev, cl, "add disconnect cb to control write list\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200737 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
738
739 }
740 mutex_unlock(&dev->device_lock);
741
Tomas Winkler12f45ed2014-08-21 14:29:18 +0300742 wait_event_timeout(cl->wait,
Tomas Winkler9ca90502013-01-08 23:07:13 +0200743 MEI_FILE_DISCONNECTED == cl->state,
744 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
745
746 mutex_lock(&dev->device_lock);
Alexander Usyskinfe2f17eb32014-07-17 10:53:38 +0300747
Tomas Winkler9ca90502013-01-08 23:07:13 +0200748 if (MEI_FILE_DISCONNECTED == cl->state) {
749 rets = 0;
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300750 cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200751 } else {
Alexander Usyskinfe2f17eb32014-07-17 10:53:38 +0300752 cl_dbg(dev, cl, "timeout on disconnect from FW client.\n");
753 rets = -ETIME;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200754 }
755
756 mei_io_list_flush(&dev->ctrl_rd_list, cl);
757 mei_io_list_flush(&dev->ctrl_wr_list, cl);
758free:
Tomas Winkler04bb1392014-03-18 22:52:04 +0200759 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300760 pm_runtime_mark_last_busy(dev->dev);
761 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200762
Tomas Winkler9ca90502013-01-08 23:07:13 +0200763 mei_io_cb_free(cb);
764 return rets;
765}
766
767
768/**
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200769 * mei_cl_is_other_connecting - checks if other
770 * client with the same me client id is connecting
Tomas Winkler9ca90502013-01-08 23:07:13 +0200771 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200772 * @cl: private data of the file object
773 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300774 * Return: true if other client is connected, false - otherwise.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200775 */
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200776bool mei_cl_is_other_connecting(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200777{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200778 struct mei_device *dev;
Tomas Winkler31f88f52014-02-17 15:13:25 +0200779 struct mei_cl *ocl; /* the other client */
Tomas Winkler9ca90502013-01-08 23:07:13 +0200780
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200781 if (WARN_ON(!cl || !cl->dev))
782 return false;
783
784 dev = cl->dev;
785
Tomas Winkler31f88f52014-02-17 15:13:25 +0200786 list_for_each_entry(ocl, &dev->file_list, link) {
787 if (ocl->state == MEI_FILE_CONNECTING &&
788 ocl != cl &&
789 cl->me_client_id == ocl->me_client_id)
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200790 return true;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200791
792 }
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200793
794 return false;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200795}
796
797/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200798 * mei_cl_connect - connect host client to the me one
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200799 *
800 * @cl: host client
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300801 * @file: pointer to file structure
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200802 *
803 * Locking: called under "dev->device_lock" lock
804 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300805 * Return: 0 on success, <0 on failure.
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200806 */
807int mei_cl_connect(struct mei_cl *cl, struct file *file)
808{
809 struct mei_device *dev;
810 struct mei_cl_cb *cb;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200811 int rets;
812
813 if (WARN_ON(!cl || !cl->dev))
814 return -ENODEV;
815
816 dev = cl->dev;
817
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300818 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200819 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300820 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200821 cl_err(dev, cl, "rpm: get failed %d\n", rets);
822 return rets;
823 }
824
Tomas Winklerbca67d62015-02-10 10:39:43 +0200825 cb = mei_io_cb_init(cl, MEI_FOP_CONNECT, file);
826 rets = cb ? 0 : -ENOMEM;
827 if (rets)
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200828 goto out;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200829
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200830 /* run hbuf acquire last so we don't have to undo */
831 if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
Alexander Usyskine4d82702014-04-27 15:42:21 +0300832 cl->state = MEI_FILE_CONNECTING;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200833 if (mei_hbm_cl_connect_req(dev, cl)) {
834 rets = -ENODEV;
835 goto out;
836 }
837 cl->timer_count = MEI_CONNECT_TIMEOUT;
838 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
839 } else {
Alexander Usyskin73ab4232014-08-12 18:07:56 +0300840 cl->state = MEI_FILE_INITIALIZING;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200841 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
842 }
843
844 mutex_unlock(&dev->device_lock);
Tomas Winkler12f45ed2014-08-21 14:29:18 +0300845 wait_event_timeout(cl->wait,
Alexander Usyskin285e2992014-02-17 15:13:20 +0200846 (cl->state == MEI_FILE_CONNECTED ||
847 cl->state == MEI_FILE_DISCONNECTED),
848 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200849 mutex_lock(&dev->device_lock);
850
851 if (cl->state != MEI_FILE_CONNECTED) {
Alexander Usyskin3e37ebb2014-07-17 10:53:34 +0300852 cl->state = MEI_FILE_DISCONNECTED;
Alexander Usyskin285e2992014-02-17 15:13:20 +0200853 /* something went really wrong */
854 if (!cl->status)
855 cl->status = -EFAULT;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200856
857 mei_io_list_flush(&dev->ctrl_rd_list, cl);
858 mei_io_list_flush(&dev->ctrl_wr_list, cl);
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200859 }
860
861 rets = cl->status;
862
863out:
Tomas Winkler04bb1392014-03-18 22:52:04 +0200864 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300865 pm_runtime_mark_last_busy(dev->dev);
866 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200867
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200868 mei_io_cb_free(cb);
869 return rets;
870}
871
872/**
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200873 * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200874 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200875 * @cl: private data of the file object
876 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300877 * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200878 * -ENOENT if mei_cl is not present
879 * -EINVAL if single_recv_buf == 0
880 */
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200881int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200882{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200883 struct mei_device *dev;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200884 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200885 int rets = 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200886
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200887 if (WARN_ON(!cl || !cl->dev))
888 return -EINVAL;
889
890 dev = cl->dev;
891
Tomas Winkler9ca90502013-01-08 23:07:13 +0200892 if (cl->mei_flow_ctrl_creds > 0)
893 return 1;
894
Tomas Winkler2e5df412014-12-07 16:40:14 +0200895 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300896 if (!me_cl) {
Alexander Usyskin12d00662014-02-17 15:13:23 +0200897 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300898 return -ENOENT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200899 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200900
Tomas Winkler79563db2015-01-11 00:07:16 +0200901 if (me_cl->mei_flow_ctrl_creds > 0) {
902 rets = 1;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200903 if (WARN_ON(me_cl->props.single_recv_buf == 0))
Tomas Winkler79563db2015-01-11 00:07:16 +0200904 rets = -EINVAL;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200905 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200906 mei_me_cl_put(me_cl);
907 return rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200908}
909
910/**
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200911 * mei_cl_flow_ctrl_reduce - reduces flow_control.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200912 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200913 * @cl: private data of the file object
Masanari Iida393b1482013-04-05 01:05:05 +0900914 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300915 * Return:
Tomas Winkler9ca90502013-01-08 23:07:13 +0200916 * 0 on success
917 * -ENOENT when me client is not found
918 * -EINVAL when ctrl credits are <= 0
919 */
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200920int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200921{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200922 struct mei_device *dev;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200923 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200924 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200925
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200926 if (WARN_ON(!cl || !cl->dev))
927 return -EINVAL;
928
929 dev = cl->dev;
930
Tomas Winkler2e5df412014-12-07 16:40:14 +0200931 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300932 if (!me_cl) {
Alexander Usyskin12d00662014-02-17 15:13:23 +0200933 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300934 return -ENOENT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200935 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200936
Tomas Winklerd3208322014-08-24 12:08:55 +0300937 if (me_cl->props.single_recv_buf) {
Tomas Winkler79563db2015-01-11 00:07:16 +0200938 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
939 rets = -EINVAL;
940 goto out;
941 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200942 me_cl->mei_flow_ctrl_creds--;
943 } else {
Tomas Winkler79563db2015-01-11 00:07:16 +0200944 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
945 rets = -EINVAL;
946 goto out;
947 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200948 cl->mei_flow_ctrl_creds--;
949 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200950 rets = 0;
951out:
952 mei_me_cl_put(me_cl);
953 return rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200954}
955
Tomas Winkler9ca90502013-01-08 23:07:13 +0200956/**
Masanari Iida393b1482013-04-05 01:05:05 +0900957 * mei_cl_read_start - the start read client message function.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200958 *
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200959 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300960 * @length: number of bytes to read
Tomas Winklerbca67d62015-02-10 10:39:43 +0200961 * @fp: pointer to file structure
Tomas Winkler9ca90502013-01-08 23:07:13 +0200962 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300963 * Return: 0 on success, <0 on failure.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200964 */
Tomas Winklerbca67d62015-02-10 10:39:43 +0200965int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200966{
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200967 struct mei_device *dev;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200968 struct mei_cl_cb *cb;
Tomas Winklerd3208322014-08-24 12:08:55 +0300969 struct mei_me_client *me_cl;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200970 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200971
Tomas Winkler90e0b5f2013-01-08 23:07:14 +0200972 if (WARN_ON(!cl || !cl->dev))
973 return -ENODEV;
974
975 dev = cl->dev;
976
Tomas Winklerb950ac12013-07-25 20:15:53 +0300977 if (!mei_cl_is_connected(cl))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200978 return -ENODEV;
979
Tomas Winklerd91aaed2013-01-08 23:07:18 +0200980 if (cl->read_cb) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300981 cl_dbg(dev, cl, "read is pending.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200982 return -EBUSY;
983 }
Tomas Winklerd880f322014-08-21 14:29:15 +0300984 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300985 if (!me_cl) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300986 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +0200987 return -ENOTTY;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200988 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200989 /* always allocate at least client max message */
990 length = max_t(size_t, length, me_cl->props.max_msg_length);
991 mei_me_cl_put(me_cl);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200992
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300993 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200994 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300995 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200996 cl_err(dev, cl, "rpm: get failed %d\n", rets);
997 return rets;
998 }
999
Tomas Winklerbca67d62015-02-10 10:39:43 +02001000 cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp);
1001 rets = cb ? 0 : -ENOMEM;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001002 if (rets)
Tomas Winkler04bb1392014-03-18 22:52:04 +02001003 goto out;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001004
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001005 if (mei_hbuf_acquire(dev)) {
Alexander Usyskin86113502014-03-31 17:59:24 +03001006 rets = mei_hbm_cl_flow_control_req(dev, cl);
1007 if (rets < 0)
Tomas Winkler04bb1392014-03-18 22:52:04 +02001008 goto out;
Tomas Winkler04bb1392014-03-18 22:52:04 +02001009
Tomas Winkler9ca90502013-01-08 23:07:13 +02001010 list_add_tail(&cb->list, &dev->read_list.list);
1011 } else {
1012 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
1013 }
Chao Biaccb8842014-02-12 21:27:25 +02001014
1015 cl->read_cb = cb;
1016
Tomas Winkler04bb1392014-03-18 22:52:04 +02001017out:
1018 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001019 pm_runtime_mark_last_busy(dev->dev);
1020 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001021
1022 if (rets)
1023 mei_io_cb_free(cb);
1024
Tomas Winkler9ca90502013-01-08 23:07:13 +02001025 return rets;
1026}
1027
Tomas Winkler074b4c02013-02-06 14:06:44 +02001028/**
Tomas Winkler9d098192014-02-19 17:35:48 +02001029 * mei_cl_irq_write - write a message to device
Tomas Winkler21767542013-06-23 09:36:59 +03001030 * from the interrupt thread context
1031 *
1032 * @cl: client
1033 * @cb: callback block.
Tomas Winkler21767542013-06-23 09:36:59 +03001034 * @cmpl_list: complete list.
1035 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001036 * Return: 0, OK; otherwise error.
Tomas Winkler21767542013-06-23 09:36:59 +03001037 */
Tomas Winkler9d098192014-02-19 17:35:48 +02001038int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
1039 struct mei_cl_cb *cmpl_list)
Tomas Winkler21767542013-06-23 09:36:59 +03001040{
Tomas Winkler136698e2013-09-16 23:44:44 +03001041 struct mei_device *dev;
1042 struct mei_msg_data *buf;
Tomas Winkler21767542013-06-23 09:36:59 +03001043 struct mei_msg_hdr mei_hdr;
Tomas Winkler136698e2013-09-16 23:44:44 +03001044 size_t len;
1045 u32 msg_slots;
Tomas Winkler9d098192014-02-19 17:35:48 +02001046 int slots;
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001047 int rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001048
Tomas Winkler136698e2013-09-16 23:44:44 +03001049 if (WARN_ON(!cl || !cl->dev))
1050 return -ENODEV;
1051
1052 dev = cl->dev;
1053
Tomas Winkler5db75142015-02-10 10:39:42 +02001054 buf = &cb->buf;
Tomas Winkler136698e2013-09-16 23:44:44 +03001055
1056 rets = mei_cl_flow_ctrl_creds(cl);
1057 if (rets < 0)
1058 return rets;
1059
1060 if (rets == 0) {
Tomas Winkler04bb1392014-03-18 22:52:04 +02001061 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
Tomas Winkler136698e2013-09-16 23:44:44 +03001062 return 0;
1063 }
1064
Tomas Winkler9d098192014-02-19 17:35:48 +02001065 slots = mei_hbuf_empty_slots(dev);
Tomas Winkler136698e2013-09-16 23:44:44 +03001066 len = buf->size - cb->buf_idx;
1067 msg_slots = mei_data2slots(len);
1068
Tomas Winkler21767542013-06-23 09:36:59 +03001069 mei_hdr.host_addr = cl->host_client_id;
1070 mei_hdr.me_addr = cl->me_client_id;
1071 mei_hdr.reserved = 0;
Tomas Winkler479327f2013-12-17 15:56:56 +02001072 mei_hdr.internal = cb->internal;
Tomas Winkler21767542013-06-23 09:36:59 +03001073
Tomas Winkler9d098192014-02-19 17:35:48 +02001074 if (slots >= msg_slots) {
Tomas Winkler21767542013-06-23 09:36:59 +03001075 mei_hdr.length = len;
1076 mei_hdr.msg_complete = 1;
1077 /* Split the message only if we can write the whole host buffer */
Tomas Winkler9d098192014-02-19 17:35:48 +02001078 } else if (slots == dev->hbuf_depth) {
1079 msg_slots = slots;
1080 len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
Tomas Winkler21767542013-06-23 09:36:59 +03001081 mei_hdr.length = len;
1082 mei_hdr.msg_complete = 0;
1083 } else {
1084 /* wait for next time the host buffer is empty */
1085 return 0;
1086 }
1087
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001088 cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
Tomas Winkler5db75142015-02-10 10:39:42 +02001089 cb->buf.size, cb->buf_idx);
Tomas Winkler21767542013-06-23 09:36:59 +03001090
Tomas Winkler136698e2013-09-16 23:44:44 +03001091 rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001092 if (rets) {
1093 cl->status = rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001094 list_move_tail(&cb->list, &cmpl_list->list);
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001095 return rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001096 }
1097
1098 cl->status = 0;
Tomas Winkler4dfaa9f2013-06-23 09:37:00 +03001099 cl->writing_state = MEI_WRITING;
Tomas Winkler21767542013-06-23 09:36:59 +03001100 cb->buf_idx += mei_hdr.length;
Tomas Winkler86601722015-02-10 10:39:40 +02001101 cb->completed = mei_hdr.msg_complete == 1;
Tomas Winkler4dfaa9f2013-06-23 09:37:00 +03001102
Tomas Winkler21767542013-06-23 09:36:59 +03001103 if (mei_hdr.msg_complete) {
1104 if (mei_cl_flow_ctrl_reduce(cl))
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001105 return -EIO;
Tomas Winkler21767542013-06-23 09:36:59 +03001106 list_move_tail(&cb->list, &dev->write_waiting_list.list);
1107 }
1108
1109 return 0;
1110}
1111
1112/**
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001113 * mei_cl_write - submit a write cb to mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001114 * assumes device_lock is locked
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001115 *
1116 * @cl: host client
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001117 * @cb: write callback with filled data
Alexander Usyskince231392014-09-29 16:31:50 +03001118 * @blocking: block until completed
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001119 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001120 * Return: number of bytes sent on success, <0 on failure.
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001121 */
1122int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
1123{
1124 struct mei_device *dev;
1125 struct mei_msg_data *buf;
1126 struct mei_msg_hdr mei_hdr;
1127 int rets;
1128
1129
1130 if (WARN_ON(!cl || !cl->dev))
1131 return -ENODEV;
1132
1133 if (WARN_ON(!cb))
1134 return -EINVAL;
1135
1136 dev = cl->dev;
1137
1138
Tomas Winkler5db75142015-02-10 10:39:42 +02001139 buf = &cb->buf;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001140
Alexander Usyskin0a01e972014-09-29 16:31:47 +03001141 cl_dbg(dev, cl, "size=%d\n", buf->size);
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001142
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001143 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001144 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001145 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001146 cl_err(dev, cl, "rpm: get failed %d\n", rets);
1147 return rets;
1148 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001149
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001150 cb->buf_idx = 0;
1151 cl->writing_state = MEI_IDLE;
1152
1153 mei_hdr.host_addr = cl->host_client_id;
1154 mei_hdr.me_addr = cl->me_client_id;
1155 mei_hdr.reserved = 0;
1156 mei_hdr.msg_complete = 0;
1157 mei_hdr.internal = cb->internal;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001158
1159 rets = mei_cl_flow_ctrl_creds(cl);
1160 if (rets < 0)
1161 goto err;
1162
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001163 if (rets == 0) {
1164 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001165 rets = buf->size;
1166 goto out;
1167 }
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001168 if (!mei_hbuf_acquire(dev)) {
1169 cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
1170 rets = buf->size;
1171 goto out;
1172 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001173
1174 /* Check for a maximum length */
1175 if (buf->size > mei_hbuf_max_len(dev)) {
1176 mei_hdr.length = mei_hbuf_max_len(dev);
1177 mei_hdr.msg_complete = 0;
1178 } else {
1179 mei_hdr.length = buf->size;
1180 mei_hdr.msg_complete = 1;
1181 }
1182
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001183 rets = mei_write_message(dev, &mei_hdr, buf->data);
1184 if (rets)
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001185 goto err;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001186
1187 cl->writing_state = MEI_WRITING;
1188 cb->buf_idx = mei_hdr.length;
Tomas Winkler86601722015-02-10 10:39:40 +02001189 cb->completed = mei_hdr.msg_complete == 1;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001190
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001191out:
1192 if (mei_hdr.msg_complete) {
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001193 rets = mei_cl_flow_ctrl_reduce(cl);
1194 if (rets < 0)
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001195 goto err;
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001196
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001197 list_add_tail(&cb->list, &dev->write_waiting_list.list);
1198 } else {
1199 list_add_tail(&cb->list, &dev->write_list.list);
1200 }
1201
1202
1203 if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
1204
1205 mutex_unlock(&dev->device_lock);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001206 rets = wait_event_interruptible(cl->tx_wait,
1207 cl->writing_state == MEI_WRITE_COMPLETE);
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001208 mutex_lock(&dev->device_lock);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001209 /* wait_event_interruptible returns -ERESTARTSYS */
1210 if (rets) {
1211 if (signal_pending(current))
1212 rets = -EINTR;
1213 goto err;
1214 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001215 }
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001216
1217 rets = buf->size;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001218err:
Tomas Winkler04bb1392014-03-18 22:52:04 +02001219 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001220 pm_runtime_mark_last_busy(dev->dev);
1221 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001222
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001223 return rets;
1224}
1225
1226
Tomas Winklerdb086fa2013-05-12 15:34:45 +03001227/**
1228 * mei_cl_complete - processes completed operation for a client
1229 *
1230 * @cl: private data of the file object.
1231 * @cb: callback block.
1232 */
1233void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
1234{
1235 if (cb->fop_type == MEI_FOP_WRITE) {
1236 mei_io_cb_free(cb);
1237 cb = NULL;
1238 cl->writing_state = MEI_WRITE_COMPLETE;
1239 if (waitqueue_active(&cl->tx_wait))
1240 wake_up_interruptible(&cl->tx_wait);
1241
1242 } else if (cb->fop_type == MEI_FOP_READ &&
1243 MEI_READING == cl->reading_state) {
1244 cl->reading_state = MEI_READ_COMPLETE;
1245 if (waitqueue_active(&cl->rx_wait))
1246 wake_up_interruptible(&cl->rx_wait);
1247 else
1248 mei_cl_bus_rx_event(cl);
1249
1250 }
1251}
1252
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001253
1254/**
Tomas Winkler074b4c02013-02-06 14:06:44 +02001255 * mei_cl_all_disconnect - disconnect forcefully all connected clients
1256 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001257 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001258 */
1259
1260void mei_cl_all_disconnect(struct mei_device *dev)
1261{
Tomas Winkler31f88f52014-02-17 15:13:25 +02001262 struct mei_cl *cl;
Tomas Winkler074b4c02013-02-06 14:06:44 +02001263
Tomas Winkler31f88f52014-02-17 15:13:25 +02001264 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winkler074b4c02013-02-06 14:06:44 +02001265 cl->state = MEI_FILE_DISCONNECTED;
1266 cl->mei_flow_ctrl_creds = 0;
Tomas Winkler074b4c02013-02-06 14:06:44 +02001267 cl->timer_count = 0;
1268 }
1269}
1270
1271
1272/**
Tomas Winkler52908012013-07-24 16:22:57 +03001273 * mei_cl_all_wakeup - wake up all readers and writers they can be interrupted
Tomas Winkler074b4c02013-02-06 14:06:44 +02001274 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001275 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001276 */
Tomas Winkler52908012013-07-24 16:22:57 +03001277void mei_cl_all_wakeup(struct mei_device *dev)
Tomas Winkler074b4c02013-02-06 14:06:44 +02001278{
Tomas Winkler31f88f52014-02-17 15:13:25 +02001279 struct mei_cl *cl;
Tomas Winkler92db1552014-09-29 16:31:37 +03001280
Tomas Winkler31f88f52014-02-17 15:13:25 +02001281 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winkler074b4c02013-02-06 14:06:44 +02001282 if (waitqueue_active(&cl->rx_wait)) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001283 cl_dbg(dev, cl, "Waking up reading client!\n");
Tomas Winkler074b4c02013-02-06 14:06:44 +02001284 wake_up_interruptible(&cl->rx_wait);
1285 }
Tomas Winkler52908012013-07-24 16:22:57 +03001286 if (waitqueue_active(&cl->tx_wait)) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001287 cl_dbg(dev, cl, "Waking up writing client!\n");
Tomas Winkler52908012013-07-24 16:22:57 +03001288 wake_up_interruptible(&cl->tx_wait);
1289 }
Tomas Winkler074b4c02013-02-06 14:06:44 +02001290 }
1291}
1292
1293/**
1294 * mei_cl_all_write_clear - clear all pending writes
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001295 *
1296 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001297 */
1298void mei_cl_all_write_clear(struct mei_device *dev)
1299{
Tomas Winklercc99ecf2014-03-10 15:10:40 +02001300 mei_io_list_free(&dev->write_list, NULL);
1301 mei_io_list_free(&dev->write_waiting_list, NULL);
Tomas Winkler074b4c02013-02-06 14:06:44 +02001302}
1303
1304