]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/misc/mei/client.c
mei: me_client lookup function to return me_client object
[mirror_ubuntu-bionic-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/pci.h>
ab841160 18#include <linux/sched.h>
9ca9050b
TW
19#include <linux/wait.h>
20#include <linux/delay.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
29/**
30 * mei_me_cl_by_uuid - locate index of me client
31 *
32 * @dev: mei device
a27a76d3
AU
33 *
34 * Locking: called under "dev->device_lock" lock
35 *
d320832f 36 * returns me client or NULL if not found
90e0b5f1 37 */
d320832f
TW
38struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
39 const uuid_le *uuid)
90e0b5f1 40{
a27a76d3 41 int i;
90e0b5f1
TW
42
43 for (i = 0; i < dev->me_clients_num; ++i)
44 if (uuid_le_cmp(*uuid,
a27a76d3 45 dev->me_clients[i].props.protocol_name) == 0)
d320832f 46 return &dev->me_clients[i];
90e0b5f1 47
d320832f 48 return NULL;
90e0b5f1
TW
49}
50
51
52/**
53 * mei_me_cl_by_id return index to me_clients for client_id
54 *
55 * @dev: the device structure
56 * @client_id: me client id
57 *
58 * Locking: called under "dev->device_lock" lock
59 *
d320832f 60 * returns me client or NULL if not found
90e0b5f1
TW
61 */
62
d320832f 63struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
90e0b5f1
TW
64{
65 int i;
a27a76d3 66
90e0b5f1
TW
67 for (i = 0; i < dev->me_clients_num; i++)
68 if (dev->me_clients[i].client_id == client_id)
d320832f 69 return &dev->me_clients[i];
90e0b5f1 70
d320832f 71 return NULL;
90e0b5f1 72}
ab841160 73
9ca9050b
TW
74
75/**
cc99ecfd 76 * mei_cl_cmp_id - tells if the clients are the same
9ca9050b 77 *
cc99ecfd
TW
78 * @cl1: host client 1
79 * @cl2: host client 2
80 *
81 * returns true - if the clients has same host and me ids
82 * false - otherwise
83 */
84static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
85 const struct mei_cl *cl2)
86{
87 return cl1 && cl2 &&
88 (cl1->host_client_id == cl2->host_client_id) &&
89 (cl1->me_client_id == cl2->me_client_id);
90}
91
92/**
93 * mei_io_list_flush - removes cbs belonging to cl.
94 *
95 * @list: an instance of our list structure
96 * @cl: host client, can be NULL for flushing the whole list
97 * @free: whether to free the cbs
9ca9050b 98 */
cc99ecfd
TW
99static void __mei_io_list_flush(struct mei_cl_cb *list,
100 struct mei_cl *cl, bool free)
9ca9050b
TW
101{
102 struct mei_cl_cb *cb;
103 struct mei_cl_cb *next;
104
cc99ecfd 105 /* enable removing everything if no cl is specified */
9ca9050b 106 list_for_each_entry_safe(cb, next, &list->list, list) {
cc99ecfd 107 if (!cl || (cb->cl && mei_cl_cmp_id(cl, cb->cl))) {
9ca9050b 108 list_del(&cb->list);
cc99ecfd
TW
109 if (free)
110 mei_io_cb_free(cb);
111 }
9ca9050b
TW
112 }
113}
114
cc99ecfd
TW
115/**
116 * mei_io_list_flush - removes list entry belonging to cl.
117 *
118 * @list: An instance of our list structure
119 * @cl: host client
120 */
5456796b 121void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
cc99ecfd
TW
122{
123 __mei_io_list_flush(list, cl, false);
124}
125
126
127/**
128 * mei_io_list_free - removes cb belonging to cl and free them
129 *
130 * @list: An instance of our list structure
131 * @cl: host client
132 */
133static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
134{
135 __mei_io_list_flush(list, cl, true);
136}
137
601a1efa
TW
138/**
139 * mei_io_cb_free - free mei_cb_private related memory
140 *
141 * @cb: mei callback struct
142 */
143void mei_io_cb_free(struct mei_cl_cb *cb)
144{
145 if (cb == NULL)
146 return;
147
148 kfree(cb->request_buffer.data);
149 kfree(cb->response_buffer.data);
150 kfree(cb);
151}
9ca9050b 152
664df38b
TW
153/**
154 * mei_io_cb_init - allocate and initialize io callback
155 *
156 * @cl - mei client
393b148f 157 * @fp: pointer to file structure
664df38b
TW
158 *
159 * returns mei_cl_cb pointer or NULL;
160 */
161struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
162{
163 struct mei_cl_cb *cb;
164
165 cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
166 if (!cb)
167 return NULL;
168
169 mei_io_list_init(cb);
170
171 cb->file_object = fp;
db3ed431 172 cb->cl = cl;
664df38b
TW
173 cb->buf_idx = 0;
174 return cb;
175}
176
664df38b
TW
177/**
178 * mei_io_cb_alloc_req_buf - allocate request buffer
179 *
393b148f
MI
180 * @cb: io callback structure
181 * @length: size of the buffer
664df38b
TW
182 *
183 * returns 0 on success
184 * -EINVAL if cb is NULL
185 * -ENOMEM if allocation failed
186 */
187int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
188{
189 if (!cb)
190 return -EINVAL;
191
192 if (length == 0)
193 return 0;
194
195 cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
196 if (!cb->request_buffer.data)
197 return -ENOMEM;
198 cb->request_buffer.size = length;
199 return 0;
200}
201/**
83ce0741 202 * mei_io_cb_alloc_resp_buf - allocate response buffer
664df38b 203 *
393b148f
MI
204 * @cb: io callback structure
205 * @length: size of the buffer
664df38b
TW
206 *
207 * returns 0 on success
208 * -EINVAL if cb is NULL
209 * -ENOMEM if allocation failed
210 */
211int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
212{
213 if (!cb)
214 return -EINVAL;
215
216 if (length == 0)
217 return 0;
218
219 cb->response_buffer.data = kmalloc(length, GFP_KERNEL);
220 if (!cb->response_buffer.data)
221 return -ENOMEM;
222 cb->response_buffer.size = length;
223 return 0;
224}
225
601a1efa 226
9ca9050b
TW
227
228/**
229 * mei_cl_flush_queues - flushes queue lists belonging to cl.
230 *
9ca9050b
TW
231 * @cl: host client
232 */
233int mei_cl_flush_queues(struct mei_cl *cl)
234{
c0abffbd
AU
235 struct mei_device *dev;
236
90e0b5f1 237 if (WARN_ON(!cl || !cl->dev))
9ca9050b
TW
238 return -EINVAL;
239
c0abffbd
AU
240 dev = cl->dev;
241
242 cl_dbg(dev, cl, "remove list entry belonging to cl\n");
9ca9050b 243 mei_io_list_flush(&cl->dev->read_list, cl);
cc99ecfd
TW
244 mei_io_list_free(&cl->dev->write_list, cl);
245 mei_io_list_free(&cl->dev->write_waiting_list, cl);
9ca9050b
TW
246 mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
247 mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
248 mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
249 mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
250 return 0;
251}
252
ab841160 253
9ca9050b 254/**
83ce0741 255 * mei_cl_init - initializes cl.
9ca9050b
TW
256 *
257 * @cl: host client to be initialized
258 * @dev: mei device
259 */
260void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
261{
262 memset(cl, 0, sizeof(struct mei_cl));
263 init_waitqueue_head(&cl->wait);
264 init_waitqueue_head(&cl->rx_wait);
265 init_waitqueue_head(&cl->tx_wait);
266 INIT_LIST_HEAD(&cl->link);
a7b71bc0 267 INIT_LIST_HEAD(&cl->device_link);
9ca9050b
TW
268 cl->reading_state = MEI_IDLE;
269 cl->writing_state = MEI_IDLE;
270 cl->dev = dev;
271}
272
273/**
274 * mei_cl_allocate - allocates cl structure and sets it up.
275 *
276 * @dev: mei device
277 * returns The allocated file or NULL on failure
278 */
279struct mei_cl *mei_cl_allocate(struct mei_device *dev)
280{
281 struct mei_cl *cl;
282
283 cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
284 if (!cl)
285 return NULL;
286
287 mei_cl_init(cl, dev);
288
289 return cl;
290}
291
90e0b5f1
TW
292/**
293 * mei_cl_find_read_cb - find this cl's callback in the read list
294 *
393b148f
MI
295 * @cl: host client
296 *
90e0b5f1
TW
297 * returns cb on success, NULL on error
298 */
299struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
300{
301 struct mei_device *dev = cl->dev;
31f88f57 302 struct mei_cl_cb *cb;
90e0b5f1 303
31f88f57 304 list_for_each_entry(cb, &dev->read_list.list, list)
90e0b5f1
TW
305 if (mei_cl_cmp_id(cl, cb->cl))
306 return cb;
307 return NULL;
308}
309
83ce0741 310/** mei_cl_link: allocate host id in the host map
9ca9050b 311 *
781d0d89 312 * @cl - host client
83ce0741 313 * @id - fixed host id or -1 for generic one
393b148f 314 *
781d0d89 315 * returns 0 on success
9ca9050b
TW
316 * -EINVAL on incorrect values
317 * -ENONET if client not found
318 */
781d0d89 319int mei_cl_link(struct mei_cl *cl, int id)
9ca9050b 320{
90e0b5f1 321 struct mei_device *dev;
22f96a0e 322 long open_handle_count;
9ca9050b 323
781d0d89 324 if (WARN_ON(!cl || !cl->dev))
9ca9050b
TW
325 return -EINVAL;
326
90e0b5f1
TW
327 dev = cl->dev;
328
83ce0741 329 /* If Id is not assigned get one*/
781d0d89
TW
330 if (id == MEI_HOST_CLIENT_ID_ANY)
331 id = find_first_zero_bit(dev->host_clients_map,
332 MEI_CLIENTS_MAX);
9ca9050b 333
781d0d89 334 if (id >= MEI_CLIENTS_MAX) {
83ce0741 335 dev_err(&dev->pdev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
e036cc57
TW
336 return -EMFILE;
337 }
338
22f96a0e
TW
339 open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
340 if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
83ce0741 341 dev_err(&dev->pdev->dev, "open_handle_count exceeded %d",
e036cc57
TW
342 MEI_MAX_OPEN_HANDLE_COUNT);
343 return -EMFILE;
9ca9050b
TW
344 }
345
781d0d89
TW
346 dev->open_handle_count++;
347
348 cl->host_client_id = id;
349 list_add_tail(&cl->link, &dev->file_list);
350
351 set_bit(id, dev->host_clients_map);
352
353 cl->state = MEI_FILE_INITIALIZING;
354
c0abffbd 355 cl_dbg(dev, cl, "link cl\n");
781d0d89 356 return 0;
9ca9050b 357}
781d0d89 358
9ca9050b 359/**
90e0b5f1 360 * mei_cl_unlink - remove me_cl from the list
9ca9050b 361 *
393b148f 362 * @cl: host client
9ca9050b 363 */
90e0b5f1 364int mei_cl_unlink(struct mei_cl *cl)
9ca9050b 365{
90e0b5f1 366 struct mei_device *dev;
90e0b5f1 367
781d0d89
TW
368 /* don't shout on error exit path */
369 if (!cl)
370 return 0;
371
8e9a4a9a
TW
372 /* wd and amthif might not be initialized */
373 if (!cl->dev)
374 return 0;
90e0b5f1
TW
375
376 dev = cl->dev;
377
a14c44d8
TW
378 cl_dbg(dev, cl, "unlink client");
379
22f96a0e
TW
380 if (dev->open_handle_count > 0)
381 dev->open_handle_count--;
382
383 /* never clear the 0 bit */
384 if (cl->host_client_id)
385 clear_bit(cl->host_client_id, dev->host_clients_map);
386
387 list_del_init(&cl->link);
388
389 cl->state = MEI_FILE_INITIALIZING;
390
90e0b5f1 391 return 0;
9ca9050b
TW
392}
393
394
395void mei_host_client_init(struct work_struct *work)
396{
397 struct mei_device *dev = container_of(work,
398 struct mei_device, init_work);
399 struct mei_client_properties *client_props;
400 int i;
401
402 mutex_lock(&dev->device_lock);
403
9ca9050b
TW
404 for (i = 0; i < dev->me_clients_num; i++) {
405 client_props = &dev->me_clients[i].props;
406
1a1aca42 407 if (!uuid_le_cmp(client_props->protocol_name, mei_amthif_guid))
9ca9050b
TW
408 mei_amthif_host_init(dev);
409 else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
410 mei_wd_host_init(dev);
59fcd7c6
SO
411 else if (!uuid_le_cmp(client_props->protocol_name, mei_nfc_guid))
412 mei_nfc_host_init(dev);
413
9ca9050b
TW
414 }
415
416 dev->dev_state = MEI_DEV_ENABLED;
6adb8efb 417 dev->reset_count = 0;
9ca9050b
TW
418
419 mutex_unlock(&dev->device_lock);
04bb139a
TW
420
421 pm_runtime_mark_last_busy(&dev->pdev->dev);
422 dev_dbg(&dev->pdev->dev, "rpm: autosuspend\n");
423 pm_runtime_autosuspend(&dev->pdev->dev);
9ca9050b
TW
424}
425
6aae48ff
TW
426/**
427 * mei_hbuf_acquire: try to acquire host buffer
428 *
429 * @dev: the device structure
430 * returns true if host buffer was acquired
431 */
432bool mei_hbuf_acquire(struct mei_device *dev)
433{
04bb139a
TW
434 if (mei_pg_state(dev) == MEI_PG_ON ||
435 dev->pg_event == MEI_PG_EVENT_WAIT) {
436 dev_dbg(&dev->pdev->dev, "device is in pg\n");
437 return false;
438 }
439
6aae48ff
TW
440 if (!dev->hbuf_is_ready) {
441 dev_dbg(&dev->pdev->dev, "hbuf is not ready\n");
442 return false;
443 }
444
445 dev->hbuf_is_ready = false;
446
447 return true;
448}
9ca9050b
TW
449
450/**
83ce0741 451 * mei_cl_disconnect - disconnect host client from the me one
9ca9050b 452 *
90e0b5f1 453 * @cl: host client
9ca9050b
TW
454 *
455 * Locking: called under "dev->device_lock" lock
456 *
457 * returns 0 on success, <0 on failure.
458 */
90e0b5f1 459int mei_cl_disconnect(struct mei_cl *cl)
9ca9050b 460{
90e0b5f1 461 struct mei_device *dev;
9ca9050b 462 struct mei_cl_cb *cb;
fe2f17eb 463 int rets;
9ca9050b 464
90e0b5f1 465 if (WARN_ON(!cl || !cl->dev))
9ca9050b
TW
466 return -ENODEV;
467
90e0b5f1
TW
468 dev = cl->dev;
469
c0abffbd
AU
470 cl_dbg(dev, cl, "disconnecting");
471
9ca9050b
TW
472 if (cl->state != MEI_FILE_DISCONNECTING)
473 return 0;
474
04bb139a
TW
475 rets = pm_runtime_get(&dev->pdev->dev);
476 if (rets < 0 && rets != -EINPROGRESS) {
477 pm_runtime_put_noidle(&dev->pdev->dev);
478 cl_err(dev, cl, "rpm: get failed %d\n", rets);
479 return rets;
480 }
481
9ca9050b 482 cb = mei_io_cb_init(cl, NULL);
04bb139a
TW
483 if (!cb) {
484 rets = -ENOMEM;
485 goto free;
486 }
9ca9050b
TW
487
488 cb->fop_type = MEI_FOP_CLOSE;
6aae48ff 489 if (mei_hbuf_acquire(dev)) {
9ca9050b
TW
490 if (mei_hbm_cl_disconnect_req(dev, cl)) {
491 rets = -ENODEV;
c0abffbd 492 cl_err(dev, cl, "failed to disconnect.\n");
9ca9050b
TW
493 goto free;
494 }
22b987a3 495 cl->timer_count = MEI_CONNECT_TIMEOUT;
9ca9050b
TW
496 mdelay(10); /* Wait for hardware disconnection ready */
497 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
498 } else {
c0abffbd 499 cl_dbg(dev, cl, "add disconnect cb to control write list\n");
9ca9050b
TW
500 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
501
502 }
503 mutex_unlock(&dev->device_lock);
504
fe2f17eb 505 wait_event_timeout(dev->wait_recvd_msg,
9ca9050b
TW
506 MEI_FILE_DISCONNECTED == cl->state,
507 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
508
509 mutex_lock(&dev->device_lock);
fe2f17eb 510
9ca9050b
TW
511 if (MEI_FILE_DISCONNECTED == cl->state) {
512 rets = 0;
c0abffbd 513 cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
9ca9050b 514 } else {
fe2f17eb
AU
515 cl_dbg(dev, cl, "timeout on disconnect from FW client.\n");
516 rets = -ETIME;
9ca9050b
TW
517 }
518
519 mei_io_list_flush(&dev->ctrl_rd_list, cl);
520 mei_io_list_flush(&dev->ctrl_wr_list, cl);
521free:
04bb139a
TW
522 cl_dbg(dev, cl, "rpm: autosuspend\n");
523 pm_runtime_mark_last_busy(&dev->pdev->dev);
524 pm_runtime_put_autosuspend(&dev->pdev->dev);
525
9ca9050b
TW
526 mei_io_cb_free(cb);
527 return rets;
528}
529
530
531/**
90e0b5f1
TW
532 * mei_cl_is_other_connecting - checks if other
533 * client with the same me client id is connecting
9ca9050b 534 *
9ca9050b
TW
535 * @cl: private data of the file object
536 *
83ce0741 537 * returns true if other client is connected, false - otherwise.
9ca9050b 538 */
90e0b5f1 539bool mei_cl_is_other_connecting(struct mei_cl *cl)
9ca9050b 540{
90e0b5f1 541 struct mei_device *dev;
31f88f57 542 struct mei_cl *ocl; /* the other client */
9ca9050b 543
90e0b5f1
TW
544 if (WARN_ON(!cl || !cl->dev))
545 return false;
546
547 dev = cl->dev;
548
31f88f57
TW
549 list_for_each_entry(ocl, &dev->file_list, link) {
550 if (ocl->state == MEI_FILE_CONNECTING &&
551 ocl != cl &&
552 cl->me_client_id == ocl->me_client_id)
90e0b5f1 553 return true;
9ca9050b
TW
554
555 }
90e0b5f1
TW
556
557 return false;
9ca9050b
TW
558}
559
9f81abda 560/**
83ce0741 561 * mei_cl_connect - connect host client to the me one
9f81abda
TW
562 *
563 * @cl: host client
564 *
565 * Locking: called under "dev->device_lock" lock
566 *
567 * returns 0 on success, <0 on failure.
568 */
569int mei_cl_connect(struct mei_cl *cl, struct file *file)
570{
571 struct mei_device *dev;
572 struct mei_cl_cb *cb;
9f81abda
TW
573 int rets;
574
575 if (WARN_ON(!cl || !cl->dev))
576 return -ENODEV;
577
578 dev = cl->dev;
579
04bb139a
TW
580 rets = pm_runtime_get(&dev->pdev->dev);
581 if (rets < 0 && rets != -EINPROGRESS) {
582 pm_runtime_put_noidle(&dev->pdev->dev);
583 cl_err(dev, cl, "rpm: get failed %d\n", rets);
584 return rets;
585 }
586
9f81abda
TW
587 cb = mei_io_cb_init(cl, file);
588 if (!cb) {
589 rets = -ENOMEM;
590 goto out;
591 }
592
02a7eecc 593 cb->fop_type = MEI_FOP_CONNECT;
9f81abda 594
6aae48ff
TW
595 /* run hbuf acquire last so we don't have to undo */
596 if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
e4d8270e 597 cl->state = MEI_FILE_CONNECTING;
9f81abda
TW
598 if (mei_hbm_cl_connect_req(dev, cl)) {
599 rets = -ENODEV;
600 goto out;
601 }
602 cl->timer_count = MEI_CONNECT_TIMEOUT;
603 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
604 } else {
73ab4232 605 cl->state = MEI_FILE_INITIALIZING;
9f81abda
TW
606 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
607 }
608
609 mutex_unlock(&dev->device_lock);
285e2996
AU
610 wait_event_timeout(dev->wait_recvd_msg,
611 (cl->state == MEI_FILE_CONNECTED ||
612 cl->state == MEI_FILE_DISCONNECTED),
613 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
9f81abda
TW
614 mutex_lock(&dev->device_lock);
615
616 if (cl->state != MEI_FILE_CONNECTED) {
3e37ebb7 617 cl->state = MEI_FILE_DISCONNECTED;
285e2996
AU
618 /* something went really wrong */
619 if (!cl->status)
620 cl->status = -EFAULT;
9f81abda
TW
621
622 mei_io_list_flush(&dev->ctrl_rd_list, cl);
623 mei_io_list_flush(&dev->ctrl_wr_list, cl);
9f81abda
TW
624 }
625
626 rets = cl->status;
627
628out:
04bb139a
TW
629 cl_dbg(dev, cl, "rpm: autosuspend\n");
630 pm_runtime_mark_last_busy(&dev->pdev->dev);
631 pm_runtime_put_autosuspend(&dev->pdev->dev);
632
9f81abda
TW
633 mei_io_cb_free(cb);
634 return rets;
635}
636
9ca9050b 637/**
90e0b5f1 638 * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
9ca9050b 639 *
9ca9050b
TW
640 * @cl: private data of the file object
641 *
642 * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
643 * -ENOENT if mei_cl is not present
644 * -EINVAL if single_recv_buf == 0
645 */
90e0b5f1 646int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
9ca9050b 647{
90e0b5f1 648 struct mei_device *dev;
12d00665 649 struct mei_me_client *me_cl;
9ca9050b 650
90e0b5f1
TW
651 if (WARN_ON(!cl || !cl->dev))
652 return -EINVAL;
653
654 dev = cl->dev;
655
9ca9050b
TW
656 if (!dev->me_clients_num)
657 return 0;
658
659 if (cl->mei_flow_ctrl_creds > 0)
660 return 1;
661
d320832f
TW
662 me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
663 if (!me_cl) {
12d00665 664 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
d320832f 665 return -ENOENT;
9ca9050b 666 }
12d00665 667
12d00665
AU
668 if (me_cl->mei_flow_ctrl_creds) {
669 if (WARN_ON(me_cl->props.single_recv_buf == 0))
670 return -EINVAL;
671 return 1;
672 }
673 return 0;
9ca9050b
TW
674}
675
676/**
90e0b5f1 677 * mei_cl_flow_ctrl_reduce - reduces flow_control.
9ca9050b 678 *
9ca9050b 679 * @cl: private data of the file object
393b148f 680 *
9ca9050b
TW
681 * @returns
682 * 0 on success
683 * -ENOENT when me client is not found
684 * -EINVAL when ctrl credits are <= 0
685 */
90e0b5f1 686int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
9ca9050b 687{
90e0b5f1 688 struct mei_device *dev;
12d00665 689 struct mei_me_client *me_cl;
9ca9050b 690
90e0b5f1
TW
691 if (WARN_ON(!cl || !cl->dev))
692 return -EINVAL;
693
694 dev = cl->dev;
695
d320832f
TW
696 me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
697 if (!me_cl) {
12d00665 698 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
d320832f 699 return -ENOENT;
12d00665 700 }
9ca9050b 701
d320832f 702 if (me_cl->props.single_recv_buf) {
12d00665
AU
703 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
704 return -EINVAL;
705 me_cl->mei_flow_ctrl_creds--;
706 } else {
707 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
708 return -EINVAL;
709 cl->mei_flow_ctrl_creds--;
9ca9050b 710 }
12d00665 711 return 0;
9ca9050b
TW
712}
713
ab841160 714/**
393b148f 715 * mei_cl_read_start - the start read client message function.
ab841160 716 *
90e0b5f1 717 * @cl: host client
ab841160
OW
718 *
719 * returns 0 on success, <0 on failure.
720 */
fcb136e1 721int mei_cl_read_start(struct mei_cl *cl, size_t length)
ab841160 722{
90e0b5f1 723 struct mei_device *dev;
ab841160 724 struct mei_cl_cb *cb;
d320832f 725 struct mei_me_client *me_cl;
664df38b 726 int rets;
ab841160 727
90e0b5f1
TW
728 if (WARN_ON(!cl || !cl->dev))
729 return -ENODEV;
730
731 dev = cl->dev;
732
b950ac1d 733 if (!mei_cl_is_connected(cl))
ab841160
OW
734 return -ENODEV;
735
d91aaed3 736 if (cl->read_cb) {
c0abffbd 737 cl_dbg(dev, cl, "read is pending.\n");
ab841160
OW
738 return -EBUSY;
739 }
d320832f
TW
740 me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
741 if (!me_cl) {
c0abffbd 742 cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
7ca96aa2 743 return -ENOTTY;
664df38b 744 }
ab841160 745
04bb139a
TW
746 rets = pm_runtime_get(&dev->pdev->dev);
747 if (rets < 0 && rets != -EINPROGRESS) {
748 pm_runtime_put_noidle(&dev->pdev->dev);
749 cl_err(dev, cl, "rpm: get failed %d\n", rets);
750 return rets;
751 }
752
664df38b 753 cb = mei_io_cb_init(cl, NULL);
04bb139a
TW
754 if (!cb) {
755 rets = -ENOMEM;
756 goto out;
757 }
ab841160 758
fcb136e1 759 /* always allocate at least client max message */
d320832f 760 length = max_t(size_t, length, me_cl->props.max_msg_length);
fcb136e1 761 rets = mei_io_cb_alloc_resp_buf(cb, length);
664df38b 762 if (rets)
04bb139a 763 goto out;
ab841160 764
4b8960b4 765 cb->fop_type = MEI_FOP_READ;
6aae48ff 766 if (mei_hbuf_acquire(dev)) {
86113500
AU
767 rets = mei_hbm_cl_flow_control_req(dev, cl);
768 if (rets < 0)
04bb139a 769 goto out;
04bb139a 770
fb601adb 771 list_add_tail(&cb->list, &dev->read_list.list);
ab841160 772 } else {
fb601adb 773 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
ab841160 774 }
accb884b
CB
775
776 cl->read_cb = cb;
777
04bb139a
TW
778out:
779 cl_dbg(dev, cl, "rpm: autosuspend\n");
780 pm_runtime_mark_last_busy(&dev->pdev->dev);
781 pm_runtime_put_autosuspend(&dev->pdev->dev);
782
783 if (rets)
784 mei_io_cb_free(cb);
785
ab841160
OW
786 return rets;
787}
788
21767546 789/**
9d098192 790 * mei_cl_irq_write - write a message to device
21767546
TW
791 * from the interrupt thread context
792 *
793 * @cl: client
794 * @cb: callback block.
21767546
TW
795 * @cmpl_list: complete list.
796 *
797 * returns 0, OK; otherwise error.
798 */
9d098192
TW
799int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
800 struct mei_cl_cb *cmpl_list)
21767546 801{
136698e5
TW
802 struct mei_device *dev;
803 struct mei_msg_data *buf;
21767546 804 struct mei_msg_hdr mei_hdr;
136698e5
TW
805 size_t len;
806 u32 msg_slots;
9d098192 807 int slots;
2ebf8c94 808 int rets;
21767546 809
136698e5
TW
810 if (WARN_ON(!cl || !cl->dev))
811 return -ENODEV;
812
813 dev = cl->dev;
814
815 buf = &cb->request_buffer;
816
817 rets = mei_cl_flow_ctrl_creds(cl);
818 if (rets < 0)
819 return rets;
820
821 if (rets == 0) {
04bb139a 822 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
136698e5
TW
823 return 0;
824 }
825
9d098192 826 slots = mei_hbuf_empty_slots(dev);
136698e5
TW
827 len = buf->size - cb->buf_idx;
828 msg_slots = mei_data2slots(len);
829
21767546
TW
830 mei_hdr.host_addr = cl->host_client_id;
831 mei_hdr.me_addr = cl->me_client_id;
832 mei_hdr.reserved = 0;
479327fc 833 mei_hdr.internal = cb->internal;
21767546 834
9d098192 835 if (slots >= msg_slots) {
21767546
TW
836 mei_hdr.length = len;
837 mei_hdr.msg_complete = 1;
838 /* Split the message only if we can write the whole host buffer */
9d098192
TW
839 } else if (slots == dev->hbuf_depth) {
840 msg_slots = slots;
841 len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
21767546
TW
842 mei_hdr.length = len;
843 mei_hdr.msg_complete = 0;
844 } else {
845 /* wait for next time the host buffer is empty */
846 return 0;
847 }
848
c0abffbd 849 cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
21767546 850 cb->request_buffer.size, cb->buf_idx);
21767546 851
136698e5 852 rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
2ebf8c94
TW
853 if (rets) {
854 cl->status = rets;
21767546 855 list_move_tail(&cb->list, &cmpl_list->list);
2ebf8c94 856 return rets;
21767546
TW
857 }
858
859 cl->status = 0;
4dfaa9f7 860 cl->writing_state = MEI_WRITING;
21767546 861 cb->buf_idx += mei_hdr.length;
4dfaa9f7 862
21767546
TW
863 if (mei_hdr.msg_complete) {
864 if (mei_cl_flow_ctrl_reduce(cl))
2ebf8c94 865 return -EIO;
21767546
TW
866 list_move_tail(&cb->list, &dev->write_waiting_list.list);
867 }
868
869 return 0;
870}
871
4234a6de
TW
872/**
873 * mei_cl_write - submit a write cb to mei device
874 assumes device_lock is locked
875 *
876 * @cl: host client
877 * @cl: write callback with filled data
878 *
83ce0741 879 * returns number of bytes sent on success, <0 on failure.
4234a6de
TW
880 */
881int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
882{
883 struct mei_device *dev;
884 struct mei_msg_data *buf;
885 struct mei_msg_hdr mei_hdr;
886 int rets;
887
888
889 if (WARN_ON(!cl || !cl->dev))
890 return -ENODEV;
891
892 if (WARN_ON(!cb))
893 return -EINVAL;
894
895 dev = cl->dev;
896
897
898 buf = &cb->request_buffer;
899
c0abffbd 900 cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size);
4234a6de 901
04bb139a
TW
902 rets = pm_runtime_get(&dev->pdev->dev);
903 if (rets < 0 && rets != -EINPROGRESS) {
904 pm_runtime_put_noidle(&dev->pdev->dev);
905 cl_err(dev, cl, "rpm: get failed %d\n", rets);
906 return rets;
907 }
4234a6de
TW
908
909 cb->fop_type = MEI_FOP_WRITE;
6aae48ff
TW
910 cb->buf_idx = 0;
911 cl->writing_state = MEI_IDLE;
912
913 mei_hdr.host_addr = cl->host_client_id;
914 mei_hdr.me_addr = cl->me_client_id;
915 mei_hdr.reserved = 0;
916 mei_hdr.msg_complete = 0;
917 mei_hdr.internal = cb->internal;
4234a6de
TW
918
919 rets = mei_cl_flow_ctrl_creds(cl);
920 if (rets < 0)
921 goto err;
922
6aae48ff
TW
923 if (rets == 0) {
924 cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
925 rets = buf->size;
926 goto out;
927 }
928 if (!mei_hbuf_acquire(dev)) {
929 cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
4234a6de
TW
930 rets = buf->size;
931 goto out;
932 }
4234a6de
TW
933
934 /* Check for a maximum length */
935 if (buf->size > mei_hbuf_max_len(dev)) {
936 mei_hdr.length = mei_hbuf_max_len(dev);
937 mei_hdr.msg_complete = 0;
938 } else {
939 mei_hdr.length = buf->size;
940 mei_hdr.msg_complete = 1;
941 }
942
2ebf8c94
TW
943 rets = mei_write_message(dev, &mei_hdr, buf->data);
944 if (rets)
4234a6de 945 goto err;
4234a6de
TW
946
947 cl->writing_state = MEI_WRITING;
948 cb->buf_idx = mei_hdr.length;
949
4234a6de
TW
950out:
951 if (mei_hdr.msg_complete) {
7ca96aa2
AU
952 rets = mei_cl_flow_ctrl_reduce(cl);
953 if (rets < 0)
4234a6de 954 goto err;
7ca96aa2 955
4234a6de
TW
956 list_add_tail(&cb->list, &dev->write_waiting_list.list);
957 } else {
958 list_add_tail(&cb->list, &dev->write_list.list);
959 }
960
961
962 if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
963
964 mutex_unlock(&dev->device_lock);
7ca96aa2
AU
965 rets = wait_event_interruptible(cl->tx_wait,
966 cl->writing_state == MEI_WRITE_COMPLETE);
4234a6de 967 mutex_lock(&dev->device_lock);
7ca96aa2
AU
968 /* wait_event_interruptible returns -ERESTARTSYS */
969 if (rets) {
970 if (signal_pending(current))
971 rets = -EINTR;
972 goto err;
973 }
4234a6de 974 }
7ca96aa2
AU
975
976 rets = buf->size;
4234a6de 977err:
04bb139a
TW
978 cl_dbg(dev, cl, "rpm: autosuspend\n");
979 pm_runtime_mark_last_busy(&dev->pdev->dev);
980 pm_runtime_put_autosuspend(&dev->pdev->dev);
981
4234a6de
TW
982 return rets;
983}
984
985
db086fa9
TW
986/**
987 * mei_cl_complete - processes completed operation for a client
988 *
989 * @cl: private data of the file object.
990 * @cb: callback block.
991 */
992void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
993{
994 if (cb->fop_type == MEI_FOP_WRITE) {
995 mei_io_cb_free(cb);
996 cb = NULL;
997 cl->writing_state = MEI_WRITE_COMPLETE;
998 if (waitqueue_active(&cl->tx_wait))
999 wake_up_interruptible(&cl->tx_wait);
1000
1001 } else if (cb->fop_type == MEI_FOP_READ &&
1002 MEI_READING == cl->reading_state) {
1003 cl->reading_state = MEI_READ_COMPLETE;
1004 if (waitqueue_active(&cl->rx_wait))
1005 wake_up_interruptible(&cl->rx_wait);
1006 else
1007 mei_cl_bus_rx_event(cl);
1008
1009 }
1010}
1011
4234a6de 1012
074b4c01
TW
1013/**
1014 * mei_cl_all_disconnect - disconnect forcefully all connected clients
1015 *
1016 * @dev - mei device
1017 */
1018
1019void mei_cl_all_disconnect(struct mei_device *dev)
1020{
31f88f57 1021 struct mei_cl *cl;
074b4c01 1022
31f88f57 1023 list_for_each_entry(cl, &dev->file_list, link) {
074b4c01
TW
1024 cl->state = MEI_FILE_DISCONNECTED;
1025 cl->mei_flow_ctrl_creds = 0;
074b4c01
TW
1026 cl->timer_count = 0;
1027 }
1028}
1029
1030
1031/**
5290801c 1032 * mei_cl_all_wakeup - wake up all readers and writers they can be interrupted
074b4c01
TW
1033 *
1034 * @dev - mei device
1035 */
5290801c 1036void mei_cl_all_wakeup(struct mei_device *dev)
074b4c01 1037{
31f88f57
TW
1038 struct mei_cl *cl;
1039 list_for_each_entry(cl, &dev->file_list, link) {
074b4c01 1040 if (waitqueue_active(&cl->rx_wait)) {
c0abffbd 1041 cl_dbg(dev, cl, "Waking up reading client!\n");
074b4c01
TW
1042 wake_up_interruptible(&cl->rx_wait);
1043 }
5290801c 1044 if (waitqueue_active(&cl->tx_wait)) {
c0abffbd 1045 cl_dbg(dev, cl, "Waking up writing client!\n");
5290801c
TW
1046 wake_up_interruptible(&cl->tx_wait);
1047 }
074b4c01
TW
1048 }
1049}
1050
1051/**
1052 * mei_cl_all_write_clear - clear all pending writes
1053
1054 * @dev - mei device
1055 */
1056void mei_cl_all_write_clear(struct mei_device *dev)
1057{
cc99ecfd
TW
1058 mei_io_list_free(&dev->write_list, NULL);
1059 mei_io_list_free(&dev->write_waiting_list, NULL);
074b4c01
TW
1060}
1061
1062