blob: 98a5363e1e8a18cd863aaf13af6ec8ad8fff9b30 [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 Winklera9bed612015-02-10 10:39:46 +0200461 * mei_cl_read_cb - find this cl's callback in the read list
462 * for a specific file
463 *
464 * @cl: host client
465 * @fp: file pointer (matching cb file object), may be NULL
466 *
467 * Return: cb on success, NULL if cb is not found
468 */
469struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, const struct file *fp)
470{
471 struct mei_cl_cb *cb;
472
473 list_for_each_entry(cb, &cl->rd_completed, list)
474 if (!fp || fp == cb->file_object)
475 return cb;
476
477 return NULL;
478}
479
480/**
481 * mei_cl_read_cb_flush - free client's read pending and completed cbs
482 * for a specific file
483 *
484 * @cl: host client
485 * @fp: file pointer (matching cb file object), may be NULL
486 */
487void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp)
488{
489 struct mei_cl_cb *cb, *next;
490
491 list_for_each_entry_safe(cb, next, &cl->rd_completed, list)
492 if (!fp || fp == cb->file_object)
493 mei_io_cb_free(cb);
494
495
496 list_for_each_entry_safe(cb, next, &cl->rd_pending, list)
497 if (!fp || fp == cb->file_object)
498 mei_io_cb_free(cb);
499}
500
501/**
Tomas Winkler9ca90502013-01-08 23:07:13 +0200502 * mei_cl_flush_queues - flushes queue lists belonging to cl.
503 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200504 * @cl: host client
Tomas Winklera9bed612015-02-10 10:39:46 +0200505 * @fp: file pointer (matching cb file object), may be NULL
Alexander Usyskince231392014-09-29 16:31:50 +0300506 *
507 * Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200508 */
Tomas Winklera9bed612015-02-10 10:39:46 +0200509int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200510{
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300511 struct mei_device *dev;
512
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200513 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200514 return -EINVAL;
515
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300516 dev = cl->dev;
517
518 cl_dbg(dev, cl, "remove list entry belonging to cl\n");
Tomas Winklercc99ecf2014-03-10 15:10:40 +0200519 mei_io_list_free(&cl->dev->write_list, cl);
520 mei_io_list_free(&cl->dev->write_waiting_list, cl);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200521 mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
522 mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
523 mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
524 mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
Tomas Winklera9bed612015-02-10 10:39:46 +0200525
526 mei_cl_read_cb_flush(cl, fp);
527
Tomas Winkler9ca90502013-01-08 23:07:13 +0200528 return 0;
529}
530
Tomas Winkler9ca90502013-01-08 23:07:13 +0200531
532/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200533 * mei_cl_init - initializes cl.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200534 *
535 * @cl: host client to be initialized
536 * @dev: mei device
537 */
538void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
539{
540 memset(cl, 0, sizeof(struct mei_cl));
541 init_waitqueue_head(&cl->wait);
542 init_waitqueue_head(&cl->rx_wait);
543 init_waitqueue_head(&cl->tx_wait);
Tomas Winklera9bed612015-02-10 10:39:46 +0200544 INIT_LIST_HEAD(&cl->rd_completed);
545 INIT_LIST_HEAD(&cl->rd_pending);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200546 INIT_LIST_HEAD(&cl->link);
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200547 INIT_LIST_HEAD(&cl->device_link);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200548 cl->writing_state = MEI_IDLE;
549 cl->dev = dev;
550}
551
552/**
553 * mei_cl_allocate - allocates cl structure and sets it up.
554 *
555 * @dev: mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300556 * Return: The allocated file or NULL on failure
Tomas Winkler9ca90502013-01-08 23:07:13 +0200557 */
558struct mei_cl *mei_cl_allocate(struct mei_device *dev)
559{
560 struct mei_cl *cl;
561
562 cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
563 if (!cl)
564 return NULL;
565
566 mei_cl_init(cl, dev);
567
568 return cl;
569}
570
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200571/**
Alexander Usyskin3908be62015-02-10 10:39:35 +0200572 * mei_cl_link - allocate host id in the host map
Tomas Winkler9ca90502013-01-08 23:07:13 +0200573 *
Alexander Usyskin3908be62015-02-10 10:39:35 +0200574 * @cl: host client
Tomas Winkler03b8d342015-02-10 10:39:44 +0200575 * @id: fixed host id or MEI_HOST_CLIENT_ID_ANY (-1) for generic one
Masanari Iida393b1482013-04-05 01:05:05 +0900576 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300577 * Return: 0 on success
Tomas Winkler9ca90502013-01-08 23:07:13 +0200578 * -EINVAL on incorrect values
Tomas Winkler03b8d342015-02-10 10:39:44 +0200579 * -EMFILE if open count exceeded.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200580 */
Tomas Winkler781d0d82013-01-08 23:07:22 +0200581int mei_cl_link(struct mei_cl *cl, int id)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200582{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200583 struct mei_device *dev;
Tomas Winkler22f96a02013-09-16 23:44:47 +0300584 long open_handle_count;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200585
Tomas Winkler781d0d82013-01-08 23:07:22 +0200586 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200587 return -EINVAL;
588
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200589 dev = cl->dev;
590
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200591 /* If Id is not assigned get one*/
Tomas Winkler781d0d82013-01-08 23:07:22 +0200592 if (id == MEI_HOST_CLIENT_ID_ANY)
593 id = find_first_zero_bit(dev->host_clients_map,
594 MEI_CLIENTS_MAX);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200595
Tomas Winkler781d0d82013-01-08 23:07:22 +0200596 if (id >= MEI_CLIENTS_MAX) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300597 dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
Tomas Winklere036cc52013-09-16 23:44:46 +0300598 return -EMFILE;
599 }
600
Tomas Winkler22f96a02013-09-16 23:44:47 +0300601 open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
602 if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300603 dev_err(dev->dev, "open_handle_count exceeded %d",
Tomas Winklere036cc52013-09-16 23:44:46 +0300604 MEI_MAX_OPEN_HANDLE_COUNT);
605 return -EMFILE;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200606 }
607
Tomas Winkler781d0d82013-01-08 23:07:22 +0200608 dev->open_handle_count++;
609
610 cl->host_client_id = id;
611 list_add_tail(&cl->link, &dev->file_list);
612
613 set_bit(id, dev->host_clients_map);
614
615 cl->state = MEI_FILE_INITIALIZING;
616
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300617 cl_dbg(dev, cl, "link cl\n");
Tomas Winkler781d0d82013-01-08 23:07:22 +0200618 return 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200619}
Tomas Winkler781d0d82013-01-08 23:07:22 +0200620
Tomas Winkler9ca90502013-01-08 23:07:13 +0200621/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200622 * mei_cl_unlink - remove me_cl from the list
Tomas Winkler9ca90502013-01-08 23:07:13 +0200623 *
Masanari Iida393b1482013-04-05 01:05:05 +0900624 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +0300625 *
626 * Return: always 0
Tomas Winkler9ca90502013-01-08 23:07:13 +0200627 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200628int mei_cl_unlink(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200629{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200630 struct mei_device *dev;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200631
Tomas Winkler781d0d82013-01-08 23:07:22 +0200632 /* don't shout on error exit path */
633 if (!cl)
634 return 0;
635
Tomas Winkler8e9a4a92013-01-10 17:32:14 +0200636 /* wd and amthif might not be initialized */
637 if (!cl->dev)
638 return 0;
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200639
640 dev = cl->dev;
641
Tomas Winklera14c44d2013-09-16 23:44:45 +0300642 cl_dbg(dev, cl, "unlink client");
643
Tomas Winkler22f96a02013-09-16 23:44:47 +0300644 if (dev->open_handle_count > 0)
645 dev->open_handle_count--;
646
647 /* never clear the 0 bit */
648 if (cl->host_client_id)
649 clear_bit(cl->host_client_id, dev->host_clients_map);
650
651 list_del_init(&cl->link);
652
653 cl->state = MEI_FILE_INITIALIZING;
654
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200655 return 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200656}
657
658
659void mei_host_client_init(struct work_struct *work)
660{
Tomas Winklerb7d88512015-02-10 10:39:31 +0200661 struct mei_device *dev =
662 container_of(work, struct mei_device, init_work);
Tomas Winkler5ca2d382014-08-21 14:29:13 +0300663 struct mei_me_client *me_cl;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200664
665 mutex_lock(&dev->device_lock);
666
Tomas Winkler9ca90502013-01-08 23:07:13 +0200667
Tomas Winklerb7d88512015-02-10 10:39:31 +0200668 me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
669 if (me_cl)
670 mei_amthif_host_init(dev);
Samuel Ortiz59fcd7c2013-04-11 03:03:29 +0200671
Tomas Winklerb7d88512015-02-10 10:39:31 +0200672 me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid);
673 if (me_cl)
674 mei_wd_host_init(dev);
675
676 me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
677 if (me_cl)
678 mei_nfc_host_init(dev);
679
Tomas Winkler9ca90502013-01-08 23:07:13 +0200680
681 dev->dev_state = MEI_DEV_ENABLED;
Tomas Winkler6adb8ef2014-01-12 00:36:10 +0200682 dev->reset_count = 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200683 mutex_unlock(&dev->device_lock);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200684
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300685 pm_runtime_mark_last_busy(dev->dev);
686 dev_dbg(dev->dev, "rpm: autosuspend\n");
687 pm_runtime_autosuspend(dev->dev);
Tomas Winkler9ca90502013-01-08 23:07:13 +0200688}
689
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200690/**
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300691 * mei_hbuf_acquire - try to acquire host buffer
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200692 *
693 * @dev: the device structure
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300694 * Return: true if host buffer was acquired
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200695 */
696bool mei_hbuf_acquire(struct mei_device *dev)
697{
Tomas Winkler04bb1392014-03-18 22:52:04 +0200698 if (mei_pg_state(dev) == MEI_PG_ON ||
699 dev->pg_event == MEI_PG_EVENT_WAIT) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300700 dev_dbg(dev->dev, "device is in pg\n");
Tomas Winkler04bb1392014-03-18 22:52:04 +0200701 return false;
702 }
703
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200704 if (!dev->hbuf_is_ready) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300705 dev_dbg(dev->dev, "hbuf is not ready\n");
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200706 return false;
707 }
708
709 dev->hbuf_is_ready = false;
710
711 return true;
712}
Tomas Winkler9ca90502013-01-08 23:07:13 +0200713
714/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200715 * mei_cl_disconnect - disconnect host client from the me one
Tomas Winkler9ca90502013-01-08 23:07:13 +0200716 *
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200717 * @cl: host client
Tomas Winkler9ca90502013-01-08 23:07:13 +0200718 *
719 * Locking: called under "dev->device_lock" lock
720 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300721 * Return: 0 on success, <0 on failure.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200722 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200723int mei_cl_disconnect(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200724{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200725 struct mei_device *dev;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200726 struct mei_cl_cb *cb;
Alexander Usyskinfe2f17e2014-07-17 10:53:38 +0300727 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200728
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200729 if (WARN_ON(!cl || !cl->dev))
Tomas Winkler9ca90502013-01-08 23:07:13 +0200730 return -ENODEV;
731
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200732 dev = cl->dev;
733
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300734 cl_dbg(dev, cl, "disconnecting");
735
Tomas Winkler9ca90502013-01-08 23:07:13 +0200736 if (cl->state != MEI_FILE_DISCONNECTING)
737 return 0;
738
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300739 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200740 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300741 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200742 cl_err(dev, cl, "rpm: get failed %d\n", rets);
743 return rets;
744 }
745
Tomas Winklerbca67d62015-02-10 10:39:43 +0200746 cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT, NULL);
747 rets = cb ? 0 : -ENOMEM;
748 if (rets)
Tomas Winkler04bb1392014-03-18 22:52:04 +0200749 goto free;
Tomas Winkler5a8373f2014-08-21 14:29:17 +0300750
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200751 if (mei_hbuf_acquire(dev)) {
Tomas Winkler9ca90502013-01-08 23:07:13 +0200752 if (mei_hbm_cl_disconnect_req(dev, cl)) {
753 rets = -ENODEV;
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300754 cl_err(dev, cl, "failed to disconnect.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200755 goto free;
756 }
Alexander Usyskin22b987a2014-07-17 10:53:35 +0300757 cl->timer_count = MEI_CONNECT_TIMEOUT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200758 mdelay(10); /* Wait for hardware disconnection ready */
759 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
760 } else {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300761 cl_dbg(dev, cl, "add disconnect cb to control write list\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200762 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
763
764 }
765 mutex_unlock(&dev->device_lock);
766
Tomas Winkler12f45ed2014-08-21 14:29:18 +0300767 wait_event_timeout(cl->wait,
Tomas Winkler9ca90502013-01-08 23:07:13 +0200768 MEI_FILE_DISCONNECTED == cl->state,
769 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
770
771 mutex_lock(&dev->device_lock);
Alexander Usyskinfe2f17e2014-07-17 10:53:38 +0300772
Tomas Winkler9ca90502013-01-08 23:07:13 +0200773 if (MEI_FILE_DISCONNECTED == cl->state) {
774 rets = 0;
Alexander Usyskinc0abffb2013-09-15 18:11:07 +0300775 cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
Tomas Winkler9ca90502013-01-08 23:07:13 +0200776 } else {
Alexander Usyskinfe2f17e2014-07-17 10:53:38 +0300777 cl_dbg(dev, cl, "timeout on disconnect from FW client.\n");
778 rets = -ETIME;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200779 }
780
781 mei_io_list_flush(&dev->ctrl_rd_list, cl);
782 mei_io_list_flush(&dev->ctrl_wr_list, cl);
783free:
Tomas Winkler04bb1392014-03-18 22:52:04 +0200784 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300785 pm_runtime_mark_last_busy(dev->dev);
786 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200787
Tomas Winkler9ca90502013-01-08 23:07:13 +0200788 mei_io_cb_free(cb);
789 return rets;
790}
791
792
793/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200794 * mei_cl_is_other_connecting - checks if other
795 * client with the same me client id is connecting
Tomas Winkler9ca90502013-01-08 23:07:13 +0200796 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200797 * @cl: private data of the file object
798 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300799 * Return: true if other client is connected, false - otherwise.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200800 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200801bool mei_cl_is_other_connecting(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200802{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200803 struct mei_device *dev;
Tomas Winkler31f88f52014-02-17 15:13:25 +0200804 struct mei_cl *ocl; /* the other client */
Tomas Winkler9ca90502013-01-08 23:07:13 +0200805
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200806 if (WARN_ON(!cl || !cl->dev))
807 return false;
808
809 dev = cl->dev;
810
Tomas Winkler31f88f52014-02-17 15:13:25 +0200811 list_for_each_entry(ocl, &dev->file_list, link) {
812 if (ocl->state == MEI_FILE_CONNECTING &&
813 ocl != cl &&
814 cl->me_client_id == ocl->me_client_id)
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200815 return true;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200816
817 }
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200818
819 return false;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200820}
821
822/**
Alexander Usyskin83ce0742014-01-08 22:31:46 +0200823 * mei_cl_connect - connect host client to the me one
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200824 *
825 * @cl: host client
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300826 * @file: pointer to file structure
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200827 *
828 * Locking: called under "dev->device_lock" lock
829 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300830 * Return: 0 on success, <0 on failure.
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200831 */
832int mei_cl_connect(struct mei_cl *cl, struct file *file)
833{
834 struct mei_device *dev;
835 struct mei_cl_cb *cb;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200836 int rets;
837
838 if (WARN_ON(!cl || !cl->dev))
839 return -ENODEV;
840
841 dev = cl->dev;
842
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300843 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200844 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300845 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200846 cl_err(dev, cl, "rpm: get failed %d\n", rets);
847 return rets;
848 }
849
Tomas Winklerbca67d62015-02-10 10:39:43 +0200850 cb = mei_io_cb_init(cl, MEI_FOP_CONNECT, file);
851 rets = cb ? 0 : -ENOMEM;
852 if (rets)
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200853 goto out;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200854
Tomas Winkler6aae48f2014-02-19 17:35:47 +0200855 /* run hbuf acquire last so we don't have to undo */
856 if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
Alexander Usyskine4d82702014-04-27 15:42:21 +0300857 cl->state = MEI_FILE_CONNECTING;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200858 if (mei_hbm_cl_connect_req(dev, cl)) {
859 rets = -ENODEV;
860 goto out;
861 }
862 cl->timer_count = MEI_CONNECT_TIMEOUT;
863 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
864 } else {
Alexander Usyskin73ab4232014-08-12 18:07:56 +0300865 cl->state = MEI_FILE_INITIALIZING;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200866 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
867 }
868
869 mutex_unlock(&dev->device_lock);
Tomas Winkler12f45ed2014-08-21 14:29:18 +0300870 wait_event_timeout(cl->wait,
Alexander Usyskin285e2992014-02-17 15:13:20 +0200871 (cl->state == MEI_FILE_CONNECTED ||
872 cl->state == MEI_FILE_DISCONNECTED),
873 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200874 mutex_lock(&dev->device_lock);
875
876 if (cl->state != MEI_FILE_CONNECTED) {
Alexander Usyskin3e37ebb2014-07-17 10:53:34 +0300877 cl->state = MEI_FILE_DISCONNECTED;
Alexander Usyskin285e2992014-02-17 15:13:20 +0200878 /* something went really wrong */
879 if (!cl->status)
880 cl->status = -EFAULT;
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200881
882 mei_io_list_flush(&dev->ctrl_rd_list, cl);
883 mei_io_list_flush(&dev->ctrl_wr_list, cl);
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200884 }
885
886 rets = cl->status;
887
888out:
Tomas Winkler04bb1392014-03-18 22:52:04 +0200889 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +0300890 pm_runtime_mark_last_busy(dev->dev);
891 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +0200892
Tomas Winkler9f81abda2013-01-08 23:07:15 +0200893 mei_io_cb_free(cb);
894 return rets;
895}
896
897/**
Tomas Winkler03b8d342015-02-10 10:39:44 +0200898 * mei_cl_alloc_linked - allocate and link host client
899 *
900 * @dev: the device structure
901 * @id: fixed host id or MEI_HOST_CLIENT_ID_ANY (-1) for generic one
902 *
903 * Return: cl on success ERR_PTR on failure
904 */
905struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id)
906{
907 struct mei_cl *cl;
908 int ret;
909
910 cl = mei_cl_allocate(dev);
911 if (!cl) {
912 ret = -ENOMEM;
913 goto err;
914 }
915
916 ret = mei_cl_link(cl, id);
917 if (ret)
918 goto err;
919
920 return cl;
921err:
922 kfree(cl);
923 return ERR_PTR(ret);
924}
925
926
927
928/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200929 * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200930 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200931 * @cl: private data of the file object
932 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300933 * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200934 * -ENOENT if mei_cl is not present
935 * -EINVAL if single_recv_buf == 0
936 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200937int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200938{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200939 struct mei_device *dev;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200940 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200941 int rets = 0;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200942
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200943 if (WARN_ON(!cl || !cl->dev))
944 return -EINVAL;
945
946 dev = cl->dev;
947
Tomas Winkler9ca90502013-01-08 23:07:13 +0200948 if (cl->mei_flow_ctrl_creds > 0)
949 return 1;
950
Tomas Winkler2e5df412014-12-07 16:40:14 +0200951 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300952 if (!me_cl) {
Alexander Usyskin12d00662014-02-17 15:13:23 +0200953 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300954 return -ENOENT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200955 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200956
Tomas Winkler79563db2015-01-11 00:07:16 +0200957 if (me_cl->mei_flow_ctrl_creds > 0) {
958 rets = 1;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200959 if (WARN_ON(me_cl->props.single_recv_buf == 0))
Tomas Winkler79563db2015-01-11 00:07:16 +0200960 rets = -EINVAL;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200961 }
Tomas Winkler79563db2015-01-11 00:07:16 +0200962 mei_me_cl_put(me_cl);
963 return rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200964}
965
966/**
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200967 * mei_cl_flow_ctrl_reduce - reduces flow_control.
Tomas Winkler9ca90502013-01-08 23:07:13 +0200968 *
Tomas Winkler9ca90502013-01-08 23:07:13 +0200969 * @cl: private data of the file object
Masanari Iida393b1482013-04-05 01:05:05 +0900970 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +0300971 * Return:
Tomas Winkler9ca90502013-01-08 23:07:13 +0200972 * 0 on success
973 * -ENOENT when me client is not found
974 * -EINVAL when ctrl credits are <= 0
975 */
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200976int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
Tomas Winkler9ca90502013-01-08 23:07:13 +0200977{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200978 struct mei_device *dev;
Alexander Usyskin12d00662014-02-17 15:13:23 +0200979 struct mei_me_client *me_cl;
Tomas Winkler79563db2015-01-11 00:07:16 +0200980 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200981
Tomas Winkler90e0b5f12013-01-08 23:07:14 +0200982 if (WARN_ON(!cl || !cl->dev))
983 return -EINVAL;
984
985 dev = cl->dev;
986
Tomas Winkler2e5df412014-12-07 16:40:14 +0200987 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300988 if (!me_cl) {
Alexander Usyskin12d00662014-02-17 15:13:23 +0200989 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +0300990 return -ENOENT;
Tomas Winkler9ca90502013-01-08 23:07:13 +0200991 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200992
Tomas Winklerd3208322014-08-24 12:08:55 +0300993 if (me_cl->props.single_recv_buf) {
Tomas Winkler79563db2015-01-11 00:07:16 +0200994 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
995 rets = -EINVAL;
996 goto out;
997 }
Alexander Usyskin12d00662014-02-17 15:13:23 +0200998 me_cl->mei_flow_ctrl_creds--;
999 } else {
Tomas Winkler79563db2015-01-11 00:07:16 +02001000 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
1001 rets = -EINVAL;
1002 goto out;
1003 }
Alexander Usyskin12d00662014-02-17 15:13:23 +02001004 cl->mei_flow_ctrl_creds--;
1005 }
Tomas Winkler79563db2015-01-11 00:07:16 +02001006 rets = 0;
1007out:
1008 mei_me_cl_put(me_cl);
1009 return rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001010}
1011
Tomas Winkler9ca90502013-01-08 23:07:13 +02001012/**
Masanari Iida393b1482013-04-05 01:05:05 +09001013 * mei_cl_read_start - the start read client message function.
Tomas Winkler9ca90502013-01-08 23:07:13 +02001014 *
Tomas Winkler90e0b5f12013-01-08 23:07:14 +02001015 * @cl: host client
Alexander Usyskince231392014-09-29 16:31:50 +03001016 * @length: number of bytes to read
Tomas Winklerbca67d62015-02-10 10:39:43 +02001017 * @fp: pointer to file structure
Tomas Winkler9ca90502013-01-08 23:07:13 +02001018 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001019 * Return: 0 on success, <0 on failure.
Tomas Winkler9ca90502013-01-08 23:07:13 +02001020 */
Tomas Winklerbca67d62015-02-10 10:39:43 +02001021int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp)
Tomas Winkler9ca90502013-01-08 23:07:13 +02001022{
Tomas Winkler90e0b5f12013-01-08 23:07:14 +02001023 struct mei_device *dev;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001024 struct mei_cl_cb *cb;
Tomas Winklerd3208322014-08-24 12:08:55 +03001025 struct mei_me_client *me_cl;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001026 int rets;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001027
Tomas Winkler90e0b5f12013-01-08 23:07:14 +02001028 if (WARN_ON(!cl || !cl->dev))
1029 return -ENODEV;
1030
1031 dev = cl->dev;
1032
Tomas Winklerb950ac12013-07-25 20:15:53 +03001033 if (!mei_cl_is_connected(cl))
Tomas Winkler9ca90502013-01-08 23:07:13 +02001034 return -ENODEV;
1035
Tomas Winklera9bed612015-02-10 10:39:46 +02001036 /* HW currently supports only one pending read */
1037 if (!list_empty(&cl->rd_pending))
Tomas Winkler9ca90502013-01-08 23:07:13 +02001038 return -EBUSY;
Tomas Winklera9bed612015-02-10 10:39:46 +02001039
Tomas Winklerd880f322014-08-21 14:29:15 +03001040 me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
Tomas Winklerd3208322014-08-24 12:08:55 +03001041 if (!me_cl) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001042 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001043 return -ENOTTY;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001044 }
Tomas Winkler79563db2015-01-11 00:07:16 +02001045 /* always allocate at least client max message */
1046 length = max_t(size_t, length, me_cl->props.max_msg_length);
1047 mei_me_cl_put(me_cl);
Tomas Winkler9ca90502013-01-08 23:07:13 +02001048
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001049 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001050 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001051 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001052 cl_err(dev, cl, "rpm: get failed %d\n", rets);
1053 return rets;
1054 }
1055
Tomas Winklerbca67d62015-02-10 10:39:43 +02001056 cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp);
1057 rets = cb ? 0 : -ENOMEM;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001058 if (rets)
Tomas Winkler04bb1392014-03-18 22:52:04 +02001059 goto out;
Tomas Winkler9ca90502013-01-08 23:07:13 +02001060
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001061 if (mei_hbuf_acquire(dev)) {
Alexander Usyskin86113502014-03-31 17:59:24 +03001062 rets = mei_hbm_cl_flow_control_req(dev, cl);
1063 if (rets < 0)
Tomas Winkler04bb1392014-03-18 22:52:04 +02001064 goto out;
Tomas Winkler04bb1392014-03-18 22:52:04 +02001065
Tomas Winklera9bed612015-02-10 10:39:46 +02001066 list_add_tail(&cb->list, &cl->rd_pending);
Tomas Winkler9ca90502013-01-08 23:07:13 +02001067 } else {
1068 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
1069 }
Chao Biaccb8842014-02-12 21:27:25 +02001070
Tomas Winkler04bb1392014-03-18 22:52:04 +02001071out:
1072 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001073 pm_runtime_mark_last_busy(dev->dev);
1074 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001075
1076 if (rets)
1077 mei_io_cb_free(cb);
1078
Tomas Winkler9ca90502013-01-08 23:07:13 +02001079 return rets;
1080}
1081
Tomas Winkler074b4c02013-02-06 14:06:44 +02001082/**
Tomas Winkler9d098192014-02-19 17:35:48 +02001083 * mei_cl_irq_write - write a message to device
Tomas Winkler21767542013-06-23 09:36:59 +03001084 * from the interrupt thread context
1085 *
1086 * @cl: client
1087 * @cb: callback block.
Tomas Winkler21767542013-06-23 09:36:59 +03001088 * @cmpl_list: complete list.
1089 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001090 * Return: 0, OK; otherwise error.
Tomas Winkler21767542013-06-23 09:36:59 +03001091 */
Tomas Winkler9d098192014-02-19 17:35:48 +02001092int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
1093 struct mei_cl_cb *cmpl_list)
Tomas Winkler21767542013-06-23 09:36:59 +03001094{
Tomas Winkler136698e2013-09-16 23:44:44 +03001095 struct mei_device *dev;
1096 struct mei_msg_data *buf;
Tomas Winkler21767542013-06-23 09:36:59 +03001097 struct mei_msg_hdr mei_hdr;
Tomas Winkler136698e2013-09-16 23:44:44 +03001098 size_t len;
1099 u32 msg_slots;
Tomas Winkler9d098192014-02-19 17:35:48 +02001100 int slots;
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001101 int rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001102
Tomas Winkler136698e2013-09-16 23:44:44 +03001103 if (WARN_ON(!cl || !cl->dev))
1104 return -ENODEV;
1105
1106 dev = cl->dev;
1107
Tomas Winkler5db75142015-02-10 10:39:42 +02001108 buf = &cb->buf;
Tomas Winkler136698e2013-09-16 23:44:44 +03001109
1110 rets = mei_cl_flow_ctrl_creds(cl);
1111 if (rets < 0)
1112 return rets;
1113
1114 if (rets == 0) {
Tomas Winkler04bb1392014-03-18 22:52:04 +02001115 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
Tomas Winkler136698e2013-09-16 23:44:44 +03001116 return 0;
1117 }
1118
Tomas Winkler9d098192014-02-19 17:35:48 +02001119 slots = mei_hbuf_empty_slots(dev);
Tomas Winkler136698e2013-09-16 23:44:44 +03001120 len = buf->size - cb->buf_idx;
1121 msg_slots = mei_data2slots(len);
1122
Tomas Winkler21767542013-06-23 09:36:59 +03001123 mei_hdr.host_addr = cl->host_client_id;
1124 mei_hdr.me_addr = cl->me_client_id;
1125 mei_hdr.reserved = 0;
Tomas Winkler479327f2013-12-17 15:56:56 +02001126 mei_hdr.internal = cb->internal;
Tomas Winkler21767542013-06-23 09:36:59 +03001127
Tomas Winkler9d098192014-02-19 17:35:48 +02001128 if (slots >= msg_slots) {
Tomas Winkler21767542013-06-23 09:36:59 +03001129 mei_hdr.length = len;
1130 mei_hdr.msg_complete = 1;
1131 /* Split the message only if we can write the whole host buffer */
Tomas Winkler9d098192014-02-19 17:35:48 +02001132 } else if (slots == dev->hbuf_depth) {
1133 msg_slots = slots;
1134 len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
Tomas Winkler21767542013-06-23 09:36:59 +03001135 mei_hdr.length = len;
1136 mei_hdr.msg_complete = 0;
1137 } else {
1138 /* wait for next time the host buffer is empty */
1139 return 0;
1140 }
1141
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001142 cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
Tomas Winkler5db75142015-02-10 10:39:42 +02001143 cb->buf.size, cb->buf_idx);
Tomas Winkler21767542013-06-23 09:36:59 +03001144
Tomas Winkler136698e2013-09-16 23:44:44 +03001145 rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001146 if (rets) {
1147 cl->status = rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001148 list_move_tail(&cb->list, &cmpl_list->list);
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001149 return rets;
Tomas Winkler21767542013-06-23 09:36:59 +03001150 }
1151
1152 cl->status = 0;
Tomas Winkler4dfaa9f2013-06-23 09:37:00 +03001153 cl->writing_state = MEI_WRITING;
Tomas Winkler21767542013-06-23 09:36:59 +03001154 cb->buf_idx += mei_hdr.length;
Tomas Winkler86601722015-02-10 10:39:40 +02001155 cb->completed = mei_hdr.msg_complete == 1;
Tomas Winkler4dfaa9f2013-06-23 09:37:00 +03001156
Tomas Winkler21767542013-06-23 09:36:59 +03001157 if (mei_hdr.msg_complete) {
1158 if (mei_cl_flow_ctrl_reduce(cl))
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001159 return -EIO;
Tomas Winkler21767542013-06-23 09:36:59 +03001160 list_move_tail(&cb->list, &dev->write_waiting_list.list);
1161 }
1162
1163 return 0;
1164}
1165
1166/**
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001167 * mei_cl_write - submit a write cb to mei device
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001168 * assumes device_lock is locked
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001169 *
1170 * @cl: host client
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001171 * @cb: write callback with filled data
Alexander Usyskince231392014-09-29 16:31:50 +03001172 * @blocking: block until completed
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001173 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001174 * Return: number of bytes sent on success, <0 on failure.
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001175 */
1176int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
1177{
1178 struct mei_device *dev;
1179 struct mei_msg_data *buf;
1180 struct mei_msg_hdr mei_hdr;
1181 int rets;
1182
1183
1184 if (WARN_ON(!cl || !cl->dev))
1185 return -ENODEV;
1186
1187 if (WARN_ON(!cb))
1188 return -EINVAL;
1189
1190 dev = cl->dev;
1191
1192
Tomas Winkler5db75142015-02-10 10:39:42 +02001193 buf = &cb->buf;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001194
Alexander Usyskin0a01e972014-09-29 16:31:47 +03001195 cl_dbg(dev, cl, "size=%d\n", buf->size);
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001196
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001197 rets = pm_runtime_get(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001198 if (rets < 0 && rets != -EINPROGRESS) {
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001199 pm_runtime_put_noidle(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001200 cl_err(dev, cl, "rpm: get failed %d\n", rets);
1201 return rets;
1202 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001203
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001204 cb->buf_idx = 0;
1205 cl->writing_state = MEI_IDLE;
1206
1207 mei_hdr.host_addr = cl->host_client_id;
1208 mei_hdr.me_addr = cl->me_client_id;
1209 mei_hdr.reserved = 0;
1210 mei_hdr.msg_complete = 0;
1211 mei_hdr.internal = cb->internal;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001212
1213 rets = mei_cl_flow_ctrl_creds(cl);
1214 if (rets < 0)
1215 goto err;
1216
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001217 if (rets == 0) {
1218 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001219 rets = buf->size;
1220 goto out;
1221 }
Tomas Winkler6aae48f2014-02-19 17:35:47 +02001222 if (!mei_hbuf_acquire(dev)) {
1223 cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
1224 rets = buf->size;
1225 goto out;
1226 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001227
1228 /* Check for a maximum length */
1229 if (buf->size > mei_hbuf_max_len(dev)) {
1230 mei_hdr.length = mei_hbuf_max_len(dev);
1231 mei_hdr.msg_complete = 0;
1232 } else {
1233 mei_hdr.length = buf->size;
1234 mei_hdr.msg_complete = 1;
1235 }
1236
Tomas Winkler2ebf8c92013-09-16 23:44:43 +03001237 rets = mei_write_message(dev, &mei_hdr, buf->data);
1238 if (rets)
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001239 goto err;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001240
1241 cl->writing_state = MEI_WRITING;
1242 cb->buf_idx = mei_hdr.length;
Tomas Winkler86601722015-02-10 10:39:40 +02001243 cb->completed = mei_hdr.msg_complete == 1;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001244
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001245out:
1246 if (mei_hdr.msg_complete) {
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001247 rets = mei_cl_flow_ctrl_reduce(cl);
1248 if (rets < 0)
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001249 goto err;
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001250
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001251 list_add_tail(&cb->list, &dev->write_waiting_list.list);
1252 } else {
1253 list_add_tail(&cb->list, &dev->write_list.list);
1254 }
1255
1256
1257 if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
1258
1259 mutex_unlock(&dev->device_lock);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001260 rets = wait_event_interruptible(cl->tx_wait,
1261 cl->writing_state == MEI_WRITE_COMPLETE);
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001262 mutex_lock(&dev->device_lock);
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001263 /* wait_event_interruptible returns -ERESTARTSYS */
1264 if (rets) {
1265 if (signal_pending(current))
1266 rets = -EINTR;
1267 goto err;
1268 }
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001269 }
Alexander Usyskin7ca96aa2014-02-19 17:35:49 +02001270
1271 rets = buf->size;
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001272err:
Tomas Winkler04bb1392014-03-18 22:52:04 +02001273 cl_dbg(dev, cl, "rpm: autosuspend\n");
Tomas Winkler2bf94cab2014-09-29 16:31:42 +03001274 pm_runtime_mark_last_busy(dev->dev);
1275 pm_runtime_put_autosuspend(dev->dev);
Tomas Winkler04bb1392014-03-18 22:52:04 +02001276
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001277 return rets;
1278}
1279
1280
Tomas Winklerdb086fa2013-05-12 15:34:45 +03001281/**
1282 * mei_cl_complete - processes completed operation for a client
1283 *
1284 * @cl: private data of the file object.
1285 * @cb: callback block.
1286 */
1287void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
1288{
1289 if (cb->fop_type == MEI_FOP_WRITE) {
1290 mei_io_cb_free(cb);
1291 cb = NULL;
1292 cl->writing_state = MEI_WRITE_COMPLETE;
1293 if (waitqueue_active(&cl->tx_wait))
1294 wake_up_interruptible(&cl->tx_wait);
1295
Tomas Winklera9bed612015-02-10 10:39:46 +02001296 } else if (cb->fop_type == MEI_FOP_READ) {
1297 list_add_tail(&cb->list, &cl->rd_completed);
Tomas Winklerdb086fa2013-05-12 15:34:45 +03001298 if (waitqueue_active(&cl->rx_wait))
1299 wake_up_interruptible(&cl->rx_wait);
1300 else
1301 mei_cl_bus_rx_event(cl);
1302
1303 }
1304}
1305
Tomas Winkler4234a6d2013-04-08 21:56:37 +03001306
1307/**
Tomas Winkler074b4c02013-02-06 14:06:44 +02001308 * mei_cl_all_disconnect - disconnect forcefully all connected clients
1309 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001310 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001311 */
1312
1313void mei_cl_all_disconnect(struct mei_device *dev)
1314{
Tomas Winkler31f88f52014-02-17 15:13:25 +02001315 struct mei_cl *cl;
Tomas Winkler074b4c02013-02-06 14:06:44 +02001316
Tomas Winkler31f88f52014-02-17 15:13:25 +02001317 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winkler074b4c02013-02-06 14:06:44 +02001318 cl->state = MEI_FILE_DISCONNECTED;
1319 cl->mei_flow_ctrl_creds = 0;
Tomas Winkler074b4c02013-02-06 14:06:44 +02001320 cl->timer_count = 0;
1321 }
1322}
1323
1324
1325/**
Tomas Winkler52908012013-07-24 16:22:57 +03001326 * mei_cl_all_wakeup - wake up all readers and writers they can be interrupted
Tomas Winkler074b4c02013-02-06 14:06:44 +02001327 *
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001328 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001329 */
Tomas Winkler52908012013-07-24 16:22:57 +03001330void mei_cl_all_wakeup(struct mei_device *dev)
Tomas Winkler074b4c02013-02-06 14:06:44 +02001331{
Tomas Winkler31f88f52014-02-17 15:13:25 +02001332 struct mei_cl *cl;
Tomas Winkler92db1552014-09-29 16:31:37 +03001333
Tomas Winkler31f88f52014-02-17 15:13:25 +02001334 list_for_each_entry(cl, &dev->file_list, link) {
Tomas Winkler074b4c02013-02-06 14:06:44 +02001335 if (waitqueue_active(&cl->rx_wait)) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001336 cl_dbg(dev, cl, "Waking up reading client!\n");
Tomas Winkler074b4c02013-02-06 14:06:44 +02001337 wake_up_interruptible(&cl->rx_wait);
1338 }
Tomas Winkler52908012013-07-24 16:22:57 +03001339 if (waitqueue_active(&cl->tx_wait)) {
Alexander Usyskinc0abffb2013-09-15 18:11:07 +03001340 cl_dbg(dev, cl, "Waking up writing client!\n");
Tomas Winkler52908012013-07-24 16:22:57 +03001341 wake_up_interruptible(&cl->tx_wait);
1342 }
Tomas Winkler074b4c02013-02-06 14:06:44 +02001343 }
1344}
1345
1346/**
1347 * mei_cl_all_write_clear - clear all pending writes
Alexander Usyskina8605ea2014-09-29 16:31:49 +03001348 *
1349 * @dev: mei device
Tomas Winkler074b4c02013-02-06 14:06:44 +02001350 */
1351void mei_cl_all_write_clear(struct mei_device *dev)
1352{
Tomas Winklercc99ecf2014-03-10 15:10:40 +02001353 mei_io_list_free(&dev->write_list, NULL);
1354 mei_io_list_free(&dev->write_waiting_list, NULL);
Tomas Winkler074b4c02013-02-06 14:06:44 +02001355}
1356
1357