]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/misc/mei/client.c
mei: add read callback on demand for fixed_address clients
[mirror_ubuntu-artful-kernel.git] / drivers / misc / mei / client.c
CommitLineData
ab841160
OW
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
733ba91c 4 * Copyright (c) 2003-2012, Intel Corporation.
ab841160
OW
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
ab841160 17#include <linux/sched.h>
9ca9050b
TW
18#include <linux/wait.h>
19#include <linux/delay.h>
1f180359 20#include <linux/slab.h>
04bb139a 21#include <linux/pm_runtime.h>
ab841160 22
4f3afe1d 23#include <linux/mei.h>
47a73801
TW
24
25#include "mei_dev.h"
0edb23fc 26#include "hbm.h"
90e0b5f1
TW
27#include "client.h"
28
79563db9
TW
29/**
30 * 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{
b7d88514
TW
51 if (me_cl && kref_get_unless_zero(&me_cl->refcnt))
52 return me_cl;
79563db9 53
b7d88514 54 return NULL;
79563db9
TW
55}
56
57/**
b7d88514 58 * mei_me_cl_release - free me client
79563db9
TW
59 *
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);
b7d88514 68
79563db9
TW
69 kfree(me_cl);
70}
b7d88514 71
79563db9
TW
72/**
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
90e0b5f1 85/**
d49ed64a 86 * __mei_me_cl_del - delete me client from the list and decrease
b7d88514
TW
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
d49ed64a 99 list_del_init(&me_cl->list);
b7d88514
TW
100 mei_me_cl_put(me_cl);
101}
102
d49ed64a
AU
103/**
104 * mei_me_cl_del - delete me client from the list and decrease
105 * reference counter
106 *
107 * @dev: mei device
108 * @me_cl: me client
109 */
110void mei_me_cl_del(struct mei_device *dev, struct mei_me_client *me_cl)
111{
112 down_write(&dev->me_clients_rwsem);
113 __mei_me_cl_del(dev, me_cl);
114 up_write(&dev->me_clients_rwsem);
115}
116
b7d88514
TW
117/**
118 * mei_me_cl_add - add me client to the list
119 *
120 * @dev: mei device
121 * @me_cl: me client
122 */
123void mei_me_cl_add(struct mei_device *dev, struct mei_me_client *me_cl)
124{
125 down_write(&dev->me_clients_rwsem);
126 list_add(&me_cl->list, &dev->me_clients);
127 up_write(&dev->me_clients_rwsem);
128}
129
130/**
131 * __mei_me_cl_by_uuid - locate me client by uuid
79563db9 132 * increases ref count
90e0b5f1
TW
133 *
134 * @dev: mei device
a8605ea2 135 * @uuid: me client uuid
a27a76d3 136 *
a8605ea2 137 * Return: me client or NULL if not found
b7d88514
TW
138 *
139 * Locking: dev->me_clients_rwsem
90e0b5f1 140 */
b7d88514 141static struct mei_me_client *__mei_me_cl_by_uuid(struct mei_device *dev,
d320832f 142 const uuid_le *uuid)
90e0b5f1 143{
5ca2d388 144 struct mei_me_client *me_cl;
b7d88514 145 const uuid_le *pn;
90e0b5f1 146
b7d88514
TW
147 WARN_ON(!rwsem_is_locked(&dev->me_clients_rwsem));
148
149 list_for_each_entry(me_cl, &dev->me_clients, list) {
150 pn = &me_cl->props.protocol_name;
151 if (uuid_le_cmp(*uuid, *pn) == 0)
79563db9 152 return mei_me_cl_get(me_cl);
b7d88514 153 }
90e0b5f1 154
d320832f 155 return NULL;
90e0b5f1
TW
156}
157
b7d88514
TW
158/**
159 * mei_me_cl_by_uuid - locate me client by uuid
160 * increases ref count
161 *
162 * @dev: mei device
163 * @uuid: me client uuid
164 *
165 * Return: me client or NULL if not found
166 *
167 * Locking: dev->me_clients_rwsem
168 */
169struct mei_me_client *mei_me_cl_by_uuid(struct mei_device *dev,
170 const uuid_le *uuid)
171{
172 struct mei_me_client *me_cl;
173
174 down_read(&dev->me_clients_rwsem);
175 me_cl = __mei_me_cl_by_uuid(dev, uuid);
176 up_read(&dev->me_clients_rwsem);
177
178 return me_cl;
179}
180
90e0b5f1 181/**
a8605ea2 182 * mei_me_cl_by_id - locate me client by client id
79563db9 183 * increases ref count
90e0b5f1
TW
184 *
185 * @dev: the device structure
186 * @client_id: me client id
187 *
a8605ea2 188 * Return: me client or NULL if not found
b7d88514
TW
189 *
190 * Locking: dev->me_clients_rwsem
90e0b5f1 191 */
d320832f 192struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
90e0b5f1 193{
a27a76d3 194
b7d88514
TW
195 struct mei_me_client *__me_cl, *me_cl = NULL;
196
197 down_read(&dev->me_clients_rwsem);
198 list_for_each_entry(__me_cl, &dev->me_clients, list) {
199 if (__me_cl->client_id == client_id) {
200 me_cl = mei_me_cl_get(__me_cl);
201 break;
202 }
203 }
204 up_read(&dev->me_clients_rwsem);
205
206 return me_cl;
207}
208
209/**
210 * __mei_me_cl_by_uuid_id - locate me client by client id and uuid
211 * increases ref count
212 *
213 * @dev: the device structure
214 * @uuid: me client uuid
215 * @client_id: me client id
216 *
217 * Return: me client or null if not found
218 *
219 * Locking: dev->me_clients_rwsem
220 */
221static struct mei_me_client *__mei_me_cl_by_uuid_id(struct mei_device *dev,
222 const uuid_le *uuid, u8 client_id)
223{
5ca2d388 224 struct mei_me_client *me_cl;
b7d88514
TW
225 const uuid_le *pn;
226
227 WARN_ON(!rwsem_is_locked(&dev->me_clients_rwsem));
90e0b5f1 228
b7d88514
TW
229 list_for_each_entry(me_cl, &dev->me_clients, list) {
230 pn = &me_cl->props.protocol_name;
231 if (uuid_le_cmp(*uuid, *pn) == 0 &&
232 me_cl->client_id == client_id)
79563db9 233 return mei_me_cl_get(me_cl);
b7d88514 234 }
79563db9 235
d320832f 236 return NULL;
90e0b5f1 237}
ab841160 238
b7d88514 239
a8605ea2
AU
240/**
241 * mei_me_cl_by_uuid_id - locate me client by client id and uuid
79563db9 242 * increases ref count
a8605ea2
AU
243 *
244 * @dev: the device structure
245 * @uuid: me client uuid
246 * @client_id: me client id
247 *
b7d88514 248 * Return: me client or null if not found
a8605ea2 249 */
d880f329
TW
250struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
251 const uuid_le *uuid, u8 client_id)
252{
253 struct mei_me_client *me_cl;
254
b7d88514
TW
255 down_read(&dev->me_clients_rwsem);
256 me_cl = __mei_me_cl_by_uuid_id(dev, uuid, client_id);
257 up_read(&dev->me_clients_rwsem);
79563db9 258
b7d88514 259 return me_cl;
d880f329
TW
260}
261
25ca6472 262/**
79563db9 263 * mei_me_cl_rm_by_uuid - remove all me clients matching uuid
25ca6472
TW
264 *
265 * @dev: the device structure
266 * @uuid: me client uuid
79563db9
TW
267 *
268 * Locking: called under "dev->device_lock" lock
25ca6472 269 */
79563db9 270void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid)
25ca6472 271{
b7d88514 272 struct mei_me_client *me_cl;
25ca6472 273
79563db9 274 dev_dbg(dev->dev, "remove %pUl\n", uuid);
b7d88514
TW
275
276 down_write(&dev->me_clients_rwsem);
277 me_cl = __mei_me_cl_by_uuid(dev, uuid);
278 __mei_me_cl_del(dev, me_cl);
279 up_write(&dev->me_clients_rwsem);
79563db9
TW
280}
281
282/**
283 * mei_me_cl_rm_by_uuid_id - remove all me clients matching client id
284 *
285 * @dev: the device structure
286 * @uuid: me client uuid
287 * @id: me client id
288 *
289 * Locking: called under "dev->device_lock" lock
290 */
291void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 id)
292{
b7d88514 293 struct mei_me_client *me_cl;
79563db9
TW
294
295 dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id);
b7d88514
TW
296
297 down_write(&dev->me_clients_rwsem);
298 me_cl = __mei_me_cl_by_uuid_id(dev, uuid, id);
299 __mei_me_cl_del(dev, me_cl);
300 up_write(&dev->me_clients_rwsem);
25ca6472
TW
301}
302
79563db9
TW
303/**
304 * mei_me_cl_rm_all - remove all me clients
305 *
306 * @dev: the device structure
307 *
308 * Locking: called under "dev->device_lock" lock
309 */
310void mei_me_cl_rm_all(struct mei_device *dev)
311{
312 struct mei_me_client *me_cl, *next;
313
b7d88514 314 down_write(&dev->me_clients_rwsem);
79563db9 315 list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
b7d88514
TW
316 __mei_me_cl_del(dev, me_cl);
317 up_write(&dev->me_clients_rwsem);
79563db9
TW
318}
319
9ca9050b 320/**
cc99ecfd 321 * mei_cl_cmp_id - tells if the clients are the same
9ca9050b 322 *
cc99ecfd
TW
323 * @cl1: host client 1
324 * @cl2: host client 2
325 *
a8605ea2 326 * Return: true - if the clients has same host and me ids
cc99ecfd
TW
327 * false - otherwise
328 */
329static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
330 const struct mei_cl *cl2)
331{
332 return cl1 && cl2 &&
333 (cl1->host_client_id == cl2->host_client_id) &&
d49ed64a 334 (mei_cl_me_id(cl1) == mei_cl_me_id(cl2));
cc99ecfd
TW
335}
336
928fa666
TW
337/**
338 * mei_io_cb_free - free mei_cb_private related memory
339 *
340 * @cb: mei callback struct
341 */
342void mei_io_cb_free(struct mei_cl_cb *cb)
343{
344 if (cb == NULL)
345 return;
346
347 list_del(&cb->list);
348 kfree(cb->buf.data);
349 kfree(cb);
350}
351
352/**
353 * mei_io_cb_init - allocate and initialize io callback
354 *
355 * @cl: mei client
356 * @type: operation type
357 * @fp: pointer to file structure
358 *
359 * Return: mei_cl_cb pointer or NULL;
360 */
361struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
f23e2cc4 362 const struct file *fp)
928fa666
TW
363{
364 struct mei_cl_cb *cb;
365
366 cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
367 if (!cb)
368 return NULL;
369
370 INIT_LIST_HEAD(&cb->list);
62e8e6ad 371 cb->fp = fp;
928fa666
TW
372 cb->cl = cl;
373 cb->buf_idx = 0;
374 cb->fop_type = type;
375 return cb;
376}
377
cc99ecfd 378/**
3908be6f 379 * __mei_io_list_flush - removes and frees cbs belonging to cl.
cc99ecfd
TW
380 *
381 * @list: an instance of our list structure
382 * @cl: host client, can be NULL for flushing the whole list
383 * @free: whether to free the cbs
9ca9050b 384 */
cc99ecfd
TW
385static void __mei_io_list_flush(struct mei_cl_cb *list,
386 struct mei_cl *cl, bool free)
9ca9050b 387{
928fa666 388 struct mei_cl_cb *cb, *next;
9ca9050b 389
cc99ecfd 390 /* enable removing everything if no cl is specified */
9ca9050b 391 list_for_each_entry_safe(cb, next, &list->list, list) {
140c7553 392 if (!cl || mei_cl_cmp_id(cl, cb->cl)) {
928fa666 393 list_del_init(&cb->list);
cc99ecfd
TW
394 if (free)
395 mei_io_cb_free(cb);
396 }
9ca9050b
TW
397 }
398}
399
cc99ecfd
TW
400/**
401 * mei_io_list_flush - removes list entry belonging to cl.
402 *
403 * @list: An instance of our list structure
404 * @cl: host client
405 */
5456796b 406void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
cc99ecfd
TW
407{
408 __mei_io_list_flush(list, cl, false);
409}
410
cc99ecfd
TW
411/**
412 * mei_io_list_free - removes cb belonging to cl and free them
413 *
414 * @list: An instance of our list structure
415 * @cl: host client
416 */
417static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
418{
419 __mei_io_list_flush(list, cl, true);
420}
421
bca67d68
TW
422/**
423 * mei_cl_alloc_cb - a convenient wrapper for allocating read cb
424 *
425 * @cl: host client
426 * @length: size of the buffer
427 * @type: operation type
428 * @fp: associated file pointer (might be NULL)
429 *
430 * Return: cb on success and NULL on failure
431 */
432struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
f23e2cc4
TW
433 enum mei_cb_file_ops type,
434 const struct file *fp)
bca67d68
TW
435{
436 struct mei_cl_cb *cb;
437
438 cb = mei_io_cb_init(cl, type, fp);
439 if (!cb)
440 return NULL;
441
aab3b1a3
AU
442 if (length == 0)
443 return cb;
444
445 cb->buf.data = kmalloc(length, GFP_KERNEL);
446 if (!cb->buf.data) {
bca67d68
TW
447 mei_io_cb_free(cb);
448 return NULL;
449 }
aab3b1a3 450 cb->buf.size = length;
bca67d68
TW
451
452 return cb;
453}
454
a9bed610
TW
455/**
456 * mei_cl_read_cb - find this cl's callback in the read list
457 * for a specific file
458 *
459 * @cl: host client
460 * @fp: file pointer (matching cb file object), may be NULL
461 *
462 * Return: cb on success, NULL if cb is not found
463 */
464struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, const struct file *fp)
465{
466 struct mei_cl_cb *cb;
467
468 list_for_each_entry(cb, &cl->rd_completed, list)
62e8e6ad 469 if (!fp || fp == cb->fp)
a9bed610
TW
470 return cb;
471
472 return NULL;
473}
474
475/**
476 * mei_cl_read_cb_flush - free client's read pending and completed cbs
477 * for a specific file
478 *
479 * @cl: host client
480 * @fp: file pointer (matching cb file object), may be NULL
481 */
482void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp)
483{
484 struct mei_cl_cb *cb, *next;
485
486 list_for_each_entry_safe(cb, next, &cl->rd_completed, list)
62e8e6ad 487 if (!fp || fp == cb->fp)
a9bed610
TW
488 mei_io_cb_free(cb);
489
490
491 list_for_each_entry_safe(cb, next, &cl->rd_pending, list)
62e8e6ad 492 if (!fp || fp == cb->fp)
a9bed610
TW
493 mei_io_cb_free(cb);
494}
495
9ca9050b
TW
496/**
497 * mei_cl_flush_queues - flushes queue lists belonging to cl.
498 *
9ca9050b 499 * @cl: host client
a9bed610 500 * @fp: file pointer (matching cb file object), may be NULL
ce23139c
AU
501 *
502 * Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
9ca9050b 503 */
a9bed610 504int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp)
9ca9050b 505{
c0abffbd
AU
506 struct mei_device *dev;
507
90e0b5f1 508 if (WARN_ON(!cl || !cl->dev))
9ca9050b
TW
509 return -EINVAL;
510
c0abffbd
AU
511 dev = cl->dev;
512
513 cl_dbg(dev, cl, "remove list entry belonging to cl\n");
cc99ecfd
TW
514 mei_io_list_free(&cl->dev->write_list, cl);
515 mei_io_list_free(&cl->dev->write_waiting_list, cl);
9ca9050b
TW
516 mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
517 mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
518 mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
a9bed610
TW
519
520 mei_cl_read_cb_flush(cl, fp);
521
9ca9050b
TW
522 return 0;
523}
524
ab841160 525
9ca9050b 526/**
83ce0741 527 * mei_cl_init - initializes cl.
9ca9050b
TW
528 *
529 * @cl: host client to be initialized
530 * @dev: mei device
531 */
532void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
533{
534 memset(cl, 0, sizeof(struct mei_cl));
535 init_waitqueue_head(&cl->wait);
536 init_waitqueue_head(&cl->rx_wait);
537 init_waitqueue_head(&cl->tx_wait);
b38a362f 538 init_waitqueue_head(&cl->ev_wait);
a9bed610
TW
539 INIT_LIST_HEAD(&cl->rd_completed);
540 INIT_LIST_HEAD(&cl->rd_pending);
9ca9050b 541 INIT_LIST_HEAD(&cl->link);
9ca9050b 542 cl->writing_state = MEI_IDLE;
3c666182 543 cl->state = MEI_FILE_INITIALIZING;
9ca9050b
TW
544 cl->dev = dev;
545}
546
547/**
548 * mei_cl_allocate - allocates cl structure and sets it up.
549 *
550 * @dev: mei device
a8605ea2 551 * Return: The allocated file or NULL on failure
9ca9050b
TW
552 */
553struct mei_cl *mei_cl_allocate(struct mei_device *dev)
554{
555 struct mei_cl *cl;
556
557 cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
558 if (!cl)
559 return NULL;
560
561 mei_cl_init(cl, dev);
562
563 return cl;
564}
565
3908be6f
AU
566/**
567 * mei_cl_link - allocate host id in the host map
9ca9050b 568 *
3908be6f 569 * @cl: host client
393b148f 570 *
a8605ea2 571 * Return: 0 on success
9ca9050b 572 * -EINVAL on incorrect values
03b8d341 573 * -EMFILE if open count exceeded.
9ca9050b 574 */
7851e008 575int mei_cl_link(struct mei_cl *cl)
9ca9050b 576{
90e0b5f1 577 struct mei_device *dev;
22f96a0e 578 long open_handle_count;
7851e008 579 int id;
9ca9050b 580
781d0d89 581 if (WARN_ON(!cl || !cl->dev))
9ca9050b
TW
582 return -EINVAL;
583
90e0b5f1
TW
584 dev = cl->dev;
585
7851e008 586 id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX);
781d0d89 587 if (id >= MEI_CLIENTS_MAX) {
2bf94cab 588 dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
e036cc57
TW
589 return -EMFILE;
590 }
591
22f96a0e
TW
592 open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
593 if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
2bf94cab 594 dev_err(dev->dev, "open_handle_count exceeded %d",
e036cc57
TW
595 MEI_MAX_OPEN_HANDLE_COUNT);
596 return -EMFILE;
9ca9050b
TW
597 }
598
781d0d89
TW
599 dev->open_handle_count++;
600
601 cl->host_client_id = id;
602 list_add_tail(&cl->link, &dev->file_list);
603
604 set_bit(id, dev->host_clients_map);
605
606 cl->state = MEI_FILE_INITIALIZING;
607
c0abffbd 608 cl_dbg(dev, cl, "link cl\n");
781d0d89 609 return 0;
9ca9050b 610}
781d0d89 611
9ca9050b 612/**
d49ed64a 613 * mei_cl_unlink - remove host client from the list
9ca9050b 614 *
393b148f 615 * @cl: host client
ce23139c
AU
616 *
617 * Return: always 0
9ca9050b 618 */
90e0b5f1 619int mei_cl_unlink(struct mei_cl *cl)
9ca9050b 620{
90e0b5f1 621 struct mei_device *dev;
90e0b5f1 622
781d0d89
TW
623 /* don't shout on error exit path */
624 if (!cl)
625 return 0;
626
fdd9b865 627 /* amthif might not be initialized */
8e9a4a9a
TW
628 if (!cl->dev)
629 return 0;
90e0b5f1
TW
630
631 dev = cl->dev;
632
a14c44d8
TW
633 cl_dbg(dev, cl, "unlink client");
634
22f96a0e
TW
635 if (dev->open_handle_count > 0)
636 dev->open_handle_count--;
637
638 /* never clear the 0 bit */
639 if (cl->host_client_id)
640 clear_bit(cl->host_client_id, dev->host_clients_map);
641
642 list_del_init(&cl->link);
643
644 cl->state = MEI_FILE_INITIALIZING;
645
90e0b5f1 646 return 0;
9ca9050b
TW
647}
648
025fb792 649void mei_host_client_init(struct mei_device *dev)
9ca9050b 650{
9ca9050b 651 dev->dev_state = MEI_DEV_ENABLED;
6adb8efb 652 dev->reset_count = 0;
04bb139a 653
025fb792 654 schedule_work(&dev->bus_rescan_work);
6009595a 655
2bf94cab
TW
656 pm_runtime_mark_last_busy(dev->dev);
657 dev_dbg(dev->dev, "rpm: autosuspend\n");
658 pm_runtime_autosuspend(dev->dev);
9ca9050b
TW
659}
660
6aae48ff 661/**
a8605ea2 662 * mei_hbuf_acquire - try to acquire host buffer
6aae48ff
TW
663 *
664 * @dev: the device structure
a8605ea2 665 * Return: true if host buffer was acquired
6aae48ff
TW
666 */
667bool mei_hbuf_acquire(struct mei_device *dev)
668{
04bb139a 669 if (mei_pg_state(dev) == MEI_PG_ON ||
3dc196ea 670 mei_pg_in_transition(dev)) {
2bf94cab 671 dev_dbg(dev->dev, "device is in pg\n");
04bb139a
TW
672 return false;
673 }
674
6aae48ff 675 if (!dev->hbuf_is_ready) {
2bf94cab 676 dev_dbg(dev->dev, "hbuf is not ready\n");
6aae48ff
TW
677 return false;
678 }
679
680 dev->hbuf_is_ready = false;
681
682 return true;
683}
9ca9050b 684
a4307fe4
AU
685/**
686 * mei_cl_wake_all - wake up readers, writers and event waiters so
687 * they can be interrupted
688 *
689 * @cl: host client
690 */
691static void mei_cl_wake_all(struct mei_cl *cl)
692{
693 struct mei_device *dev = cl->dev;
694
695 /* synchronized under device mutex */
696 if (waitqueue_active(&cl->rx_wait)) {
697 cl_dbg(dev, cl, "Waking up reading client!\n");
698 wake_up_interruptible(&cl->rx_wait);
699 }
700 /* synchronized under device mutex */
701 if (waitqueue_active(&cl->tx_wait)) {
702 cl_dbg(dev, cl, "Waking up writing client!\n");
703 wake_up_interruptible(&cl->tx_wait);
704 }
705 /* synchronized under device mutex */
706 if (waitqueue_active(&cl->ev_wait)) {
707 cl_dbg(dev, cl, "Waking up waiting for event clients!\n");
708 wake_up_interruptible(&cl->ev_wait);
709 }
7ff4bdd4
AU
710 /* synchronized under device mutex */
711 if (waitqueue_active(&cl->wait)) {
712 cl_dbg(dev, cl, "Waking up ctrl write clients!\n");
69f1804a 713 wake_up(&cl->wait);
7ff4bdd4 714 }
a4307fe4
AU
715}
716
3c666182
TW
717/**
718 * mei_cl_set_disconnected - set disconnected state and clear
719 * associated states and resources
720 *
721 * @cl: host client
722 */
723void mei_cl_set_disconnected(struct mei_cl *cl)
724{
725 struct mei_device *dev = cl->dev;
726
727 if (cl->state == MEI_FILE_DISCONNECTED ||
728 cl->state == MEI_FILE_INITIALIZING)
729 return;
730
731 cl->state = MEI_FILE_DISCONNECTED;
a4307fe4
AU
732 mei_io_list_free(&dev->write_list, cl);
733 mei_io_list_free(&dev->write_waiting_list, cl);
3c666182
TW
734 mei_io_list_flush(&dev->ctrl_rd_list, cl);
735 mei_io_list_flush(&dev->ctrl_wr_list, cl);
a4307fe4 736 mei_cl_wake_all(cl);
3c666182
TW
737 cl->mei_flow_ctrl_creds = 0;
738 cl->timer_count = 0;
d49ed64a 739
a03d77f6
AU
740 if (!cl->me_cl)
741 return;
742
743 if (!WARN_ON(cl->me_cl->connect_count == 0))
744 cl->me_cl->connect_count--;
745
c241e9b1
AU
746 if (cl->me_cl->connect_count == 0)
747 cl->me_cl->mei_flow_ctrl_creds = 0;
748
d49ed64a
AU
749 mei_me_cl_put(cl->me_cl);
750 cl->me_cl = NULL;
3c666182
TW
751}
752
a03d77f6
AU
753static int mei_cl_set_connecting(struct mei_cl *cl, struct mei_me_client *me_cl)
754{
1df629ef 755 if (!mei_me_cl_get(me_cl))
a03d77f6
AU
756 return -ENOENT;
757
1df629ef
AU
758 /* only one connection is allowed for fixed address clients */
759 if (me_cl->props.fixed_address) {
760 if (me_cl->connect_count) {
761 mei_me_cl_put(me_cl);
762 return -EBUSY;
763 }
764 }
765
766 cl->me_cl = me_cl;
a03d77f6
AU
767 cl->state = MEI_FILE_CONNECTING;
768 cl->me_cl->connect_count++;
769
770 return 0;
771}
772
3c666182
TW
773/*
774 * mei_cl_send_disconnect - send disconnect request
775 *
776 * @cl: host client
777 * @cb: callback block
778 *
779 * Return: 0, OK; otherwise, error.
780 */
781static int mei_cl_send_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb)
782{
783 struct mei_device *dev;
784 int ret;
785
786 dev = cl->dev;
787
788 ret = mei_hbm_cl_disconnect_req(dev, cl);
789 cl->status = ret;
790 if (ret) {
791 cl->state = MEI_FILE_DISCONNECT_REPLY;
792 return ret;
793 }
794
795 list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
796 cl->timer_count = MEI_CONNECT_TIMEOUT;
797
798 return 0;
799}
800
801/**
802 * mei_cl_irq_disconnect - processes close related operation from
803 * interrupt thread context - send disconnect request
804 *
805 * @cl: client
806 * @cb: callback block.
807 * @cmpl_list: complete list.
808 *
809 * Return: 0, OK; otherwise, error.
810 */
811int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
812 struct mei_cl_cb *cmpl_list)
813{
814 struct mei_device *dev = cl->dev;
815 u32 msg_slots;
816 int slots;
817 int ret;
818
819 msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
820 slots = mei_hbuf_empty_slots(dev);
821
822 if (slots < msg_slots)
823 return -EMSGSIZE;
824
825 ret = mei_cl_send_disconnect(cl, cb);
826 if (ret)
827 list_move_tail(&cb->list, &cmpl_list->list);
828
829 return ret;
830}
831
9ca9050b 832/**
18901357
AU
833 * __mei_cl_disconnect - disconnect host client from the me one
834 * internal function runtime pm has to be already acquired
9ca9050b 835 *
90e0b5f1 836 * @cl: host client
9ca9050b 837 *
a8605ea2 838 * Return: 0 on success, <0 on failure.
9ca9050b 839 */
18901357 840static int __mei_cl_disconnect(struct mei_cl *cl)
9ca9050b 841{
90e0b5f1 842 struct mei_device *dev;
9ca9050b 843 struct mei_cl_cb *cb;
fe2f17eb 844 int rets;
9ca9050b 845
90e0b5f1
TW
846 dev = cl->dev;
847
3c666182
TW
848 cl->state = MEI_FILE_DISCONNECTING;
849
bca67d68
TW
850 cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT, NULL);
851 rets = cb ? 0 : -ENOMEM;
852 if (rets)
3c666182
TW
853 goto out;
854
855 cl_dbg(dev, cl, "add disconnect cb to control write list\n");
856 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
5a8373fb 857
6aae48ff 858 if (mei_hbuf_acquire(dev)) {
3c666182
TW
859 rets = mei_cl_send_disconnect(cl, cb);
860 if (rets) {
c0abffbd 861 cl_err(dev, cl, "failed to disconnect.\n");
3c666182 862 goto out;
9ca9050b 863 }
9ca9050b 864 }
9ca9050b 865
3c666182 866 mutex_unlock(&dev->device_lock);
7ff4bdd4
AU
867 wait_event_timeout(cl->wait,
868 cl->state == MEI_FILE_DISCONNECT_REPLY ||
869 cl->state == MEI_FILE_DISCONNECTED,
3c666182 870 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
9ca9050b 871 mutex_lock(&dev->device_lock);
fe2f17eb 872
3c666182 873 rets = cl->status;
7ff4bdd4
AU
874 if (cl->state != MEI_FILE_DISCONNECT_REPLY &&
875 cl->state != MEI_FILE_DISCONNECTED) {
fe2f17eb
AU
876 cl_dbg(dev, cl, "timeout on disconnect from FW client.\n");
877 rets = -ETIME;
9ca9050b
TW
878 }
879
3c666182
TW
880out:
881 /* we disconnect also on error */
882 mei_cl_set_disconnected(cl);
883 if (!rets)
884 cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
885
18901357
AU
886 mei_io_cb_free(cb);
887 return rets;
888}
889
890/**
891 * mei_cl_disconnect - disconnect host client from the me one
892 *
893 * @cl: host client
894 *
895 * Locking: called under "dev->device_lock" lock
896 *
897 * Return: 0 on success, <0 on failure.
898 */
899int mei_cl_disconnect(struct mei_cl *cl)
900{
901 struct mei_device *dev;
902 int rets;
903
904 if (WARN_ON(!cl || !cl->dev))
905 return -ENODEV;
906
907 dev = cl->dev;
908
909 cl_dbg(dev, cl, "disconnecting");
910
911 if (!mei_cl_is_connected(cl))
912 return 0;
913
914 if (mei_cl_is_fixed_address(cl)) {
915 mei_cl_set_disconnected(cl);
916 return 0;
917 }
918
919 rets = pm_runtime_get(dev->dev);
920 if (rets < 0 && rets != -EINPROGRESS) {
921 pm_runtime_put_noidle(dev->dev);
922 cl_err(dev, cl, "rpm: get failed %d\n", rets);
923 return rets;
924 }
925
926 rets = __mei_cl_disconnect(cl);
927
04bb139a 928 cl_dbg(dev, cl, "rpm: autosuspend\n");
2bf94cab
TW
929 pm_runtime_mark_last_busy(dev->dev);
930 pm_runtime_put_autosuspend(dev->dev);
04bb139a 931
9ca9050b
TW
932 return rets;
933}
934
935
936/**
90e0b5f1
TW
937 * mei_cl_is_other_connecting - checks if other
938 * client with the same me client id is connecting
9ca9050b 939 *
9ca9050b
TW
940 * @cl: private data of the file object
941 *
a8605ea2 942 * Return: true if other client is connected, false - otherwise.
9ca9050b 943 */
0c53357c 944static bool mei_cl_is_other_connecting(struct mei_cl *cl)
9ca9050b 945{
90e0b5f1 946 struct mei_device *dev;
0c53357c 947 struct mei_cl_cb *cb;
90e0b5f1
TW
948
949 dev = cl->dev;
950
0c53357c
TW
951 list_for_each_entry(cb, &dev->ctrl_rd_list.list, list) {
952 if (cb->fop_type == MEI_FOP_CONNECT &&
d49ed64a 953 mei_cl_me_id(cl) == mei_cl_me_id(cb->cl))
90e0b5f1 954 return true;
9ca9050b 955 }
90e0b5f1
TW
956
957 return false;
9ca9050b
TW
958}
959
0c53357c
TW
960/**
961 * mei_cl_send_connect - send connect request
962 *
963 * @cl: host client
964 * @cb: callback block
965 *
966 * Return: 0, OK; otherwise, error.
967 */
968static int mei_cl_send_connect(struct mei_cl *cl, struct mei_cl_cb *cb)
969{
970 struct mei_device *dev;
971 int ret;
972
973 dev = cl->dev;
974
975 ret = mei_hbm_cl_connect_req(dev, cl);
976 cl->status = ret;
977 if (ret) {
978 cl->state = MEI_FILE_DISCONNECT_REPLY;
979 return ret;
980 }
981
982 list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
983 cl->timer_count = MEI_CONNECT_TIMEOUT;
984 return 0;
985}
986
987/**
988 * mei_cl_irq_connect - send connect request in irq_thread context
989 *
990 * @cl: host client
991 * @cb: callback block
992 * @cmpl_list: complete list
993 *
994 * Return: 0, OK; otherwise, error.
995 */
996int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
997 struct mei_cl_cb *cmpl_list)
998{
999 struct mei_device *dev = cl->dev;
1000 u32 msg_slots;
1001 int slots;
1002 int rets;
1003
1004 msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
1005 slots = mei_hbuf_empty_slots(dev);
1006
1007 if (mei_cl_is_other_connecting(cl))
1008 return 0;
1009
1010 if (slots < msg_slots)
1011 return -EMSGSIZE;
1012
1013 rets = mei_cl_send_connect(cl, cb);
1014 if (rets)
1015 list_move_tail(&cb->list, &cmpl_list->list);
1016
1017 return rets;
1018}
1019
9f81abda 1020/**
83ce0741 1021 * mei_cl_connect - connect host client to the me one
9f81abda
TW
1022 *
1023 * @cl: host client
d49ed64a 1024 * @me_cl: me client
a8605ea2 1025 * @file: pointer to file structure
9f81abda
TW
1026 *
1027 * Locking: called under "dev->device_lock" lock
1028 *
a8605ea2 1029 * Return: 0 on success, <0 on failure.
9f81abda 1030 */
d49ed64a 1031int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
f23e2cc4 1032 const struct file *file)
9f81abda
TW
1033{
1034 struct mei_device *dev;
1035 struct mei_cl_cb *cb;
9f81abda
TW
1036 int rets;
1037
1df629ef 1038 if (WARN_ON(!cl || !cl->dev || !me_cl))
9f81abda
TW
1039 return -ENODEV;
1040
1041 dev = cl->dev;
1042
1df629ef
AU
1043 rets = mei_cl_set_connecting(cl, me_cl);
1044 if (rets)
1045 return rets;
1046
1047 if (mei_cl_is_fixed_address(cl)) {
1048 cl->state = MEI_FILE_CONNECTED;
1049 return 0;
1050 }
1051
2bf94cab 1052 rets = pm_runtime_get(dev->dev);
04bb139a 1053 if (rets < 0 && rets != -EINPROGRESS) {
2bf94cab 1054 pm_runtime_put_noidle(dev->dev);
04bb139a 1055 cl_err(dev, cl, "rpm: get failed %d\n", rets);
1df629ef 1056 goto nortpm;
04bb139a
TW
1057 }
1058
bca67d68
TW
1059 cb = mei_io_cb_init(cl, MEI_FOP_CONNECT, file);
1060 rets = cb ? 0 : -ENOMEM;
1061 if (rets)
9f81abda 1062 goto out;
9f81abda 1063
0c53357c
TW
1064 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
1065
6aae48ff
TW
1066 /* run hbuf acquire last so we don't have to undo */
1067 if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
0c53357c
TW
1068 rets = mei_cl_send_connect(cl, cb);
1069 if (rets)
9f81abda 1070 goto out;
9f81abda
TW
1071 }
1072
1073 mutex_unlock(&dev->device_lock);
12f45ed4 1074 wait_event_timeout(cl->wait,
285e2996 1075 (cl->state == MEI_FILE_CONNECTED ||
7ff4bdd4 1076 cl->state == MEI_FILE_DISCONNECTED ||
18901357 1077 cl->state == MEI_FILE_DISCONNECT_REQUIRED ||
3c666182 1078 cl->state == MEI_FILE_DISCONNECT_REPLY),
285e2996 1079 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
9f81abda
TW
1080 mutex_lock(&dev->device_lock);
1081
f3de9b63 1082 if (!mei_cl_is_connected(cl)) {
18901357
AU
1083 if (cl->state == MEI_FILE_DISCONNECT_REQUIRED) {
1084 mei_io_list_flush(&dev->ctrl_rd_list, cl);
1085 mei_io_list_flush(&dev->ctrl_wr_list, cl);
1086 /* ignore disconnect return valuue;
1087 * in case of failure reset will be invoked
1088 */
1089 __mei_cl_disconnect(cl);
1090 rets = -EFAULT;
1091 goto out;
1092 }
1093
0c53357c 1094 /* timeout or something went really wrong */
285e2996
AU
1095 if (!cl->status)
1096 cl->status = -EFAULT;
9f81abda
TW
1097 }
1098
1099 rets = cl->status;
9f81abda 1100out:
04bb139a 1101 cl_dbg(dev, cl, "rpm: autosuspend\n");
2bf94cab
TW
1102 pm_runtime_mark_last_busy(dev->dev);
1103 pm_runtime_put_autosuspend(dev->dev);
04bb139a 1104
9f81abda 1105 mei_io_cb_free(cb);
0c53357c 1106
1df629ef 1107nortpm:
0c53357c
TW
1108 if (!mei_cl_is_connected(cl))
1109 mei_cl_set_disconnected(cl);
1110
9f81abda
TW
1111 return rets;
1112}
1113
03b8d341
TW
1114/**
1115 * mei_cl_alloc_linked - allocate and link host client
1116 *
1117 * @dev: the device structure
03b8d341
TW
1118 *
1119 * Return: cl on success ERR_PTR on failure
1120 */
7851e008 1121struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev)
03b8d341
TW
1122{
1123 struct mei_cl *cl;
1124 int ret;
1125
1126 cl = mei_cl_allocate(dev);
1127 if (!cl) {
1128 ret = -ENOMEM;
1129 goto err;
1130 }
1131
7851e008 1132 ret = mei_cl_link(cl);
03b8d341
TW
1133 if (ret)
1134 goto err;
1135
1136 return cl;
1137err:
1138 kfree(cl);
1139 return ERR_PTR(ret);
1140}
1141
1142
1143
9ca9050b 1144/**
90e0b5f1 1145 * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
9ca9050b 1146 *
06ee536b 1147 * @cl: host client
9ca9050b 1148 *
a8605ea2 1149 * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
9ca9050b 1150 */
a808c80c 1151static int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
9ca9050b 1152{
d49ed64a 1153 if (WARN_ON(!cl || !cl->me_cl))
90e0b5f1
TW
1154 return -EINVAL;
1155
9ca9050b
TW
1156 if (cl->mei_flow_ctrl_creds > 0)
1157 return 1;
1158
a808c80c 1159 if (mei_cl_is_fixed_address(cl))
1df629ef 1160 return 1;
1df629ef 1161
d49ed64a
AU
1162 if (mei_cl_is_single_recv_buf(cl)) {
1163 if (cl->me_cl->mei_flow_ctrl_creds > 0)
1164 return 1;
9ca9050b 1165 }
d49ed64a 1166 return 0;
9ca9050b
TW
1167}
1168
1169/**
90e0b5f1 1170 * mei_cl_flow_ctrl_reduce - reduces flow_control.
9ca9050b 1171 *
9ca9050b 1172 * @cl: private data of the file object
393b148f 1173 *
a8605ea2 1174 * Return:
9ca9050b 1175 * 0 on success
9ca9050b
TW
1176 * -EINVAL when ctrl credits are <= 0
1177 */
fdd9b865 1178static int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
9ca9050b 1179{
d49ed64a 1180 if (WARN_ON(!cl || !cl->me_cl))
90e0b5f1
TW
1181 return -EINVAL;
1182
1df629ef
AU
1183 if (mei_cl_is_fixed_address(cl))
1184 return 0;
1185
d49ed64a
AU
1186 if (mei_cl_is_single_recv_buf(cl)) {
1187 if (WARN_ON(cl->me_cl->mei_flow_ctrl_creds <= 0))
1188 return -EINVAL;
1189 cl->me_cl->mei_flow_ctrl_creds--;
12d00665 1190 } else {
d49ed64a
AU
1191 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
1192 return -EINVAL;
12d00665 1193 cl->mei_flow_ctrl_creds--;
9ca9050b 1194 }
d49ed64a 1195 return 0;
9ca9050b
TW
1196}
1197
51678ccb
TW
1198/**
1199 * mei_cl_notify_fop2req - convert fop to proper request
1200 *
1201 * @fop: client notification start response command
1202 *
1203 * Return: MEI_HBM_NOTIFICATION_START/STOP
1204 */
1205u8 mei_cl_notify_fop2req(enum mei_cb_file_ops fop)
1206{
1207 if (fop == MEI_FOP_NOTIFY_START)
1208 return MEI_HBM_NOTIFICATION_START;
1209 else
1210 return MEI_HBM_NOTIFICATION_STOP;
1211}
1212
1213/**
1214 * mei_cl_notify_req2fop - convert notification request top file operation type
1215 *
1216 * @req: hbm notification request type
1217 *
1218 * Return: MEI_FOP_NOTIFY_START/STOP
1219 */
1220enum mei_cb_file_ops mei_cl_notify_req2fop(u8 req)
1221{
1222 if (req == MEI_HBM_NOTIFICATION_START)
1223 return MEI_FOP_NOTIFY_START;
1224 else
1225 return MEI_FOP_NOTIFY_STOP;
1226}
1227
1228/**
1229 * mei_cl_irq_notify - send notification request in irq_thread context
1230 *
1231 * @cl: client
1232 * @cb: callback block.
1233 * @cmpl_list: complete list.
1234 *
1235 * Return: 0 on such and error otherwise.
1236 */
1237int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
1238 struct mei_cl_cb *cmpl_list)
1239{
1240 struct mei_device *dev = cl->dev;
1241 u32 msg_slots;
1242 int slots;
1243 int ret;
1244 bool request;
1245
1246 msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
1247 slots = mei_hbuf_empty_slots(dev);
1248
1249 if (slots < msg_slots)
1250 return -EMSGSIZE;
1251
1252 request = mei_cl_notify_fop2req(cb->fop_type);
1253 ret = mei_hbm_cl_notify_req(dev, cl, request);
1254 if (ret) {
1255 cl->status = ret;
1256 list_move_tail(&cb->list, &cmpl_list->list);
1257 return ret;
1258 }
1259
1260 list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
1261 return 0;
1262}
1263
1264/**
1265 * mei_cl_notify_request - send notification stop/start request
1266 *
1267 * @cl: host client
1268 * @file: associate request with file
1269 * @request: 1 for start or 0 for stop
1270 *
1271 * Locking: called under "dev->device_lock" lock
1272 *
1273 * Return: 0 on such and error otherwise.
1274 */
f23e2cc4
TW
1275int mei_cl_notify_request(struct mei_cl *cl,
1276 const struct file *file, u8 request)
51678ccb
TW
1277{
1278 struct mei_device *dev;
1279 struct mei_cl_cb *cb;
1280 enum mei_cb_file_ops fop_type;
1281 int rets;
1282
1283 if (WARN_ON(!cl || !cl->dev))
1284 return -ENODEV;
1285
1286 dev = cl->dev;
1287
1288 if (!dev->hbm_f_ev_supported) {
1289 cl_dbg(dev, cl, "notifications not supported\n");
1290 return -EOPNOTSUPP;
1291 }
1292
1293 rets = pm_runtime_get(dev->dev);
1294 if (rets < 0 && rets != -EINPROGRESS) {
1295 pm_runtime_put_noidle(dev->dev);
1296 cl_err(dev, cl, "rpm: get failed %d\n", rets);
1297 return rets;
1298 }
1299
1300 fop_type = mei_cl_notify_req2fop(request);
1301 cb = mei_io_cb_init(cl, fop_type, file);
1302 if (!cb) {
1303 rets = -ENOMEM;
1304 goto out;
1305 }
1306
1307 if (mei_hbuf_acquire(dev)) {
1308 if (mei_hbm_cl_notify_req(dev, cl, request)) {
1309 rets = -ENODEV;
1310 goto out;
1311 }
1312 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
1313 } else {
1314 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
1315 }
1316
1317 mutex_unlock(&dev->device_lock);
7ff4bdd4
AU
1318 wait_event_timeout(cl->wait,
1319 cl->notify_en == request || !mei_cl_is_connected(cl),
1320 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
51678ccb
TW
1321 mutex_lock(&dev->device_lock);
1322
4a8eaa96
AU
1323 if (cl->notify_en != request && !cl->status)
1324 cl->status = -EFAULT;
51678ccb
TW
1325
1326 rets = cl->status;
1327
1328out:
1329 cl_dbg(dev, cl, "rpm: autosuspend\n");
1330 pm_runtime_mark_last_busy(dev->dev);
1331 pm_runtime_put_autosuspend(dev->dev);
1332
1333 mei_io_cb_free(cb);
1334 return rets;
1335}
1336
237092bf
TW
1337/**
1338 * mei_cl_notify - raise notification
1339 *
1340 * @cl: host client
1341 *
1342 * Locking: called under "dev->device_lock" lock
1343 */
1344void mei_cl_notify(struct mei_cl *cl)
1345{
1346 struct mei_device *dev;
1347
1348 if (!cl || !cl->dev)
1349 return;
1350
1351 dev = cl->dev;
1352
1353 if (!cl->notify_en)
1354 return;
1355
1356 cl_dbg(dev, cl, "notify event");
1357 cl->notify_ev = true;
850f8940
TW
1358 if (!mei_cl_bus_notify_event(cl))
1359 wake_up_interruptible(&cl->ev_wait);
237092bf
TW
1360
1361 if (cl->ev_async)
1362 kill_fasync(&cl->ev_async, SIGIO, POLL_PRI);
bb2ef9c3 1363
237092bf
TW
1364}
1365
b38a362f
TW
1366/**
1367 * mei_cl_notify_get - get or wait for notification event
1368 *
1369 * @cl: host client
1370 * @block: this request is blocking
1371 * @notify_ev: true if notification event was received
1372 *
1373 * Locking: called under "dev->device_lock" lock
1374 *
1375 * Return: 0 on such and error otherwise.
1376 */
1377int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev)
1378{
1379 struct mei_device *dev;
1380 int rets;
1381
1382 *notify_ev = false;
1383
1384 if (WARN_ON(!cl || !cl->dev))
1385 return -ENODEV;
1386
1387 dev = cl->dev;
1388
1389 if (!mei_cl_is_connected(cl))
1390 return -ENODEV;
1391
1392 if (cl->notify_ev)
1393 goto out;
1394
1395 if (!block)
1396 return -EAGAIN;
1397
1398 mutex_unlock(&dev->device_lock);
1399 rets = wait_event_interruptible(cl->ev_wait, cl->notify_ev);
1400 mutex_lock(&dev->device_lock);
1401
1402 if (rets < 0)
1403 return rets;
1404
1405out:
1406 *notify_ev = cl->notify_ev;
1407 cl->notify_ev = false;
1408 return 0;
1409}
1410
13cf9885
AU
1411/**
1412 * mei_cl_is_read_fc_cb - check if read cb is waiting for flow control
1413 * for given host client
1414 *
1415 * @cl: host client
1416 *
1417 * Return: true, if found at least one cb.
1418 */
1419static bool mei_cl_is_read_fc_cb(struct mei_cl *cl)
1420{
1421 struct mei_device *dev = cl->dev;
1422 struct mei_cl_cb *cb;
1423
1424 list_for_each_entry(cb, &dev->ctrl_wr_list.list, list)
1425 if (cb->fop_type == MEI_FOP_READ && cb->cl == cl)
1426 return true;
1427 return false;
1428}
1429
ab841160 1430/**
393b148f 1431 * mei_cl_read_start - the start read client message function.
ab841160 1432 *
90e0b5f1 1433 * @cl: host client
ce23139c 1434 * @length: number of bytes to read
bca67d68 1435 * @fp: pointer to file structure
ab841160 1436 *
a8605ea2 1437 * Return: 0 on success, <0 on failure.
ab841160 1438 */
f23e2cc4 1439int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
ab841160 1440{
90e0b5f1 1441 struct mei_device *dev;
ab841160 1442 struct mei_cl_cb *cb;
664df38b 1443 int rets;
ab841160 1444
90e0b5f1
TW
1445 if (WARN_ON(!cl || !cl->dev))
1446 return -ENODEV;
1447
1448 dev = cl->dev;
1449
b950ac1d 1450 if (!mei_cl_is_connected(cl))
ab841160
OW
1451 return -ENODEV;
1452
a9bed610 1453 /* HW currently supports only one pending read */
13cf9885 1454 if (!list_empty(&cl->rd_pending) || mei_cl_is_read_fc_cb(cl))
ab841160 1455 return -EBUSY;
a9bed610 1456
d49ed64a
AU
1457 if (!mei_me_cl_is_active(cl->me_cl)) {
1458 cl_err(dev, cl, "no such me client\n");
7ca96aa2 1459 return -ENOTTY;
664df38b 1460 }
1df629ef 1461
79563db9 1462 /* always allocate at least client max message */
d49ed64a 1463 length = max_t(size_t, length, mei_cl_mtu(cl));
1df629ef
AU
1464 cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp);
1465 if (!cb)
1466 return -ENOMEM;
1467
1468 if (mei_cl_is_fixed_address(cl)) {
1469 list_add_tail(&cb->list, &cl->rd_pending);
1470 return 0;
1471 }
ab841160 1472
2bf94cab 1473 rets = pm_runtime_get(dev->dev);
04bb139a 1474 if (rets < 0 && rets != -EINPROGRESS) {
2bf94cab 1475 pm_runtime_put_noidle(dev->dev);
04bb139a 1476 cl_err(dev, cl, "rpm: get failed %d\n", rets);
1df629ef 1477 goto nortpm;
04bb139a
TW
1478 }
1479
6aae48ff 1480 if (mei_hbuf_acquire(dev)) {
86113500
AU
1481 rets = mei_hbm_cl_flow_control_req(dev, cl);
1482 if (rets < 0)
04bb139a 1483 goto out;
04bb139a 1484
a9bed610 1485 list_add_tail(&cb->list, &cl->rd_pending);
ab841160 1486 } else {
1df629ef 1487 rets = 0;
fb601adb 1488 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
ab841160 1489 }
accb884b 1490
04bb139a
TW
1491out:
1492 cl_dbg(dev, cl, "rpm: autosuspend\n");
2bf94cab
TW
1493 pm_runtime_mark_last_busy(dev->dev);
1494 pm_runtime_put_autosuspend(dev->dev);
1df629ef 1495nortpm:
04bb139a
TW
1496 if (rets)
1497 mei_io_cb_free(cb);
1498
ab841160
OW
1499 return rets;
1500}
1501
21767546 1502/**
9d098192 1503 * mei_cl_irq_write - write a message to device
21767546
TW
1504 * from the interrupt thread context
1505 *
1506 * @cl: client
1507 * @cb: callback block.
21767546
TW
1508 * @cmpl_list: complete list.
1509 *
a8605ea2 1510 * Return: 0, OK; otherwise error.
21767546 1511 */
9d098192
TW
1512int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
1513 struct mei_cl_cb *cmpl_list)
21767546 1514{
136698e5
TW
1515 struct mei_device *dev;
1516 struct mei_msg_data *buf;
21767546 1517 struct mei_msg_hdr mei_hdr;
136698e5
TW
1518 size_t len;
1519 u32 msg_slots;
9d098192 1520 int slots;
2ebf8c94 1521 int rets;
b8b73035 1522 bool first_chunk;
21767546 1523
136698e5
TW
1524 if (WARN_ON(!cl || !cl->dev))
1525 return -ENODEV;
1526
1527 dev = cl->dev;
1528
5db7514d 1529 buf = &cb->buf;
136698e5 1530
b8b73035
AU
1531 first_chunk = cb->buf_idx == 0;
1532
a808c80c 1533 rets = first_chunk ? mei_cl_flow_ctrl_creds(cl) : 1;
136698e5
TW
1534 if (rets < 0)
1535 return rets;
1536
1537 if (rets == 0) {
04bb139a 1538 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
136698e5
TW
1539 return 0;
1540 }
1541
9d098192 1542 slots = mei_hbuf_empty_slots(dev);
136698e5
TW
1543 len = buf->size - cb->buf_idx;
1544 msg_slots = mei_data2slots(len);
1545
1df629ef 1546 mei_hdr.host_addr = mei_cl_host_addr(cl);
d49ed64a 1547 mei_hdr.me_addr = mei_cl_me_id(cl);
21767546 1548 mei_hdr.reserved = 0;
479327fc 1549 mei_hdr.internal = cb->internal;
21767546 1550
9d098192 1551 if (slots >= msg_slots) {
21767546
TW
1552 mei_hdr.length = len;
1553 mei_hdr.msg_complete = 1;
1554 /* Split the message only if we can write the whole host buffer */
9d098192
TW
1555 } else if (slots == dev->hbuf_depth) {
1556 msg_slots = slots;
1557 len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
21767546
TW
1558 mei_hdr.length = len;
1559 mei_hdr.msg_complete = 0;
1560 } else {
1561 /* wait for next time the host buffer is empty */
1562 return 0;
1563 }
1564
35bf7692 1565 cl_dbg(dev, cl, "buf: size = %zu idx = %zu\n",
5db7514d 1566 cb->buf.size, cb->buf_idx);
21767546 1567
136698e5 1568 rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
2ebf8c94
TW
1569 if (rets) {
1570 cl->status = rets;
21767546 1571 list_move_tail(&cb->list, &cmpl_list->list);
2ebf8c94 1572 return rets;
21767546
TW
1573 }
1574
1575 cl->status = 0;
4dfaa9f7 1576 cl->writing_state = MEI_WRITING;
21767546 1577 cb->buf_idx += mei_hdr.length;
8660172e 1578 cb->completed = mei_hdr.msg_complete == 1;
4dfaa9f7 1579
b8b73035 1580 if (first_chunk) {
21767546 1581 if (mei_cl_flow_ctrl_reduce(cl))
2ebf8c94 1582 return -EIO;
21767546
TW
1583 }
1584
b8b73035
AU
1585 if (mei_hdr.msg_complete)
1586 list_move_tail(&cb->list, &dev->write_waiting_list.list);
1587
21767546
TW
1588 return 0;
1589}
1590
4234a6de
TW
1591/**
1592 * mei_cl_write - submit a write cb to mei device
a8605ea2 1593 * assumes device_lock is locked
4234a6de
TW
1594 *
1595 * @cl: host client
a8605ea2 1596 * @cb: write callback with filled data
ce23139c 1597 * @blocking: block until completed
4234a6de 1598 *
a8605ea2 1599 * Return: number of bytes sent on success, <0 on failure.
4234a6de
TW
1600 */
1601int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
1602{
1603 struct mei_device *dev;
1604 struct mei_msg_data *buf;
1605 struct mei_msg_hdr mei_hdr;
23253c31 1606 int size;
4234a6de
TW
1607 int rets;
1608
1609
1610 if (WARN_ON(!cl || !cl->dev))
1611 return -ENODEV;
1612
1613 if (WARN_ON(!cb))
1614 return -EINVAL;
1615
1616 dev = cl->dev;
1617
5db7514d 1618 buf = &cb->buf;
23253c31 1619 size = buf->size;
4234a6de 1620
23253c31 1621 cl_dbg(dev, cl, "size=%d\n", size);
4234a6de 1622
2bf94cab 1623 rets = pm_runtime_get(dev->dev);
04bb139a 1624 if (rets < 0 && rets != -EINPROGRESS) {
2bf94cab 1625 pm_runtime_put_noidle(dev->dev);
04bb139a 1626 cl_err(dev, cl, "rpm: get failed %d\n", rets);
6cbb097f 1627 goto free;
04bb139a 1628 }
4234a6de 1629
6aae48ff
TW
1630 cb->buf_idx = 0;
1631 cl->writing_state = MEI_IDLE;
1632
1df629ef 1633 mei_hdr.host_addr = mei_cl_host_addr(cl);
d49ed64a 1634 mei_hdr.me_addr = mei_cl_me_id(cl);
6aae48ff
TW
1635 mei_hdr.reserved = 0;
1636 mei_hdr.msg_complete = 0;
1637 mei_hdr.internal = cb->internal;
4234a6de 1638
a808c80c 1639 rets = mei_cl_flow_ctrl_creds(cl);
4234a6de
TW
1640 if (rets < 0)
1641 goto err;
1642
6aae48ff
TW
1643 if (rets == 0) {
1644 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
23253c31 1645 rets = size;
6aae48ff
TW
1646 goto out;
1647 }
1648 if (!mei_hbuf_acquire(dev)) {
1649 cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
23253c31 1650 rets = size;
4234a6de
TW
1651 goto out;
1652 }
4234a6de
TW
1653
1654 /* Check for a maximum length */
23253c31 1655 if (size > mei_hbuf_max_len(dev)) {
4234a6de
TW
1656 mei_hdr.length = mei_hbuf_max_len(dev);
1657 mei_hdr.msg_complete = 0;
1658 } else {
23253c31 1659 mei_hdr.length = size;
4234a6de
TW
1660 mei_hdr.msg_complete = 1;
1661 }
1662
2ebf8c94
TW
1663 rets = mei_write_message(dev, &mei_hdr, buf->data);
1664 if (rets)
4234a6de 1665 goto err;
4234a6de 1666
b8b73035
AU
1667 rets = mei_cl_flow_ctrl_reduce(cl);
1668 if (rets)
1669 goto err;
1670
4234a6de
TW
1671 cl->writing_state = MEI_WRITING;
1672 cb->buf_idx = mei_hdr.length;
8660172e 1673 cb->completed = mei_hdr.msg_complete == 1;
4234a6de 1674
4234a6de 1675out:
b8b73035 1676 if (mei_hdr.msg_complete)
4234a6de 1677 list_add_tail(&cb->list, &dev->write_waiting_list.list);
b8b73035 1678 else
4234a6de 1679 list_add_tail(&cb->list, &dev->write_list.list);
4234a6de 1680
23253c31 1681 cb = NULL;
4234a6de
TW
1682 if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
1683
1684 mutex_unlock(&dev->device_lock);
7ca96aa2 1685 rets = wait_event_interruptible(cl->tx_wait,
0faf6a3b
AU
1686 cl->writing_state == MEI_WRITE_COMPLETE ||
1687 (!mei_cl_is_connected(cl)));
4234a6de 1688 mutex_lock(&dev->device_lock);
7ca96aa2
AU
1689 /* wait_event_interruptible returns -ERESTARTSYS */
1690 if (rets) {
1691 if (signal_pending(current))
1692 rets = -EINTR;
1693 goto err;
1694 }
0faf6a3b
AU
1695 if (cl->writing_state != MEI_WRITE_COMPLETE) {
1696 rets = -EFAULT;
1697 goto err;
1698 }
4234a6de 1699 }
7ca96aa2 1700
23253c31 1701 rets = size;
4234a6de 1702err:
04bb139a 1703 cl_dbg(dev, cl, "rpm: autosuspend\n");
2bf94cab
TW
1704 pm_runtime_mark_last_busy(dev->dev);
1705 pm_runtime_put_autosuspend(dev->dev);
6cbb097f
AU
1706free:
1707 mei_io_cb_free(cb);
04bb139a 1708
4234a6de
TW
1709 return rets;
1710}
1711
1712
db086fa9
TW
1713/**
1714 * mei_cl_complete - processes completed operation for a client
1715 *
1716 * @cl: private data of the file object.
1717 * @cb: callback block.
1718 */
1719void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
1720{
a1809d38
AU
1721 struct mei_device *dev = cl->dev;
1722
3c666182
TW
1723 switch (cb->fop_type) {
1724 case MEI_FOP_WRITE:
db086fa9 1725 mei_io_cb_free(cb);
db086fa9 1726 cl->writing_state = MEI_WRITE_COMPLETE;
a1809d38 1727 if (waitqueue_active(&cl->tx_wait)) {
db086fa9 1728 wake_up_interruptible(&cl->tx_wait);
a1809d38
AU
1729 } else {
1730 pm_runtime_mark_last_busy(dev->dev);
1731 pm_request_autosuspend(dev->dev);
1732 }
3c666182 1733 break;
db086fa9 1734
3c666182 1735 case MEI_FOP_READ:
a9bed610 1736 list_add_tail(&cb->list, &cl->rd_completed);
a1f9ae2b
TW
1737 if (!mei_cl_bus_rx_event(cl))
1738 wake_up_interruptible(&cl->rx_wait);
3c666182
TW
1739 break;
1740
1741 case MEI_FOP_CONNECT:
1742 case MEI_FOP_DISCONNECT:
51678ccb
TW
1743 case MEI_FOP_NOTIFY_STOP:
1744 case MEI_FOP_NOTIFY_START:
3c666182
TW
1745 if (waitqueue_active(&cl->wait))
1746 wake_up(&cl->wait);
db086fa9 1747
6a8d648c
AU
1748 break;
1749 case MEI_FOP_DISCONNECT_RSP:
1750 mei_io_cb_free(cb);
1751 mei_cl_set_disconnected(cl);
3c666182
TW
1752 break;
1753 default:
1754 BUG_ON(0);
db086fa9
TW
1755 }
1756}
1757
4234a6de 1758
074b4c01
TW
1759/**
1760 * mei_cl_all_disconnect - disconnect forcefully all connected clients
1761 *
a8605ea2 1762 * @dev: mei device
074b4c01 1763 */
074b4c01
TW
1764void mei_cl_all_disconnect(struct mei_device *dev)
1765{
31f88f57 1766 struct mei_cl *cl;
074b4c01 1767
3c666182
TW
1768 list_for_each_entry(cl, &dev->file_list, link)
1769 mei_cl_set_disconnected(cl);
074b4c01 1770}