blob: e263c0713a6d5263fb8f6dcf4c8a7db0201fbc46 [file] [log] [blame]
Tomas Winkler9ca90502013-01-08 23:07:13 +02001/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2012, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
Tomas Winkler9ca90502013-01-08 23:07:13 +020017#include <linux/sched.h>
18#include <linux/wait.h>
19#include <linux/delay.h>
Tomas Winkler1f180352014-09-29 16:31:46 +030020#include <linux/slab.h>
Tomas Winkler04bb1392014-03-18 22:52:04 +020021#include <linux/pm_runtime.h>
Tomas Winkler9ca90502013-01-08 23:07:13 +020022
23#include <linux/mei.h>
24
25#include "mei_dev.h"
26#include "hbm.h"
Tomas Winkler90e0b5f12013-01-08 23:07:14 +020027#include "client.h"
28
29/**
Tomas Winkler79563db2015-01-11 00:07:16 +020030 * mei_me_cl_init - initialize me client
31 *
32 * @me_cl: me client
33 */
34void mei_me_cl_init(struct mei_me_client *me_cl)
35{
36 INIT_LIST_HEAD(&me_cl->list);
37 kref_init(&me_cl->refcnt);
38}
39
40/**
41 * mei_me_cl_get - increases me client refcount
42 *
43 * @me_cl: me client
44 *
45 * Locking: called under "dev->device_lock" lock
46 *
47 * Return: me client or NULL
48 */
49struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl)
50{
Tomas Winklerb7d88512015-02-10 10:39:31 +020051 if (me_cl && kref_get_unless_zero(&me_cl->refcnt))
52 return me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +020053
Tomas Winklerb7d88512015-02-10 10:39:31 +020054 return NULL;
Tomas Winkler79563db2015-01-11 00:07:16 +020055}
56
57/**
Tomas Winklerb7d88512015-02-10 10:39:31 +020058 * mei_me_cl_release - free me client
Tomas Winkler79563db2015-01-11 00:07:16 +020059 *
60 * Locking: called under "dev->device_lock" lock
61 *
62 * @ref: me_client refcount
63 */
64static void mei_me_cl_release(struct kref *ref)
65{
66 struct mei_me_client *me_cl =
67 container_of(ref, struct mei_me_client, refcnt);
Tomas Winklerb7d88512015-02-10 10:39:31 +020068
Tomas Winkler79563db2015-01-11 00:07:16 +020069 kfree(me_cl);
70}
Tomas Winklerb7d88512015-02-10 10:39:31 +020071
Tomas Winkler79563db2015-01-11 00:07:16 +020072/**
73 * mei_me_cl_put - decrease me client refcount and free client if necessary
74 *
75 * Locking: called under "dev->device_lock" lock
76 *
77 * @me_cl: me client
78 */
79void mei_me_cl_put(struct mei_me_client *me_cl)
80{
81 if (me_cl)
82 kref_put(&me_cl->refcnt, mei_me_cl_release);
83}
84
85/**
Tomas Winklerb7d88512015-02-10 10:39:31 +020086 * __mei_me_cl_del - delete me client form the list and decrease
87 * reference counter
88 *
89 * @dev: mei device
90 * @me_cl: me client
91 *
92 * Locking: dev->me_clients_rwsem
93 */
94static void __mei_me_cl_del(struct mei_device *dev, struct mei_me_client *me_cl)
95{
96 if (!me_cl)
97 return;
98
99 list_del(&me_cl->list);
100 mei_me_cl_put(me_cl);
101}
102
103/**
104 * mei_me_cl_add - add me client to the list
105 *
106 * @dev: mei device
107 * @me_cl: me client
108 */
109void mei_me_cl_add(struct mei_device *dev, struct mei_me_client *me_cl)
110{
111 down_write(&dev->me_clients_rwsem);
112 list_add(&me_cl->list, &dev->me_clients);
113 up_write(&dev->me_clients_rwsem);
114}
115
116/**
117 * __mei_me_cl_by_uuid - locate me client by uuid
118 * increases ref count
119 *
120 * @dev: mei device
121 * @uuid: me client uuid
122 *
123 * Return: me client or NULL if not found
124 *
125 * Locking: dev->me_clients_rwsem
126 */
127static struct mei_me_client *__mei_me_cl_by_uuid(struct mei_device *dev,
128 const uuid_le *uuid)
129{
130 struct mei_me_client *me_cl;
131 const uuid_le *pn;
132
133 WARN_ON(!rwsem_is_locked(&dev->me_clients_rwsem));
134
135 list_for_each_entry(me_cl, &dev->me_clients, list) {
136 pn = &me_cl->props.protocol_name;
137 if (uuid_le_cmp(*uuid, *pn) == 0)
138 return mei_me_cl_get(me_cl);
139 }
140
141 return NULL;
142}
143
144/**
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300145 * mei_me_cl_by_uuid - locate me client by uuid
Tomas Winkler79563db2015-01-11 00:07:16 +0200146 * increases ref count
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200147 *
148 * @dev: mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300149 * @uuid: me client uuid
Alexander Usyskina27a76d2014-02-17 15:13:22 +0200150 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300151 * Return: me client or NULL if not found
Tomas Winklerb7d88512015-02-10 10:39:31 +0200152 *
153 * Locking: dev->me_clients_rwsem
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200154 */
Tomas Winklerb7d88512015-02-10 10:39:31 +0200155struct mei_me_client *mei_me_cl_by_uuid(struct mei_device *dev,
Tomas Winklerd3208322014-08-24 12:08:55 +0300156 const uuid_le *uuid)
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200157{
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300158 struct mei_me_client *me_cl;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200159
Tomas Winklerb7d88512015-02-10 10:39:31 +0200160 down_read(&dev->me_clients_rwsem);
161 me_cl = __mei_me_cl_by_uuid(dev, uuid);
162 up_read(&dev->me_clients_rwsem);
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200163
Tomas Winklerb7d88512015-02-10 10:39:31 +0200164 return me_cl;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200165}
166
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200167/**
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300168 * mei_me_cl_by_id - locate me client by client id
Tomas Winkler79563db2015-01-11 00:07:16 +0200169 * increases ref count
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200170 *
171 * @dev: the device structure
172 * @client_id: me client id
173 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300174 * Return: me client or NULL if not found
Tomas Winklerb7d88512015-02-10 10:39:31 +0200175 *
176 * Locking: dev->me_clients_rwsem
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200177 */
Tomas Winklerd3208322014-08-24 12:08:55 +0300178struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200179{
Alexander Usyskina27a76d2014-02-17 15:13:22 +0200180
Tomas Winklerb7d88512015-02-10 10:39:31 +0200181 struct mei_me_client *__me_cl, *me_cl = NULL;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200182
Tomas Winklerb7d88512015-02-10 10:39:31 +0200183 down_read(&dev->me_clients_rwsem);
184 list_for_each_entry(__me_cl, &dev->me_clients, list) {
185 if (__me_cl->client_id == client_id) {
186 me_cl = mei_me_cl_get(__me_cl);
187 break;
188 }
189 }
190 up_read(&dev->me_clients_rwsem);
191
192 return me_cl;
193}
194
195/**
196 * __mei_me_cl_by_uuid_id - locate me client by client id and uuid
197 * increases ref count
198 *
199 * @dev: the device structure
200 * @uuid: me client uuid
201 * @client_id: me client id
202 *
203 * Return: me client or null if not found
204 *
205 * Locking: dev->me_clients_rwsem
206 */
207static struct mei_me_client *__mei_me_cl_by_uuid_id(struct mei_device *dev,
208 const uuid_le *uuid, u8 client_id)
209{
210 struct mei_me_client *me_cl;
211 const uuid_le *pn;
212
213 WARN_ON(!rwsem_is_locked(&dev->me_clients_rwsem));
214
215 list_for_each_entry(me_cl, &dev->me_clients, list) {
216 pn = &me_cl->props.protocol_name;
217 if (uuid_le_cmp(*uuid, *pn) == 0 &&
218 me_cl->client_id == client_id)
Tomas Winkler79563db2015-01-11 00:07:16 +0200219 return mei_me_cl_get(me_cl);
Tomas Winklerb7d88512015-02-10 10:39:31 +0200220 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200221
Tomas Winklerd3208322014-08-24 12:08:55 +0300222 return NULL;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200223}
Tomas Winkler9ca90502013-01-08 23:07:13 +0200224
Tomas Winklerb7d88512015-02-10 10:39:31 +0200225
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300226/**
227 * mei_me_cl_by_uuid_id - locate me client by client id and uuid
Tomas Winkler79563db2015-01-11 00:07:16 +0200228 * increases ref count
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300229 *
230 * @dev: the device structure
231 * @uuid: me client uuid
232 * @client_id: me client id
233 *
Tomas Winklerb7d88512015-02-10 10:39:31 +0200234 * Return: me client or null if not found
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300235 */
Tomas Winklerd880f322014-08-21 14:29:15 +0300236struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
237 const uuid_le *uuid, u8 client_id)
238{
239 struct mei_me_client *me_cl;
240
Tomas Winklerb7d88512015-02-10 10:39:31 +0200241 down_read(&dev->me_clients_rwsem);
242 me_cl = __mei_me_cl_by_uuid_id(dev, uuid, client_id);
243 up_read(&dev->me_clients_rwsem);
Tomas Winkler79563db2015-01-11 00:07:16 +0200244
Tomas Winklerb7d88512015-02-10 10:39:31 +0200245 return me_cl;
Tomas Winklerd880f322014-08-21 14:29:15 +0300246}
247
Tomas Winkler25ca6472014-08-21 14:29:14 +0300248/**
Tomas Winkler79563db2015-01-11 00:07:16 +0200249 * mei_me_cl_rm_by_uuid - remove all me clients matching uuid
Tomas Winkler25ca6472014-08-21 14:29:14 +0300250 *
251 * @dev: the device structure
252 * @uuid: me client uuid
Tomas Winkler79563db2015-01-11 00:07:16 +0200253 *
254 * Locking: called under "dev->device_lock" lock
Tomas Winkler25ca6472014-08-21 14:29:14 +0300255 */
Tomas Winkler79563db2015-01-11 00:07:16 +0200256void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid)
Tomas Winkler25ca6472014-08-21 14:29:14 +0300257{
Tomas Winklerb7d88512015-02-10 10:39:31 +0200258 struct mei_me_client *me_cl;
Tomas Winkler25ca6472014-08-21 14:29:14 +0300259
Tomas Winkler79563db2015-01-11 00:07:16 +0200260 dev_dbg(dev->dev, "remove %pUl\n", uuid);
Tomas Winklerb7d88512015-02-10 10:39:31 +0200261
262 down_write(&dev->me_clients_rwsem);
263 me_cl = __mei_me_cl_by_uuid(dev, uuid);
264 __mei_me_cl_del(dev, me_cl);
265 up_write(&dev->me_clients_rwsem);
Tomas Winkler79563db2015-01-11 00:07:16 +0200266}
267
268/**
269 * mei_me_cl_rm_by_uuid_id - remove all me clients matching client id
270 *
271 * @dev: the device structure
272 * @uuid: me client uuid
273 * @id: me client id
274 *
275 * Locking: called under "dev->device_lock" lock
276 */
277void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 id)
278{
Tomas Winklerb7d88512015-02-10 10:39:31 +0200279 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200280
281 dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id);
Tomas Winklerb7d88512015-02-10 10:39:31 +0200282
283 down_write(&dev->me_clients_rwsem);
284 me_cl = __mei_me_cl_by_uuid_id(dev, uuid, id);
285 __mei_me_cl_del(dev, me_cl);
286 up_write(&dev->me_clients_rwsem);
Tomas Winkler25ca6472014-08-21 14:29:14 +0300287}
288
Tomas Winkler79563db2015-01-11 00:07:16 +0200289/**
290 * mei_me_cl_rm_all - remove all me clients
291 *
292 * @dev: the device structure
293 *
294 * Locking: called under "dev->device_lock" lock
295 */
296void mei_me_cl_rm_all(struct mei_device *dev)
297{
298 struct mei_me_client *me_cl, *next;
299
Tomas Winklerb7d88512015-02-10 10:39:31 +0200300 down_write(&dev->me_clients_rwsem);
Tomas Winkler79563db2015-01-11 00:07:16 +0200301 list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
Tomas Winklerb7d88512015-02-10 10:39:31 +0200302 __mei_me_cl_del(dev, me_cl);
303 up_write(&dev->me_clients_rwsem);
Tomas Winkler79563db2015-01-11 00:07:16 +0200304}
305
Tomas Winkler9ca90502013-01-08 23:07:13 +0200306/**
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200307 * mei_cl_cmp_id - tells if the clients are the same
308 *
309 * @cl1: host client 1
310 * @cl2: host client 2
311 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300312 * Return: true - if the clients has same host and me ids
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200313 * false - otherwise
314 */
315static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
316 const struct mei_cl *cl2)
317{
318 return cl1 && cl2 &&
319 (cl1->host_client_id == cl2->host_client_id) &&
320 (cl1->me_client_id == cl2->me_client_id);
321}
322
323/**
Alexander Usyskin3908be62015-02-10 10:39:35 +0200324 * __mei_io_list_flush - removes and frees cbs belonging to cl.
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200325 *
326 * @list: an instance of our list structure
327 * @cl: host client, can be NULL for flushing the whole list
328 * @free: whether to free the cbs
329 */
330static void __mei_io_list_flush(struct mei_cl_cb *list,
331 struct mei_cl *cl, bool free)
332{
333 struct mei_cl_cb *cb;
334 struct mei_cl_cb *next;
335
336 /* enable removing everything if no cl is specified */
337 list_for_each_entry_safe(cb, next, &list->list, list) {
Alexander Usyskin140c7552014-10-02 13:39:31 +0300338 if (!cl || mei_cl_cmp_id(cl, cb->cl)) {
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200339 list_del(&cb->list);
340 if (free)
341 mei_io_cb_free(cb);
342 }
343 }
344}
345
346/**
Tomas Winkler9ca90502013-01-08 23:07:13 +0200347 * mei_io_list_flush - removes list entry belonging to cl.
348 *
349 * @list: An instance of our list structure
350 * @cl: host client
351 */
Alexander Usyskin54567962014-08-14 17:22:20 +0300352void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200353{
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200354 __mei_io_list_flush(list, cl, false);
355}
Tomas Winkler9ca90502013-01-08 23:07:13 +0200356
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200357
358/**
359 * mei_io_list_free - removes cb belonging to cl and free them
360 *
361 * @list: An instance of our list structure
362 * @cl: host client
363 */
364static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
365{
366 __mei_io_list_flush(list, cl, true);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200367}
368
369/**
370 * mei_io_cb_free - free mei_cb_private related memory
371 *
372 * @cb: mei callback struct
373 */
374void mei_io_cb_free(struct mei_cl_cb *cb)
375{
376 if (cb == NULL)
377 return;
378
Tomas Winkler5db75142015-02-10 10:39:42 +0200379 kfree(cb->buf.data);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200380 kfree(cb);
381}
382
383/**
384 * mei_io_cb_init - allocate and initialize io callback
385 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300386 * @cl: mei client
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 Winkler90e0b5f12013-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 Winkler90e0b5f12013-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 Winkler90e0b5f12013-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 Winkler90e0b5f12013-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 Winkler90e0b5f12013-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
Tomas Winkler03b8d342015-02-10 10:39:44 +0200550 * @id: fixed host id or MEI_HOST_CLIENT_ID_ANY (-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
Tomas Winkler03b8d342015-02-10 10:39:44 +0200554 * -EMFILE if open count exceeded.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200555 */
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 Winkler90e0b5f12013-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 Winkler90e0b5f12013-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 Winkler90e0b5f12013-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 Winkler90e0b5f12013-01-08 23:07:14 +0200603int mei_cl_unlink(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200604{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200605 struct mei_device *dev;
Tomas Winkler90e0b5f12013-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 Winkler90e0b5f12013-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 Winkler90e0b5f12013-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 Winkler90e0b5f12013-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 Winkler90e0b5f12013-01-08 23:07:14 +0200698int mei_cl_disconnect(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200699{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200700 struct mei_device *dev;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200701 struct mei_cl_cb *cb;
Alexander Usyskinfe2f17e2014-07-17 10:53:38 +0300702 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200703
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200704 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200705 return -ENODEV;
706
Tomas Winkler90e0b5f12013-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 Usyskinfe2f17e2014-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 Usyskinfe2f17e2014-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 Winkler90e0b5f12013-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 Winkler90e0b5f12013-01-08 23:07:14 +0200776bool mei_cl_is_other_connecting(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200777{
Tomas Winkler90e0b5f12013-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 Winkler90e0b5f12013-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 Winkler90e0b5f12013-01-08 23:07:14 +0200790 return true;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200791
792 }
Tomas Winkler90e0b5f12013-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 Winkler03b8d342015-02-10 10:39:44 +0200873 * mei_cl_alloc_linked - allocate and link host client
874 *
875 * @dev: the device structure
876 * @id: fixed host id or MEI_HOST_CLIENT_ID_ANY (-1) for generic one
877 *
878 * Return: cl on success ERR_PTR on failure
879 */
880struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id)
881{
882 struct mei_cl *cl;
883 int ret;
884
885 cl = mei_cl_allocate(dev);
886 if (!cl) {
887 ret = -ENOMEM;
888 goto err;
889 }
890
891 ret = mei_cl_link(cl, id);
892 if (ret)
893 goto err;
894
895 return cl;
896err:
897 kfree(cl);
898 return ERR_PTR(ret);
899}
900
901
902
903/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200904 * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200905 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200906 * @cl: private data of the file object
907 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300908 * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200909 * -ENOENT if mei_cl is not present
910 * -EINVAL if single_recv_buf == 0
911 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200912int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200913{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200914 struct mei_device *dev;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200915 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200916 int rets = 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200917
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200918 if (WARN_ON(!cl || !cl->dev))
919 return -EINVAL;
920
921 dev = cl->dev;
922
Tomas Winkler9ca90502013-01-08 23:07:13 +0200923 if (cl->mei_flow_ctrl_creds > 0)
924 return 1;
925
Tomas Winkler2e5df412014-12-07 16:40:14 +0200926 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300927 if (!me_cl) {
Alexander Usyskin12d00662014-02-17 15:13:23 +0200928 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300929 return -ENOENT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200930 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200931
Tomas Winkler79563db2015-01-11 00:07:16 +0200932 if (me_cl->mei_flow_ctrl_creds > 0) {
933 rets = 1;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200934 if (WARN_ON(me_cl->props.single_recv_buf == 0))
Tomas Winkler79563db2015-01-11 00:07:16 +0200935 rets = -EINVAL;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200936 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200937 mei_me_cl_put(me_cl);
938 return rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200939}
940
941/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200942 * mei_cl_flow_ctrl_reduce - reduces flow_control.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200943 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200944 * @cl: private data of the file object
Masanari Iida393b1482013-04-05 01:05:05 +0900945 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300946 * Return:
Tomas Winkler9ca90502013-01-08 23:07:13 +0200947 * 0 on success
948 * -ENOENT when me client is not found
949 * -EINVAL when ctrl credits are <= 0
950 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200951int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200952{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200953 struct mei_device *dev;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200954 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200955 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200956
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200957 if (WARN_ON(!cl || !cl->dev))
958 return -EINVAL;
959
960 dev = cl->dev;
961
Tomas Winkler2e5df412014-12-07 16:40:14 +0200962 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300963 if (!me_cl) {
Alexander Usyskin12d00662014-02-17 15:13:23 +0200964 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300965 return -ENOENT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200966 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200967
Tomas Winklerd3208322014-08-24 12:08:55 +0300968 if (me_cl->props.single_recv_buf) {
Tomas Winkler79563db2015-01-11 00:07:16 +0200969 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
970 rets = -EINVAL;
971 goto out;
972 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200973 me_cl->mei_flow_ctrl_creds--;
974 } else {
Tomas Winkler79563db2015-01-11 00:07:16 +0200975 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
976 rets = -EINVAL;
977 goto out;
978 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200979 cl->mei_flow_ctrl_creds--;
980 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200981 rets = 0;
982out:
983 mei_me_cl_put(me_cl);
984 return rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200985}
986
Tomas Winkler9ca90502013-01-08 23:07:13 +0200987/**
Masanari Iida393b1482013-04-05 01:05:05 +0900988 * mei_cl_read_start - the start read client message function.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200989 *
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200990 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300991 * @length: number of bytes to read
Tomas Winklerbca67d62015-02-10 10:39:43 +0200992 * @fp: pointer to file structure
Tomas Winkler9ca90502013-01-08 23:07:13 +0200993 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300994 * Return: 0 on success, <0 on failure.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200995 */
Tomas Winklerbca67d62015-02-10 10:39:43 +0200996int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200997{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200998 struct mei_device *dev;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200999 struct mei_cl_cb *cb;
Tomas Winklerd3208322014-08-24 12:08:55 +03001000 struct mei_me_client *me_cl;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001001 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001002
Tomas Winkler90e0b5f12013-01-08 23:07:14 +02001003 if (WARN_ON(!cl || !cl->dev))
1004 return -ENODEV;
1005
1006 dev = cl->dev;
1007
Tomas Winklerb950ac12013-07-25 20:15:53 +03001008 if (!mei_cl_is_connected(cl))
Tomas Winkler9ca90502013-01-08 23:07:13 +02001009 return -ENODEV;
1010
Tomas Winklerd91aaed2013-01-08 23:07:18 +02001011 if (cl->read_cb) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001012 cl_dbg(dev, cl, "read is pending.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +02001013 return -EBUSY;
1014 }
Tomas Winklerd880f322014-08-21 14:29:15 +03001015 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +03001016 if (!me_cl) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001017 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001018 return -ENOTTY;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001019 }
Tomas Winkler79563db2015-01-11 00:07:16 +02001020 /* always allocate at least client max message */
1021 length = max_t(size_t, length, me_cl->props.max_msg_length);
1022 mei_me_cl_put(me_cl);
Tomas Winkler9ca90502013-01-08 23:07:13 +02001023
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001024 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001025 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001026 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001027 cl_err(dev, cl, "rpm: get failed %d\n", rets);
1028 return rets;
1029 }
1030
Tomas Winklerbca67d62015-02-10 10:39:43 +02001031 cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp);
1032 rets = cb ? 0 : -ENOMEM;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001033 if (rets)
Tomas Winkler04bb1392014-03-18 22:52:04 +02001034 goto out;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001035
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001036 if (mei_hbuf_acquire(dev)) {
Alexander Usyskin86113502014-03-31 17:59:24 +03001037 rets = mei_hbm_cl_flow_control_req(dev, cl);
1038 if (rets < 0)
Tomas Winkler04bb1392014-03-18 22:52:04 +02001039 goto out;
Tomas Winkler04bb1392014-03-18 22:52:04 +02001040
Tomas Winkler9ca90502013-01-08 23:07:13 +02001041 list_add_tail(&cb->list, &dev->read_list.list);
1042 } else {
1043 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
1044 }
Chao Biaccb8842014-02-12 21:27:25 +02001045
1046 cl->read_cb = cb;
1047
Tomas Winkler04bb1392014-03-18 22:52:04 +02001048out:
1049 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001050 pm_runtime_mark_last_busy(dev->dev);
1051 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001052
1053 if (rets)
1054 mei_io_cb_free(cb);
1055
Tomas Winkler9ca90502013-01-08 23:07:13 +02001056 return rets;
1057}
1058
Tomas Winkler074b4c02013-02-06 14:06:44 +02001059/**
Tomas Winkler9d098192014-02-19 17:35:48 +02001060 * mei_cl_irq_write - write a message to device
Tomas Winkler21767542013-06-23 09:36:59 +03001061 * from the interrupt thread context
1062 *
1063 * @cl: client
1064 * @cb: callback block.
Tomas Winkler21767542013-06-23 09:36:59 +03001065 * @cmpl_list: complete list.
1066 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001067 * Return: 0, OK; otherwise error.
Tomas Winkler21767542013-06-23 09:36:59 +03001068 */
Tomas Winkler9d098192014-02-19 17:35:48 +02001069int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
1070 struct mei_cl_cb *cmpl_list)
Tomas Winkler21767542013-06-23 09:36:59 +03001071{
Tomas Winkler136698e2013-09-16 23:44:44 +03001072 struct mei_device *dev;
1073 struct mei_msg_data *buf;
Tomas Winkler21767542013-06-23 09:36:59 +03001074 struct mei_msg_hdr mei_hdr;
Tomas Winkler136698e2013-09-16 23:44:44 +03001075 size_t len;
1076 u32 msg_slots;
Tomas Winkler9d098192014-02-19 17:35:48 +02001077 int slots;
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001078 int rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001079
Tomas Winkler136698e2013-09-16 23:44:44 +03001080 if (WARN_ON(!cl || !cl->dev))
1081 return -ENODEV;
1082
1083 dev = cl->dev;
1084
Tomas Winkler5db75142015-02-10 10:39:42 +02001085 buf = &cb->buf;
Tomas Winkler136698e2013-09-16 23:44:44 +03001086
1087 rets = mei_cl_flow_ctrl_creds(cl);
1088 if (rets < 0)
1089 return rets;
1090
1091 if (rets == 0) {
Tomas Winkler04bb1392014-03-18 22:52:04 +02001092 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
Tomas Winkler136698e2013-09-16 23:44:44 +03001093 return 0;
1094 }
1095
Tomas Winkler9d098192014-02-19 17:35:48 +02001096 slots = mei_hbuf_empty_slots(dev);
Tomas Winkler136698e2013-09-16 23:44:44 +03001097 len = buf->size - cb->buf_idx;
1098 msg_slots = mei_data2slots(len);
1099
Tomas Winkler21767542013-06-23 09:36:59 +03001100 mei_hdr.host_addr = cl->host_client_id;
1101 mei_hdr.me_addr = cl->me_client_id;
1102 mei_hdr.reserved = 0;
Tomas Winkler479327f2013-12-17 15:56:56 +02001103 mei_hdr.internal = cb->internal;
Tomas Winkler21767542013-06-23 09:36:59 +03001104
Tomas Winkler9d098192014-02-19 17:35:48 +02001105 if (slots >= msg_slots) {
Tomas Winkler21767542013-06-23 09:36:59 +03001106 mei_hdr.length = len;
1107 mei_hdr.msg_complete = 1;
1108 /* Split the message only if we can write the whole host buffer */
Tomas Winkler9d098192014-02-19 17:35:48 +02001109 } else if (slots == dev->hbuf_depth) {
1110 msg_slots = slots;
1111 len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
Tomas Winkler21767542013-06-23 09:36:59 +03001112 mei_hdr.length = len;
1113 mei_hdr.msg_complete = 0;
1114 } else {
1115 /* wait for next time the host buffer is empty */
1116 return 0;
1117 }
1118
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001119 cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
Tomas Winkler5db75142015-02-10 10:39:42 +02001120 cb->buf.size, cb->buf_idx);
Tomas Winkler21767542013-06-23 09:36:59 +03001121
Tomas Winkler136698e2013-09-16 23:44:44 +03001122 rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001123 if (rets) {
1124 cl->status = rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001125 list_move_tail(&cb->list, &cmpl_list->list);
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001126 return rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001127 }
1128
1129 cl->status = 0;
Tomas Winkler4dfaa9f2013-06-23 09:37:00 +03001130 cl->writing_state = MEI_WRITING;
Tomas Winkler21767542013-06-23 09:36:59 +03001131 cb->buf_idx += mei_hdr.length;
Tomas Winkler86601722015-02-10 10:39:40 +02001132 cb->completed = mei_hdr.msg_complete == 1;
Tomas Winkler4dfaa9f2013-06-23 09:37:00 +03001133
Tomas Winkler21767542013-06-23 09:36:59 +03001134 if (mei_hdr.msg_complete) {
1135 if (mei_cl_flow_ctrl_reduce(cl))
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001136 return -EIO;
Tomas Winkler21767542013-06-23 09:36:59 +03001137 list_move_tail(&cb->list, &dev->write_waiting_list.list);
1138 }
1139
1140 return 0;
1141}
1142
1143/**
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001144 * mei_cl_write - submit a write cb to mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001145 * assumes device_lock is locked
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001146 *
1147 * @cl: host client
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001148 * @cb: write callback with filled data
Alexander Usyskince231392014-09-29 16:31:50 +03001149 * @blocking: block until completed
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001150 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001151 * Return: number of bytes sent on success, <0 on failure.
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001152 */
1153int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
1154{
1155 struct mei_device *dev;
1156 struct mei_msg_data *buf;
1157 struct mei_msg_hdr mei_hdr;
1158 int rets;
1159
1160
1161 if (WARN_ON(!cl || !cl->dev))
1162 return -ENODEV;
1163
1164 if (WARN_ON(!cb))
1165 return -EINVAL;
1166
1167 dev = cl->dev;
1168
1169
Tomas Winkler5db75142015-02-10 10:39:42 +02001170 buf = &cb->buf;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001171
Alexander Usyskin0a01e972014-09-29 16:31:47 +03001172 cl_dbg(dev, cl, "size=%d\n", buf->size);
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001173
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001174 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001175 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001176 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001177 cl_err(dev, cl, "rpm: get failed %d\n", rets);
1178 return rets;
1179 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001180
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001181 cb->buf_idx = 0;
1182 cl->writing_state = MEI_IDLE;
1183
1184 mei_hdr.host_addr = cl->host_client_id;
1185 mei_hdr.me_addr = cl->me_client_id;
1186 mei_hdr.reserved = 0;
1187 mei_hdr.msg_complete = 0;
1188 mei_hdr.internal = cb->internal;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001189
1190 rets = mei_cl_flow_ctrl_creds(cl);
1191 if (rets < 0)
1192 goto err;
1193
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001194 if (rets == 0) {
1195 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001196 rets = buf->size;
1197 goto out;
1198 }
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001199 if (!mei_hbuf_acquire(dev)) {
1200 cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
1201 rets = buf->size;
1202 goto out;
1203 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001204
1205 /* Check for a maximum length */
1206 if (buf->size > mei_hbuf_max_len(dev)) {
1207 mei_hdr.length = mei_hbuf_max_len(dev);
1208 mei_hdr.msg_complete = 0;
1209 } else {
1210 mei_hdr.length = buf->size;
1211 mei_hdr.msg_complete = 1;
1212 }
1213
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001214 rets = mei_write_message(dev, &mei_hdr, buf->data);
1215 if (rets)
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001216 goto err;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001217
1218 cl->writing_state = MEI_WRITING;
1219 cb->buf_idx = mei_hdr.length;
Tomas Winkler86601722015-02-10 10:39:40 +02001220 cb->completed = mei_hdr.msg_complete == 1;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001221
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001222out:
1223 if (mei_hdr.msg_complete) {
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001224 rets = mei_cl_flow_ctrl_reduce(cl);
1225 if (rets < 0)
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001226 goto err;
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001227
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001228 list_add_tail(&cb->list, &dev->write_waiting_list.list);
1229 } else {
1230 list_add_tail(&cb->list, &dev->write_list.list);
1231 }
1232
1233
1234 if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
1235
1236 mutex_unlock(&dev->device_lock);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001237 rets = wait_event_interruptible(cl->tx_wait,
1238 cl->writing_state == MEI_WRITE_COMPLETE);
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001239 mutex_lock(&dev->device_lock);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001240 /* wait_event_interruptible returns -ERESTARTSYS */
1241 if (rets) {
1242 if (signal_pending(current))
1243 rets = -EINTR;
1244 goto err;
1245 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001246 }
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001247
1248 rets = buf->size;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001249err:
Tomas Winkler04bb1392014-03-18 22:52:04 +02001250 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001251 pm_runtime_mark_last_busy(dev->dev);
1252 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001253
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001254 return rets;
1255}
1256
1257
Tomas Winklerdb086fa2013-05-12 15:34:45 +03001258/**
1259 * mei_cl_complete - processes completed operation for a client
1260 *
1261 * @cl: private data of the file object.
1262 * @cb: callback block.
1263 */
1264void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
1265{
1266 if (cb->fop_type == MEI_FOP_WRITE) {
1267 mei_io_cb_free(cb);
1268 cb = NULL;
1269 cl->writing_state = MEI_WRITE_COMPLETE;
1270 if (waitqueue_active(&cl->tx_wait))
1271 wake_up_interruptible(&cl->tx_wait);
1272
1273 } else if (cb->fop_type == MEI_FOP_READ &&
1274 MEI_READING == cl->reading_state) {
1275 cl->reading_state = MEI_READ_COMPLETE;
1276 if (waitqueue_active(&cl->rx_wait))
1277 wake_up_interruptible(&cl->rx_wait);
1278 else
1279 mei_cl_bus_rx_event(cl);
1280
1281 }
1282}
1283
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001284
1285/**
Tomas Winkler074b4c02013-02-06 14:06:44 +02001286 * mei_cl_all_disconnect - disconnect forcefully all connected clients
1287 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001288 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001289 */
1290
1291void mei_cl_all_disconnect(struct mei_device *dev)
1292{
Tomas Winkler31f88f52014-02-17 15:13:25 +02001293 struct mei_cl *cl;
Tomas Winkler074b4c02013-02-06 14:06:44 +02001294
Tomas Winkler31f88f52014-02-17 15:13:25 +02001295 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winkler074b4c02013-02-06 14:06:44 +02001296 cl->state = MEI_FILE_DISCONNECTED;
1297 cl->mei_flow_ctrl_creds = 0;
Tomas Winkler074b4c02013-02-06 14:06:44 +02001298 cl->timer_count = 0;
1299 }
1300}
1301
1302
1303/**
Tomas Winkler52908012013-07-24 16:22:57 +03001304 * mei_cl_all_wakeup - wake up all readers and writers they can be interrupted
Tomas Winkler074b4c02013-02-06 14:06:44 +02001305 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001306 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001307 */
Tomas Winkler52908012013-07-24 16:22:57 +03001308void mei_cl_all_wakeup(struct mei_device *dev)
Tomas Winkler074b4c02013-02-06 14:06:44 +02001309{
Tomas Winkler31f88f52014-02-17 15:13:25 +02001310 struct mei_cl *cl;
Tomas Winkler92db1552014-09-29 16:31:37 +03001311
Tomas Winkler31f88f52014-02-17 15:13:25 +02001312 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winkler074b4c02013-02-06 14:06:44 +02001313 if (waitqueue_active(&cl->rx_wait)) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001314 cl_dbg(dev, cl, "Waking up reading client!\n");
Tomas Winkler074b4c02013-02-06 14:06:44 +02001315 wake_up_interruptible(&cl->rx_wait);
1316 }
Tomas Winkler52908012013-07-24 16:22:57 +03001317 if (waitqueue_active(&cl->tx_wait)) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001318 cl_dbg(dev, cl, "Waking up writing client!\n");
Tomas Winkler52908012013-07-24 16:22:57 +03001319 wake_up_interruptible(&cl->tx_wait);
1320 }
Tomas Winkler074b4c02013-02-06 14:06:44 +02001321 }
1322}
1323
1324/**
1325 * mei_cl_all_write_clear - clear all pending writes
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001326 *
1327 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001328 */
1329void mei_cl_all_write_clear(struct mei_device *dev)
1330{
Tomas Winklercc99ecf2014-03-10 15:10:40 +02001331 mei_io_list_free(&dev->write_list, NULL);
1332 mei_io_list_free(&dev->write_waiting_list, NULL);
Tomas Winkler074b4c02013-02-06 14:06:44 +02001333}
1334
1335