blob: 624bf0182a504bc7380192dd06012ad7ae5cc1f3 [file] [log] [blame]
Tomas Winkler9ca90502013-01-08 23:07:13 +02001/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2012, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
Tomas Winkler9ca90502013-01-08 23:07:13 +020017#include <linux/sched.h>
18#include <linux/wait.h>
19#include <linux/delay.h>
Tomas Winkler1f180352014-09-29 16:31:46 +030020#include <linux/slab.h>
Tomas Winkler04bb1392014-03-18 22:52:04 +020021#include <linux/pm_runtime.h>
Tomas Winkler9ca90502013-01-08 23:07:13 +020022
23#include <linux/mei.h>
24
25#include "mei_dev.h"
26#include "hbm.h"
Tomas Winkler90e0b5f12013-01-08 23:07:14 +020027#include "client.h"
28
29/**
Tomas Winkler79563db2015-01-11 00:07:16 +020030 * mei_me_cl_init - initialize me client
31 *
32 * @me_cl: me client
33 */
34void mei_me_cl_init(struct mei_me_client *me_cl)
35{
36 INIT_LIST_HEAD(&me_cl->list);
37 kref_init(&me_cl->refcnt);
38}
39
40/**
41 * mei_me_cl_get - increases me client refcount
42 *
43 * @me_cl: me client
44 *
45 * Locking: called under "dev->device_lock" lock
46 *
47 * Return: me client or NULL
48 */
49struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl)
50{
Tomas Winklerb7d88512015-02-10 10:39:31 +020051 if (me_cl && kref_get_unless_zero(&me_cl->refcnt))
52 return me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +020053
Tomas Winklerb7d88512015-02-10 10:39:31 +020054 return NULL;
Tomas Winkler79563db2015-01-11 00:07:16 +020055}
56
57/**
Tomas Winklerb7d88512015-02-10 10:39:31 +020058 * mei_me_cl_release - free me client
Tomas Winkler79563db2015-01-11 00:07:16 +020059 *
60 * Locking: called under "dev->device_lock" lock
61 *
62 * @ref: me_client refcount
63 */
64static void mei_me_cl_release(struct kref *ref)
65{
66 struct mei_me_client *me_cl =
67 container_of(ref, struct mei_me_client, refcnt);
Tomas Winklerb7d88512015-02-10 10:39:31 +020068
Tomas Winkler79563db2015-01-11 00:07:16 +020069 kfree(me_cl);
70}
Tomas Winklerb7d88512015-02-10 10:39:31 +020071
Tomas Winkler79563db2015-01-11 00:07:16 +020072/**
73 * mei_me_cl_put - decrease me client refcount and free client if necessary
74 *
75 * Locking: called under "dev->device_lock" lock
76 *
77 * @me_cl: me client
78 */
79void mei_me_cl_put(struct mei_me_client *me_cl)
80{
81 if (me_cl)
82 kref_put(&me_cl->refcnt, mei_me_cl_release);
83}
84
85/**
Tomas Winklerb7d88512015-02-10 10:39:31 +020086 * __mei_me_cl_del - delete me client form the list and decrease
87 * reference counter
88 *
89 * @dev: mei device
90 * @me_cl: me client
91 *
92 * Locking: dev->me_clients_rwsem
93 */
94static void __mei_me_cl_del(struct mei_device *dev, struct mei_me_client *me_cl)
95{
96 if (!me_cl)
97 return;
98
99 list_del(&me_cl->list);
100 mei_me_cl_put(me_cl);
101}
102
103/**
104 * mei_me_cl_add - add me client to the list
105 *
106 * @dev: mei device
107 * @me_cl: me client
108 */
109void mei_me_cl_add(struct mei_device *dev, struct mei_me_client *me_cl)
110{
111 down_write(&dev->me_clients_rwsem);
112 list_add(&me_cl->list, &dev->me_clients);
113 up_write(&dev->me_clients_rwsem);
114}
115
116/**
117 * __mei_me_cl_by_uuid - locate me client by uuid
118 * increases ref count
119 *
120 * @dev: mei device
121 * @uuid: me client uuid
122 *
123 * Return: me client or NULL if not found
124 *
125 * Locking: dev->me_clients_rwsem
126 */
127static struct mei_me_client *__mei_me_cl_by_uuid(struct mei_device *dev,
128 const uuid_le *uuid)
129{
130 struct mei_me_client *me_cl;
131 const uuid_le *pn;
132
133 WARN_ON(!rwsem_is_locked(&dev->me_clients_rwsem));
134
135 list_for_each_entry(me_cl, &dev->me_clients, list) {
136 pn = &me_cl->props.protocol_name;
137 if (uuid_le_cmp(*uuid, *pn) == 0)
138 return mei_me_cl_get(me_cl);
139 }
140
141 return NULL;
142}
143
144/**
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300145 * mei_me_cl_by_uuid - locate me client by uuid
Tomas Winkler79563db2015-01-11 00:07:16 +0200146 * increases ref count
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200147 *
148 * @dev: mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300149 * @uuid: me client uuid
Alexander Usyskina27a76d2014-02-17 15:13:22 +0200150 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300151 * Return: me client or NULL if not found
Tomas Winklerb7d88512015-02-10 10:39:31 +0200152 *
153 * Locking: dev->me_clients_rwsem
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200154 */
Tomas Winklerb7d88512015-02-10 10:39:31 +0200155struct mei_me_client *mei_me_cl_by_uuid(struct mei_device *dev,
Tomas Winklerd3208322014-08-24 12:08:55 +0300156 const uuid_le *uuid)
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200157{
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300158 struct mei_me_client *me_cl;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200159
Tomas Winklerb7d88512015-02-10 10:39:31 +0200160 down_read(&dev->me_clients_rwsem);
161 me_cl = __mei_me_cl_by_uuid(dev, uuid);
162 up_read(&dev->me_clients_rwsem);
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200163
Tomas Winklerb7d88512015-02-10 10:39:31 +0200164 return me_cl;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200165}
166
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200167/**
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300168 * mei_me_cl_by_id - locate me client by client id
Tomas Winkler79563db2015-01-11 00:07:16 +0200169 * increases ref count
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200170 *
171 * @dev: the device structure
172 * @client_id: me client id
173 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300174 * Return: me client or NULL if not found
Tomas Winklerb7d88512015-02-10 10:39:31 +0200175 *
176 * Locking: dev->me_clients_rwsem
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200177 */
Tomas Winklerd3208322014-08-24 12:08:55 +0300178struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200179{
Alexander Usyskina27a76d2014-02-17 15:13:22 +0200180
Tomas Winklerb7d88512015-02-10 10:39:31 +0200181 struct mei_me_client *__me_cl, *me_cl = NULL;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200182
Tomas Winklerb7d88512015-02-10 10:39:31 +0200183 down_read(&dev->me_clients_rwsem);
184 list_for_each_entry(__me_cl, &dev->me_clients, list) {
185 if (__me_cl->client_id == client_id) {
186 me_cl = mei_me_cl_get(__me_cl);
187 break;
188 }
189 }
190 up_read(&dev->me_clients_rwsem);
191
192 return me_cl;
193}
194
195/**
196 * __mei_me_cl_by_uuid_id - locate me client by client id and uuid
197 * increases ref count
198 *
199 * @dev: the device structure
200 * @uuid: me client uuid
201 * @client_id: me client id
202 *
203 * Return: me client or null if not found
204 *
205 * Locking: dev->me_clients_rwsem
206 */
207static struct mei_me_client *__mei_me_cl_by_uuid_id(struct mei_device *dev,
208 const uuid_le *uuid, u8 client_id)
209{
210 struct mei_me_client *me_cl;
211 const uuid_le *pn;
212
213 WARN_ON(!rwsem_is_locked(&dev->me_clients_rwsem));
214
215 list_for_each_entry(me_cl, &dev->me_clients, list) {
216 pn = &me_cl->props.protocol_name;
217 if (uuid_le_cmp(*uuid, *pn) == 0 &&
218 me_cl->client_id == client_id)
Tomas Winkler79563db2015-01-11 00:07:16 +0200219 return mei_me_cl_get(me_cl);
Tomas Winklerb7d88512015-02-10 10:39:31 +0200220 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200221
Tomas Winklerd3208322014-08-24 12:08:55 +0300222 return NULL;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200223}
Tomas Winkler9ca90502013-01-08 23:07:13 +0200224
Tomas Winklerb7d88512015-02-10 10:39:31 +0200225
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300226/**
227 * mei_me_cl_by_uuid_id - locate me client by client id and uuid
Tomas Winkler79563db2015-01-11 00:07:16 +0200228 * increases ref count
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300229 *
230 * @dev: the device structure
231 * @uuid: me client uuid
232 * @client_id: me client id
233 *
Tomas Winklerb7d88512015-02-10 10:39:31 +0200234 * Return: me client or null if not found
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300235 */
Tomas Winklerd880f322014-08-21 14:29:15 +0300236struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
237 const uuid_le *uuid, u8 client_id)
238{
239 struct mei_me_client *me_cl;
240
Tomas Winklerb7d88512015-02-10 10:39:31 +0200241 down_read(&dev->me_clients_rwsem);
242 me_cl = __mei_me_cl_by_uuid_id(dev, uuid, client_id);
243 up_read(&dev->me_clients_rwsem);
Tomas Winkler79563db2015-01-11 00:07:16 +0200244
Tomas Winklerb7d88512015-02-10 10:39:31 +0200245 return me_cl;
Tomas Winklerd880f322014-08-21 14:29:15 +0300246}
247
Tomas Winkler25ca6472014-08-21 14:29:14 +0300248/**
Tomas Winkler79563db2015-01-11 00:07:16 +0200249 * mei_me_cl_rm_by_uuid - remove all me clients matching uuid
Tomas Winkler25ca6472014-08-21 14:29:14 +0300250 *
251 * @dev: the device structure
252 * @uuid: me client uuid
Tomas Winkler79563db2015-01-11 00:07:16 +0200253 *
254 * Locking: called under "dev->device_lock" lock
Tomas Winkler25ca6472014-08-21 14:29:14 +0300255 */
Tomas Winkler79563db2015-01-11 00:07:16 +0200256void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid)
Tomas Winkler25ca6472014-08-21 14:29:14 +0300257{
Tomas Winklerb7d88512015-02-10 10:39:31 +0200258 struct mei_me_client *me_cl;
Tomas Winkler25ca6472014-08-21 14:29:14 +0300259
Tomas Winkler79563db2015-01-11 00:07:16 +0200260 dev_dbg(dev->dev, "remove %pUl\n", uuid);
Tomas Winklerb7d88512015-02-10 10:39:31 +0200261
262 down_write(&dev->me_clients_rwsem);
263 me_cl = __mei_me_cl_by_uuid(dev, uuid);
264 __mei_me_cl_del(dev, me_cl);
265 up_write(&dev->me_clients_rwsem);
Tomas Winkler79563db2015-01-11 00:07:16 +0200266}
267
268/**
269 * mei_me_cl_rm_by_uuid_id - remove all me clients matching client id
270 *
271 * @dev: the device structure
272 * @uuid: me client uuid
273 * @id: me client id
274 *
275 * Locking: called under "dev->device_lock" lock
276 */
277void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 id)
278{
Tomas Winklerb7d88512015-02-10 10:39:31 +0200279 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200280
281 dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id);
Tomas Winklerb7d88512015-02-10 10:39:31 +0200282
283 down_write(&dev->me_clients_rwsem);
284 me_cl = __mei_me_cl_by_uuid_id(dev, uuid, id);
285 __mei_me_cl_del(dev, me_cl);
286 up_write(&dev->me_clients_rwsem);
Tomas Winkler25ca6472014-08-21 14:29:14 +0300287}
288
Tomas Winkler79563db2015-01-11 00:07:16 +0200289/**
290 * mei_me_cl_rm_all - remove all me clients
291 *
292 * @dev: the device structure
293 *
294 * Locking: called under "dev->device_lock" lock
295 */
296void mei_me_cl_rm_all(struct mei_device *dev)
297{
298 struct mei_me_client *me_cl, *next;
299
Tomas Winklerb7d88512015-02-10 10:39:31 +0200300 down_write(&dev->me_clients_rwsem);
Tomas Winkler79563db2015-01-11 00:07:16 +0200301 list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
Tomas Winklerb7d88512015-02-10 10:39:31 +0200302 __mei_me_cl_del(dev, me_cl);
303 up_write(&dev->me_clients_rwsem);
Tomas Winkler79563db2015-01-11 00:07:16 +0200304}
305
Tomas Winkler9ca90502013-01-08 23:07:13 +0200306/**
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200307 * mei_cl_cmp_id - tells if the clients are the same
308 *
309 * @cl1: host client 1
310 * @cl2: host client 2
311 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300312 * Return: true - if the clients has same host and me ids
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200313 * false - otherwise
314 */
315static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
316 const struct mei_cl *cl2)
317{
318 return cl1 && cl2 &&
319 (cl1->host_client_id == cl2->host_client_id) &&
320 (cl1->me_client_id == cl2->me_client_id);
321}
322
323/**
Tomas Winkler9ca90502013-01-08 23:07:13 +0200324 * mei_io_cb_free - free mei_cb_private related memory
325 *
326 * @cb: mei callback struct
327 */
328void mei_io_cb_free(struct mei_cl_cb *cb)
329{
330 if (cb == NULL)
331 return;
332
Tomas Winkler928fa662015-02-10 10:39:45 +0200333 list_del(&cb->list);
Tomas Winkler5db75142015-02-10 10:39:42 +0200334 kfree(cb->buf.data);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200335 kfree(cb);
336}
337
338/**
339 * mei_io_cb_init - allocate and initialize io callback
340 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300341 * @cl: mei client
Tomas Winklerbca67d62015-02-10 10:39:43 +0200342 * @type: operation type
Masanari Iida393b1482013-04-05 01:05:05 +0900343 * @fp: pointer to file structure
Tomas Winkler9ca90502013-01-08 23:07:13 +0200344 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300345 * Return: mei_cl_cb pointer or NULL;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200346 */
Tomas Winklerbca67d62015-02-10 10:39:43 +0200347struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
348 struct file *fp)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200349{
350 struct mei_cl_cb *cb;
351
352 cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
353 if (!cb)
354 return NULL;
355
Tomas Winkler928fa662015-02-10 10:39:45 +0200356 INIT_LIST_HEAD(&cb->list);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200357 cb->file_object = fp;
358 cb->cl = cl;
359 cb->buf_idx = 0;
Tomas Winklerbca67d62015-02-10 10:39:43 +0200360 cb->fop_type = type;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200361 return cb;
362}
363
364/**
Tomas Winkler928fa662015-02-10 10:39:45 +0200365 * __mei_io_list_flush - removes and frees cbs belonging to cl.
366 *
367 * @list: an instance of our list structure
368 * @cl: host client, can be NULL for flushing the whole list
369 * @free: whether to free the cbs
370 */
371static void __mei_io_list_flush(struct mei_cl_cb *list,
372 struct mei_cl *cl, bool free)
373{
374 struct mei_cl_cb *cb, *next;
375
376 /* enable removing everything if no cl is specified */
377 list_for_each_entry_safe(cb, next, &list->list, list) {
378 if (!cl || mei_cl_cmp_id(cl, cb->cl)) {
379 list_del_init(&cb->list);
380 if (free)
381 mei_io_cb_free(cb);
382 }
383 }
384}
385
386/**
387 * mei_io_list_flush - removes list entry belonging to cl.
388 *
389 * @list: An instance of our list structure
390 * @cl: host client
391 */
392void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
393{
394 __mei_io_list_flush(list, cl, false);
395}
396
397/**
398 * mei_io_list_free - removes cb belonging to cl and free them
399 *
400 * @list: An instance of our list structure
401 * @cl: host client
402 */
403static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
404{
405 __mei_io_list_flush(list, cl, true);
406}
407
408/**
Tomas Winkler5db75142015-02-10 10:39:42 +0200409 * mei_io_cb_alloc_buf - allocate callback buffer
Tomas Winkler9ca90502013-01-08 23:07:13 +0200410 *
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 */
Tomas Winkler5db75142015-02-10 10:39:42 +0200418int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200419{
420 if (!cb)
421 return -EINVAL;
422
423 if (length == 0)
424 return 0;
425
Tomas Winkler5db75142015-02-10 10:39:42 +0200426 cb->buf.data = kmalloc(length, GFP_KERNEL);
427 if (!cb->buf.data)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200428 return -ENOMEM;
Tomas Winkler5db75142015-02-10 10:39:42 +0200429 cb->buf.size = length;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200430 return 0;
431}
Tomas Winkler9ca90502013-01-08 23:07:13 +0200432
433/**
Tomas Winklerbca67d62015-02-10 10:39:43 +0200434 * mei_cl_alloc_cb - a convenient wrapper for allocating read cb
435 *
436 * @cl: host client
437 * @length: size of the buffer
438 * @type: operation type
439 * @fp: associated file pointer (might be NULL)
440 *
441 * Return: cb on success and NULL on failure
442 */
443struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
444 enum mei_cb_file_ops type, struct file *fp)
445{
446 struct mei_cl_cb *cb;
447
448 cb = mei_io_cb_init(cl, type, fp);
449 if (!cb)
450 return NULL;
451
452 if (mei_io_cb_alloc_buf(cb, length)) {
453 mei_io_cb_free(cb);
454 return NULL;
455 }
456
457 return cb;
458}
459
460/**
Tomas Winkler9ca90502013-01-08 23:07:13 +0200461 * mei_cl_flush_queues - flushes queue lists belonging to cl.
462 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200463 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300464 *
465 * Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200466 */
467int mei_cl_flush_queues(struct mei_cl *cl)
468{
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300469 struct mei_device *dev;
470
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200471 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200472 return -EINVAL;
473
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300474 dev = cl->dev;
475
476 cl_dbg(dev, cl, "remove list entry belonging to cl\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200477 mei_io_list_flush(&cl->dev->read_list, cl);
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200478 mei_io_list_free(&cl->dev->write_list, cl);
479 mei_io_list_free(&cl->dev->write_waiting_list, cl);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200480 mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
481 mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
482 mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
483 mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
484 return 0;
485}
486
Tomas Winkler9ca90502013-01-08 23:07:13 +0200487
488/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200489 * mei_cl_init - initializes cl.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200490 *
491 * @cl: host client to be initialized
492 * @dev: mei device
493 */
494void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
495{
496 memset(cl, 0, sizeof(struct mei_cl));
497 init_waitqueue_head(&cl->wait);
498 init_waitqueue_head(&cl->rx_wait);
499 init_waitqueue_head(&cl->tx_wait);
500 INIT_LIST_HEAD(&cl->link);
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200501 INIT_LIST_HEAD(&cl->device_link);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200502 cl->reading_state = MEI_IDLE;
503 cl->writing_state = MEI_IDLE;
504 cl->dev = dev;
505}
506
507/**
508 * mei_cl_allocate - allocates cl structure and sets it up.
509 *
510 * @dev: mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300511 * Return: The allocated file or NULL on failure
Tomas Winkler9ca90502013-01-08 23:07:13 +0200512 */
513struct mei_cl *mei_cl_allocate(struct mei_device *dev)
514{
515 struct mei_cl *cl;
516
517 cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
518 if (!cl)
519 return NULL;
520
521 mei_cl_init(cl, dev);
522
523 return cl;
524}
525
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200526/**
527 * mei_cl_find_read_cb - find this cl's callback in the read list
528 *
Masanari Iida393b1482013-04-05 01:05:05 +0900529 * @cl: host client
530 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300531 * Return: cb on success, NULL on error
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200532 */
533struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
534{
535 struct mei_device *dev = cl->dev;
Tomas Winkler31f88f52014-02-17 15:13:25 +0200536 struct mei_cl_cb *cb;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200537
Tomas Winkler31f88f52014-02-17 15:13:25 +0200538 list_for_each_entry(cb, &dev->read_list.list, list)
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200539 if (mei_cl_cmp_id(cl, cb->cl))
540 return cb;
541 return NULL;
542}
543
Alexander Usyskin3908be62015-02-10 10:39:35 +0200544/**
545 * mei_cl_link - allocate host id in the host map
Tomas Winkler9ca90502013-01-08 23:07:13 +0200546 *
Alexander Usyskin3908be62015-02-10 10:39:35 +0200547 * @cl: host client
Tomas Winkler03b8d342015-02-10 10:39:44 +0200548 * @id: fixed host id or MEI_HOST_CLIENT_ID_ANY (-1) for generic one
Masanari Iida393b1482013-04-05 01:05:05 +0900549 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300550 * Return: 0 on success
Tomas Winkler9ca90502013-01-08 23:07:13 +0200551 * -EINVAL on incorrect values
Tomas Winkler03b8d342015-02-10 10:39:44 +0200552 * -EMFILE if open count exceeded.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200553 */
Tomas Winkler781d0d82013-01-08 23:07:22 +0200554int mei_cl_link(struct mei_cl *cl, int id)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200555{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200556 struct mei_device *dev;
Tomas Winkler22f96a02013-09-16 23:44:47 +0300557 long open_handle_count;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200558
Tomas Winkler781d0d82013-01-08 23:07:22 +0200559 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200560 return -EINVAL;
561
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200562 dev = cl->dev;
563
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200564 /* If Id is not assigned get one*/
Tomas Winkler781d0d82013-01-08 23:07:22 +0200565 if (id == MEI_HOST_CLIENT_ID_ANY)
566 id = find_first_zero_bit(dev->host_clients_map,
567 MEI_CLIENTS_MAX);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200568
Tomas Winkler781d0d82013-01-08 23:07:22 +0200569 if (id >= MEI_CLIENTS_MAX) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300570 dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
Tomas Winklere036cc52013-09-16 23:44:46 +0300571 return -EMFILE;
572 }
573
Tomas Winkler22f96a02013-09-16 23:44:47 +0300574 open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
575 if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300576 dev_err(dev->dev, "open_handle_count exceeded %d",
Tomas Winklere036cc52013-09-16 23:44:46 +0300577 MEI_MAX_OPEN_HANDLE_COUNT);
578 return -EMFILE;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200579 }
580
Tomas Winkler781d0d82013-01-08 23:07:22 +0200581 dev->open_handle_count++;
582
583 cl->host_client_id = id;
584 list_add_tail(&cl->link, &dev->file_list);
585
586 set_bit(id, dev->host_clients_map);
587
588 cl->state = MEI_FILE_INITIALIZING;
589
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300590 cl_dbg(dev, cl, "link cl\n");
Tomas Winkler781d0d82013-01-08 23:07:22 +0200591 return 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200592}
Tomas Winkler781d0d82013-01-08 23:07:22 +0200593
Tomas Winkler9ca90502013-01-08 23:07:13 +0200594/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200595 * mei_cl_unlink - remove me_cl from the list
Tomas Winkler9ca90502013-01-08 23:07:13 +0200596 *
Masanari Iida393b1482013-04-05 01:05:05 +0900597 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300598 *
599 * Return: always 0
Tomas Winkler9ca90502013-01-08 23:07:13 +0200600 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200601int mei_cl_unlink(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200602{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200603 struct mei_device *dev;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200604
Tomas Winkler781d0d82013-01-08 23:07:22 +0200605 /* don't shout on error exit path */
606 if (!cl)
607 return 0;
608
Tomas Winkler8e9a4a92013-01-10 17:32:14 +0200609 /* wd and amthif might not be initialized */
610 if (!cl->dev)
611 return 0;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200612
613 dev = cl->dev;
614
Tomas Winklera14c44d2013-09-16 23:44:45 +0300615 cl_dbg(dev, cl, "unlink client");
616
Tomas Winkler22f96a02013-09-16 23:44:47 +0300617 if (dev->open_handle_count > 0)
618 dev->open_handle_count--;
619
620 /* never clear the 0 bit */
621 if (cl->host_client_id)
622 clear_bit(cl->host_client_id, dev->host_clients_map);
623
624 list_del_init(&cl->link);
625
626 cl->state = MEI_FILE_INITIALIZING;
627
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200628 return 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200629}
630
631
632void mei_host_client_init(struct work_struct *work)
633{
Tomas Winklerb7d88512015-02-10 10:39:31 +0200634 struct mei_device *dev =
635 container_of(work, struct mei_device, init_work);
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300636 struct mei_me_client *me_cl;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200637
638 mutex_lock(&dev->device_lock);
639
Tomas Winkler9ca90502013-01-08 23:07:13 +0200640
Tomas Winklerb7d88512015-02-10 10:39:31 +0200641 me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
642 if (me_cl)
643 mei_amthif_host_init(dev);
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200644
Tomas Winklerb7d88512015-02-10 10:39:31 +0200645 me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid);
646 if (me_cl)
647 mei_wd_host_init(dev);
648
649 me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
650 if (me_cl)
651 mei_nfc_host_init(dev);
652
Tomas Winkler9ca90502013-01-08 23:07:13 +0200653
654 dev->dev_state = MEI_DEV_ENABLED;
Tomas Winkler6adb8ef2014-01-12 00:36:10 +0200655 dev->reset_count = 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200656 mutex_unlock(&dev->device_lock);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200657
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300658 pm_runtime_mark_last_busy(dev->dev);
659 dev_dbg(dev->dev, "rpm: autosuspend\n");
660 pm_runtime_autosuspend(dev->dev);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200661}
662
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200663/**
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300664 * mei_hbuf_acquire - try to acquire host buffer
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200665 *
666 * @dev: the device structure
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300667 * Return: true if host buffer was acquired
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200668 */
669bool mei_hbuf_acquire(struct mei_device *dev)
670{
Tomas Winkler04bb1392014-03-18 22:52:04 +0200671 if (mei_pg_state(dev) == MEI_PG_ON ||
672 dev->pg_event == MEI_PG_EVENT_WAIT) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300673 dev_dbg(dev->dev, "device is in pg\n");
Tomas Winkler04bb1392014-03-18 22:52:04 +0200674 return false;
675 }
676
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200677 if (!dev->hbuf_is_ready) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300678 dev_dbg(dev->dev, "hbuf is not ready\n");
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200679 return false;
680 }
681
682 dev->hbuf_is_ready = false;
683
684 return true;
685}
Tomas Winkler9ca90502013-01-08 23:07:13 +0200686
687/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200688 * mei_cl_disconnect - disconnect host client from the me one
Tomas Winkler9ca90502013-01-08 23:07:13 +0200689 *
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200690 * @cl: host client
Tomas Winkler9ca90502013-01-08 23:07:13 +0200691 *
692 * Locking: called under "dev->device_lock" lock
693 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300694 * Return: 0 on success, <0 on failure.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200695 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200696int mei_cl_disconnect(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200697{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200698 struct mei_device *dev;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200699 struct mei_cl_cb *cb;
Alexander Usyskinfe2f17e2014-07-17 10:53:38 +0300700 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200701
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200702 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200703 return -ENODEV;
704
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200705 dev = cl->dev;
706
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300707 cl_dbg(dev, cl, "disconnecting");
708
Tomas Winkler9ca90502013-01-08 23:07:13 +0200709 if (cl->state != MEI_FILE_DISCONNECTING)
710 return 0;
711
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300712 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200713 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300714 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200715 cl_err(dev, cl, "rpm: get failed %d\n", rets);
716 return rets;
717 }
718
Tomas Winklerbca67d62015-02-10 10:39:43 +0200719 cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT, NULL);
720 rets = cb ? 0 : -ENOMEM;
721 if (rets)
Tomas Winkler04bb1392014-03-18 22:52:04 +0200722 goto free;
Tomas Winkler5a8373f2014-08-21 14:29:17 +0300723
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200724 if (mei_hbuf_acquire(dev)) {
Tomas Winkler9ca90502013-01-08 23:07:13 +0200725 if (mei_hbm_cl_disconnect_req(dev, cl)) {
726 rets = -ENODEV;
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300727 cl_err(dev, cl, "failed to disconnect.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200728 goto free;
729 }
Alexander Usyskin22b987a2014-07-17 10:53:35 +0300730 cl->timer_count = MEI_CONNECT_TIMEOUT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200731 mdelay(10); /* Wait for hardware disconnection ready */
732 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
733 } else {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300734 cl_dbg(dev, cl, "add disconnect cb to control write list\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200735 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
736
737 }
738 mutex_unlock(&dev->device_lock);
739
Tomas Winkler12f45ed2014-08-21 14:29:18 +0300740 wait_event_timeout(cl->wait,
Tomas Winkler9ca90502013-01-08 23:07:13 +0200741 MEI_FILE_DISCONNECTED == cl->state,
742 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
743
744 mutex_lock(&dev->device_lock);
Alexander Usyskinfe2f17e2014-07-17 10:53:38 +0300745
Tomas Winkler9ca90502013-01-08 23:07:13 +0200746 if (MEI_FILE_DISCONNECTED == cl->state) {
747 rets = 0;
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300748 cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200749 } else {
Alexander Usyskinfe2f17e2014-07-17 10:53:38 +0300750 cl_dbg(dev, cl, "timeout on disconnect from FW client.\n");
751 rets = -ETIME;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200752 }
753
754 mei_io_list_flush(&dev->ctrl_rd_list, cl);
755 mei_io_list_flush(&dev->ctrl_wr_list, cl);
756free:
Tomas Winkler04bb1392014-03-18 22:52:04 +0200757 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300758 pm_runtime_mark_last_busy(dev->dev);
759 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200760
Tomas Winkler9ca90502013-01-08 23:07:13 +0200761 mei_io_cb_free(cb);
762 return rets;
763}
764
765
766/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200767 * mei_cl_is_other_connecting - checks if other
768 * client with the same me client id is connecting
Tomas Winkler9ca90502013-01-08 23:07:13 +0200769 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200770 * @cl: private data of the file object
771 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300772 * Return: true if other client is connected, false - otherwise.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200773 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200774bool mei_cl_is_other_connecting(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200775{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200776 struct mei_device *dev;
Tomas Winkler31f88f52014-02-17 15:13:25 +0200777 struct mei_cl *ocl; /* the other client */
Tomas Winkler9ca90502013-01-08 23:07:13 +0200778
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200779 if (WARN_ON(!cl || !cl->dev))
780 return false;
781
782 dev = cl->dev;
783
Tomas Winkler31f88f52014-02-17 15:13:25 +0200784 list_for_each_entry(ocl, &dev->file_list, link) {
785 if (ocl->state == MEI_FILE_CONNECTING &&
786 ocl != cl &&
787 cl->me_client_id == ocl->me_client_id)
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200788 return true;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200789
790 }
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200791
792 return false;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200793}
794
795/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200796 * mei_cl_connect - connect host client to the me one
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200797 *
798 * @cl: host client
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300799 * @file: pointer to file structure
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200800 *
801 * Locking: called under "dev->device_lock" lock
802 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300803 * Return: 0 on success, <0 on failure.
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200804 */
805int mei_cl_connect(struct mei_cl *cl, struct file *file)
806{
807 struct mei_device *dev;
808 struct mei_cl_cb *cb;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200809 int rets;
810
811 if (WARN_ON(!cl || !cl->dev))
812 return -ENODEV;
813
814 dev = cl->dev;
815
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300816 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200817 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300818 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200819 cl_err(dev, cl, "rpm: get failed %d\n", rets);
820 return rets;
821 }
822
Tomas Winklerbca67d62015-02-10 10:39:43 +0200823 cb = mei_io_cb_init(cl, MEI_FOP_CONNECT, file);
824 rets = cb ? 0 : -ENOMEM;
825 if (rets)
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200826 goto out;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200827
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200828 /* run hbuf acquire last so we don't have to undo */
829 if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
Alexander Usyskine4d82702014-04-27 15:42:21 +0300830 cl->state = MEI_FILE_CONNECTING;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200831 if (mei_hbm_cl_connect_req(dev, cl)) {
832 rets = -ENODEV;
833 goto out;
834 }
835 cl->timer_count = MEI_CONNECT_TIMEOUT;
836 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
837 } else {
Alexander Usyskin73ab4232014-08-12 18:07:56 +0300838 cl->state = MEI_FILE_INITIALIZING;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200839 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
840 }
841
842 mutex_unlock(&dev->device_lock);
Tomas Winkler12f45ed2014-08-21 14:29:18 +0300843 wait_event_timeout(cl->wait,
Alexander Usyskin285e2992014-02-17 15:13:20 +0200844 (cl->state == MEI_FILE_CONNECTED ||
845 cl->state == MEI_FILE_DISCONNECTED),
846 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200847 mutex_lock(&dev->device_lock);
848
849 if (cl->state != MEI_FILE_CONNECTED) {
Alexander Usyskin3e37ebb2014-07-17 10:53:34 +0300850 cl->state = MEI_FILE_DISCONNECTED;
Alexander Usyskin285e2992014-02-17 15:13:20 +0200851 /* something went really wrong */
852 if (!cl->status)
853 cl->status = -EFAULT;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200854
855 mei_io_list_flush(&dev->ctrl_rd_list, cl);
856 mei_io_list_flush(&dev->ctrl_wr_list, cl);
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200857 }
858
859 rets = cl->status;
860
861out:
Tomas Winkler04bb1392014-03-18 22:52:04 +0200862 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300863 pm_runtime_mark_last_busy(dev->dev);
864 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200865
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200866 mei_io_cb_free(cb);
867 return rets;
868}
869
870/**
Tomas Winkler03b8d342015-02-10 10:39:44 +0200871 * mei_cl_alloc_linked - allocate and link host client
872 *
873 * @dev: the device structure
874 * @id: fixed host id or MEI_HOST_CLIENT_ID_ANY (-1) for generic one
875 *
876 * Return: cl on success ERR_PTR on failure
877 */
878struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id)
879{
880 struct mei_cl *cl;
881 int ret;
882
883 cl = mei_cl_allocate(dev);
884 if (!cl) {
885 ret = -ENOMEM;
886 goto err;
887 }
888
889 ret = mei_cl_link(cl, id);
890 if (ret)
891 goto err;
892
893 return cl;
894err:
895 kfree(cl);
896 return ERR_PTR(ret);
897}
898
899
900
901/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200902 * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200903 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200904 * @cl: private data of the file object
905 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300906 * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200907 * -ENOENT if mei_cl is not present
908 * -EINVAL if single_recv_buf == 0
909 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200910int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200911{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200912 struct mei_device *dev;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200913 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200914 int rets = 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200915
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200916 if (WARN_ON(!cl || !cl->dev))
917 return -EINVAL;
918
919 dev = cl->dev;
920
Tomas Winkler9ca90502013-01-08 23:07:13 +0200921 if (cl->mei_flow_ctrl_creds > 0)
922 return 1;
923
Tomas Winkler2e5df412014-12-07 16:40:14 +0200924 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300925 if (!me_cl) {
Alexander Usyskin12d00662014-02-17 15:13:23 +0200926 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300927 return -ENOENT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200928 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200929
Tomas Winkler79563db2015-01-11 00:07:16 +0200930 if (me_cl->mei_flow_ctrl_creds > 0) {
931 rets = 1;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200932 if (WARN_ON(me_cl->props.single_recv_buf == 0))
Tomas Winkler79563db2015-01-11 00:07:16 +0200933 rets = -EINVAL;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200934 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200935 mei_me_cl_put(me_cl);
936 return rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200937}
938
939/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200940 * mei_cl_flow_ctrl_reduce - reduces flow_control.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200941 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200942 * @cl: private data of the file object
Masanari Iida393b1482013-04-05 01:05:05 +0900943 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300944 * Return:
Tomas Winkler9ca90502013-01-08 23:07:13 +0200945 * 0 on success
946 * -ENOENT when me client is not found
947 * -EINVAL when ctrl credits are <= 0
948 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200949int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200950{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200951 struct mei_device *dev;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200952 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200953 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200954
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200955 if (WARN_ON(!cl || !cl->dev))
956 return -EINVAL;
957
958 dev = cl->dev;
959
Tomas Winkler2e5df412014-12-07 16:40:14 +0200960 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300961 if (!me_cl) {
Alexander Usyskin12d00662014-02-17 15:13:23 +0200962 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300963 return -ENOENT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200964 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200965
Tomas Winklerd3208322014-08-24 12:08:55 +0300966 if (me_cl->props.single_recv_buf) {
Tomas Winkler79563db2015-01-11 00:07:16 +0200967 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
968 rets = -EINVAL;
969 goto out;
970 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200971 me_cl->mei_flow_ctrl_creds--;
972 } else {
Tomas Winkler79563db2015-01-11 00:07:16 +0200973 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
974 rets = -EINVAL;
975 goto out;
976 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200977 cl->mei_flow_ctrl_creds--;
978 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200979 rets = 0;
980out:
981 mei_me_cl_put(me_cl);
982 return rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200983}
984
Tomas Winkler9ca90502013-01-08 23:07:13 +0200985/**
Masanari Iida393b1482013-04-05 01:05:05 +0900986 * mei_cl_read_start - the start read client message function.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200987 *
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200988 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300989 * @length: number of bytes to read
Tomas Winklerbca67d62015-02-10 10:39:43 +0200990 * @fp: pointer to file structure
Tomas Winkler9ca90502013-01-08 23:07:13 +0200991 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300992 * Return: 0 on success, <0 on failure.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200993 */
Tomas Winklerbca67d62015-02-10 10:39:43 +0200994int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200995{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200996 struct mei_device *dev;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200997 struct mei_cl_cb *cb;
Tomas Winklerd3208322014-08-24 12:08:55 +0300998 struct mei_me_client *me_cl;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200999 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001000
Tomas Winkler90e0b5f12013-01-08 23:07:14 +02001001 if (WARN_ON(!cl || !cl->dev))
1002 return -ENODEV;
1003
1004 dev = cl->dev;
1005
Tomas Winklerb950ac12013-07-25 20:15:53 +03001006 if (!mei_cl_is_connected(cl))
Tomas Winkler9ca90502013-01-08 23:07:13 +02001007 return -ENODEV;
1008
Tomas Winklerd91aaed2013-01-08 23:07:18 +02001009 if (cl->read_cb) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001010 cl_dbg(dev, cl, "read is pending.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +02001011 return -EBUSY;
1012 }
Tomas Winklerd880f322014-08-21 14:29:15 +03001013 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +03001014 if (!me_cl) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001015 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001016 return -ENOTTY;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001017 }
Tomas Winkler79563db2015-01-11 00:07:16 +02001018 /* always allocate at least client max message */
1019 length = max_t(size_t, length, me_cl->props.max_msg_length);
1020 mei_me_cl_put(me_cl);
Tomas Winkler9ca90502013-01-08 23:07:13 +02001021
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001022 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001023 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001024 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001025 cl_err(dev, cl, "rpm: get failed %d\n", rets);
1026 return rets;
1027 }
1028
Tomas Winklerbca67d62015-02-10 10:39:43 +02001029 cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp);
1030 rets = cb ? 0 : -ENOMEM;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001031 if (rets)
Tomas Winkler04bb1392014-03-18 22:52:04 +02001032 goto out;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001033
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001034 if (mei_hbuf_acquire(dev)) {
Alexander Usyskin86113502014-03-31 17:59:24 +03001035 rets = mei_hbm_cl_flow_control_req(dev, cl);
1036 if (rets < 0)
Tomas Winkler04bb1392014-03-18 22:52:04 +02001037 goto out;
Tomas Winkler04bb1392014-03-18 22:52:04 +02001038
Tomas Winkler9ca90502013-01-08 23:07:13 +02001039 list_add_tail(&cb->list, &dev->read_list.list);
1040 } else {
1041 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
1042 }
Chao Biaccb8842014-02-12 21:27:25 +02001043
1044 cl->read_cb = cb;
1045
Tomas Winkler04bb1392014-03-18 22:52:04 +02001046out:
1047 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001048 pm_runtime_mark_last_busy(dev->dev);
1049 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001050
1051 if (rets)
1052 mei_io_cb_free(cb);
1053
Tomas Winkler9ca90502013-01-08 23:07:13 +02001054 return rets;
1055}
1056
Tomas Winkler074b4c02013-02-06 14:06:44 +02001057/**
Tomas Winkler9d098192014-02-19 17:35:48 +02001058 * mei_cl_irq_write - write a message to device
Tomas Winkler21767542013-06-23 09:36:59 +03001059 * from the interrupt thread context
1060 *
1061 * @cl: client
1062 * @cb: callback block.
Tomas Winkler21767542013-06-23 09:36:59 +03001063 * @cmpl_list: complete list.
1064 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001065 * Return: 0, OK; otherwise error.
Tomas Winkler21767542013-06-23 09:36:59 +03001066 */
Tomas Winkler9d098192014-02-19 17:35:48 +02001067int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
1068 struct mei_cl_cb *cmpl_list)
Tomas Winkler21767542013-06-23 09:36:59 +03001069{
Tomas Winkler136698e2013-09-16 23:44:44 +03001070 struct mei_device *dev;
1071 struct mei_msg_data *buf;
Tomas Winkler21767542013-06-23 09:36:59 +03001072 struct mei_msg_hdr mei_hdr;
Tomas Winkler136698e2013-09-16 23:44:44 +03001073 size_t len;
1074 u32 msg_slots;
Tomas Winkler9d098192014-02-19 17:35:48 +02001075 int slots;
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001076 int rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001077
Tomas Winkler136698e2013-09-16 23:44:44 +03001078 if (WARN_ON(!cl || !cl->dev))
1079 return -ENODEV;
1080
1081 dev = cl->dev;
1082
Tomas Winkler5db75142015-02-10 10:39:42 +02001083 buf = &cb->buf;
Tomas Winkler136698e2013-09-16 23:44:44 +03001084
1085 rets = mei_cl_flow_ctrl_creds(cl);
1086 if (rets < 0)
1087 return rets;
1088
1089 if (rets == 0) {
Tomas Winkler04bb1392014-03-18 22:52:04 +02001090 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
Tomas Winkler136698e2013-09-16 23:44:44 +03001091 return 0;
1092 }
1093
Tomas Winkler9d098192014-02-19 17:35:48 +02001094 slots = mei_hbuf_empty_slots(dev);
Tomas Winkler136698e2013-09-16 23:44:44 +03001095 len = buf->size - cb->buf_idx;
1096 msg_slots = mei_data2slots(len);
1097
Tomas Winkler21767542013-06-23 09:36:59 +03001098 mei_hdr.host_addr = cl->host_client_id;
1099 mei_hdr.me_addr = cl->me_client_id;
1100 mei_hdr.reserved = 0;
Tomas Winkler479327f2013-12-17 15:56:56 +02001101 mei_hdr.internal = cb->internal;
Tomas Winkler21767542013-06-23 09:36:59 +03001102
Tomas Winkler9d098192014-02-19 17:35:48 +02001103 if (slots >= msg_slots) {
Tomas Winkler21767542013-06-23 09:36:59 +03001104 mei_hdr.length = len;
1105 mei_hdr.msg_complete = 1;
1106 /* Split the message only if we can write the whole host buffer */
Tomas Winkler9d098192014-02-19 17:35:48 +02001107 } else if (slots == dev->hbuf_depth) {
1108 msg_slots = slots;
1109 len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
Tomas Winkler21767542013-06-23 09:36:59 +03001110 mei_hdr.length = len;
1111 mei_hdr.msg_complete = 0;
1112 } else {
1113 /* wait for next time the host buffer is empty */
1114 return 0;
1115 }
1116
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001117 cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
Tomas Winkler5db75142015-02-10 10:39:42 +02001118 cb->buf.size, cb->buf_idx);
Tomas Winkler21767542013-06-23 09:36:59 +03001119
Tomas Winkler136698e2013-09-16 23:44:44 +03001120 rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001121 if (rets) {
1122 cl->status = rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001123 list_move_tail(&cb->list, &cmpl_list->list);
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001124 return rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001125 }
1126
1127 cl->status = 0;
Tomas Winkler4dfaa9f2013-06-23 09:37:00 +03001128 cl->writing_state = MEI_WRITING;
Tomas Winkler21767542013-06-23 09:36:59 +03001129 cb->buf_idx += mei_hdr.length;
Tomas Winkler86601722015-02-10 10:39:40 +02001130 cb->completed = mei_hdr.msg_complete == 1;
Tomas Winkler4dfaa9f2013-06-23 09:37:00 +03001131
Tomas Winkler21767542013-06-23 09:36:59 +03001132 if (mei_hdr.msg_complete) {
1133 if (mei_cl_flow_ctrl_reduce(cl))
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001134 return -EIO;
Tomas Winkler21767542013-06-23 09:36:59 +03001135 list_move_tail(&cb->list, &dev->write_waiting_list.list);
1136 }
1137
1138 return 0;
1139}
1140
1141/**
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001142 * mei_cl_write - submit a write cb to mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001143 * assumes device_lock is locked
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001144 *
1145 * @cl: host client
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001146 * @cb: write callback with filled data
Alexander Usyskince231392014-09-29 16:31:50 +03001147 * @blocking: block until completed
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001148 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001149 * Return: number of bytes sent on success, <0 on failure.
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001150 */
1151int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
1152{
1153 struct mei_device *dev;
1154 struct mei_msg_data *buf;
1155 struct mei_msg_hdr mei_hdr;
1156 int rets;
1157
1158
1159 if (WARN_ON(!cl || !cl->dev))
1160 return -ENODEV;
1161
1162 if (WARN_ON(!cb))
1163 return -EINVAL;
1164
1165 dev = cl->dev;
1166
1167
Tomas Winkler5db75142015-02-10 10:39:42 +02001168 buf = &cb->buf;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001169
Alexander Usyskin0a01e972014-09-29 16:31:47 +03001170 cl_dbg(dev, cl, "size=%d\n", buf->size);
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001171
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001172 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001173 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001174 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001175 cl_err(dev, cl, "rpm: get failed %d\n", rets);
1176 return rets;
1177 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001178
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001179 cb->buf_idx = 0;
1180 cl->writing_state = MEI_IDLE;
1181
1182 mei_hdr.host_addr = cl->host_client_id;
1183 mei_hdr.me_addr = cl->me_client_id;
1184 mei_hdr.reserved = 0;
1185 mei_hdr.msg_complete = 0;
1186 mei_hdr.internal = cb->internal;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001187
1188 rets = mei_cl_flow_ctrl_creds(cl);
1189 if (rets < 0)
1190 goto err;
1191
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001192 if (rets == 0) {
1193 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001194 rets = buf->size;
1195 goto out;
1196 }
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001197 if (!mei_hbuf_acquire(dev)) {
1198 cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
1199 rets = buf->size;
1200 goto out;
1201 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001202
1203 /* Check for a maximum length */
1204 if (buf->size > mei_hbuf_max_len(dev)) {
1205 mei_hdr.length = mei_hbuf_max_len(dev);
1206 mei_hdr.msg_complete = 0;
1207 } else {
1208 mei_hdr.length = buf->size;
1209 mei_hdr.msg_complete = 1;
1210 }
1211
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001212 rets = mei_write_message(dev, &mei_hdr, buf->data);
1213 if (rets)
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001214 goto err;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001215
1216 cl->writing_state = MEI_WRITING;
1217 cb->buf_idx = mei_hdr.length;
Tomas Winkler86601722015-02-10 10:39:40 +02001218 cb->completed = mei_hdr.msg_complete == 1;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001219
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001220out:
1221 if (mei_hdr.msg_complete) {
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001222 rets = mei_cl_flow_ctrl_reduce(cl);
1223 if (rets < 0)
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001224 goto err;
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001225
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001226 list_add_tail(&cb->list, &dev->write_waiting_list.list);
1227 } else {
1228 list_add_tail(&cb->list, &dev->write_list.list);
1229 }
1230
1231
1232 if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
1233
1234 mutex_unlock(&dev->device_lock);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001235 rets = wait_event_interruptible(cl->tx_wait,
1236 cl->writing_state == MEI_WRITE_COMPLETE);
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001237 mutex_lock(&dev->device_lock);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001238 /* wait_event_interruptible returns -ERESTARTSYS */
1239 if (rets) {
1240 if (signal_pending(current))
1241 rets = -EINTR;
1242 goto err;
1243 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001244 }
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001245
1246 rets = buf->size;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001247err:
Tomas Winkler04bb1392014-03-18 22:52:04 +02001248 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001249 pm_runtime_mark_last_busy(dev->dev);
1250 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001251
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001252 return rets;
1253}
1254
1255
Tomas Winklerdb086fa2013-05-12 15:34:45 +03001256/**
1257 * mei_cl_complete - processes completed operation for a client
1258 *
1259 * @cl: private data of the file object.
1260 * @cb: callback block.
1261 */
1262void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
1263{
1264 if (cb->fop_type == MEI_FOP_WRITE) {
1265 mei_io_cb_free(cb);
1266 cb = NULL;
1267 cl->writing_state = MEI_WRITE_COMPLETE;
1268 if (waitqueue_active(&cl->tx_wait))
1269 wake_up_interruptible(&cl->tx_wait);
1270
1271 } else if (cb->fop_type == MEI_FOP_READ &&
1272 MEI_READING == cl->reading_state) {
1273 cl->reading_state = MEI_READ_COMPLETE;
1274 if (waitqueue_active(&cl->rx_wait))
1275 wake_up_interruptible(&cl->rx_wait);
1276 else
1277 mei_cl_bus_rx_event(cl);
1278
1279 }
1280}
1281
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001282
1283/**
Tomas Winkler074b4c02013-02-06 14:06:44 +02001284 * mei_cl_all_disconnect - disconnect forcefully all connected clients
1285 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001286 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001287 */
1288
1289void mei_cl_all_disconnect(struct mei_device *dev)
1290{
Tomas Winkler31f88f52014-02-17 15:13:25 +02001291 struct mei_cl *cl;
Tomas Winkler074b4c02013-02-06 14:06:44 +02001292
Tomas Winkler31f88f52014-02-17 15:13:25 +02001293 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winkler074b4c02013-02-06 14:06:44 +02001294 cl->state = MEI_FILE_DISCONNECTED;
1295 cl->mei_flow_ctrl_creds = 0;
Tomas Winkler074b4c02013-02-06 14:06:44 +02001296 cl->timer_count = 0;
1297 }
1298}
1299
1300
1301/**
Tomas Winkler52908012013-07-24 16:22:57 +03001302 * mei_cl_all_wakeup - wake up all readers and writers they can be interrupted
Tomas Winkler074b4c02013-02-06 14:06:44 +02001303 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001304 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001305 */
Tomas Winkler52908012013-07-24 16:22:57 +03001306void mei_cl_all_wakeup(struct mei_device *dev)
Tomas Winkler074b4c02013-02-06 14:06:44 +02001307{
Tomas Winkler31f88f52014-02-17 15:13:25 +02001308 struct mei_cl *cl;
Tomas Winkler92db1552014-09-29 16:31:37 +03001309
Tomas Winkler31f88f52014-02-17 15:13:25 +02001310 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winkler074b4c02013-02-06 14:06:44 +02001311 if (waitqueue_active(&cl->rx_wait)) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001312 cl_dbg(dev, cl, "Waking up reading client!\n");
Tomas Winkler074b4c02013-02-06 14:06:44 +02001313 wake_up_interruptible(&cl->rx_wait);
1314 }
Tomas Winkler52908012013-07-24 16:22:57 +03001315 if (waitqueue_active(&cl->tx_wait)) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001316 cl_dbg(dev, cl, "Waking up writing client!\n");
Tomas Winkler52908012013-07-24 16:22:57 +03001317 wake_up_interruptible(&cl->tx_wait);
1318 }
Tomas Winkler074b4c02013-02-06 14:06:44 +02001319 }
1320}
1321
1322/**
1323 * mei_cl_all_write_clear - clear all pending writes
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001324 *
1325 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001326 */
1327void mei_cl_all_write_clear(struct mei_device *dev)
1328{
Tomas Winklercc99ecf2014-03-10 15:10:40 +02001329 mei_io_list_free(&dev->write_list, NULL);
1330 mei_io_list_free(&dev->write_waiting_list, NULL);
Tomas Winkler074b4c02013-02-06 14:06:44 +02001331}
1332
1333