aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2013-01-08 16:07:13 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-08 19:40:44 -0500
commit9ca9050b3df690d9d44e39424ab2a531120af936 (patch)
tree06664064214caea9635e66025ad342f60cfc9662
parent0edb23fc3451c84350edcc999c023d225a49530d (diff)
mei: move client functions to client.c
This file now contains me and host client functions and also io callback helpers We also kill iorw.c which is no longer needed Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/misc/mei/Makefile2
-rw-r--r--drivers/misc/mei/client.c (renamed from drivers/misc/mei/iorw.c)377
-rw-r--r--drivers/misc/mei/init.c252
-rw-r--r--drivers/misc/mei/interface.c96
4 files changed, 361 insertions, 366 deletions
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 1f382a5ca3a6..67f543ab234f 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -7,7 +7,7 @@ mei-objs := init.o
7mei-objs += hbm.o 7mei-objs += hbm.o
8mei-objs += interrupt.o 8mei-objs += interrupt.o
9mei-objs += interface.o 9mei-objs += interface.o
10mei-objs += iorw.o
11mei-objs += main.o 10mei-objs += main.o
12mei-objs += amthif.o 11mei-objs += amthif.o
13mei-objs += wd.o 12mei-objs += wd.o
13mei-objs += client.o
diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/client.c
index 4328c2d2ca54..19f62073fa67 100644
--- a/drivers/misc/mei/iorw.c
+++ b/drivers/misc/mei/client.c
@@ -14,24 +14,10 @@
14 * 14 *
15 */ 15 */
16 16
17
18#include <linux/kernel.h>
19#include <linux/fs.h>
20#include <linux/errno.h>
21#include <linux/types.h>
22#include <linux/fcntl.h>
23#include <linux/aio.h>
24#include <linux/pci.h> 17#include <linux/pci.h>
25#include <linux/init.h>
26#include <linux/ioctl.h>
27#include <linux/cdev.h>
28#include <linux/list.h>
29#include <linux/delay.h>
30#include <linux/sched.h> 18#include <linux/sched.h>
31#include <linux/uuid.h> 19#include <linux/wait.h>
32#include <linux/jiffies.h> 20#include <linux/delay.h>
33#include <linux/uaccess.h>
34
35 21
36#include <linux/mei.h> 22#include <linux/mei.h>
37 23
@@ -39,6 +25,24 @@
39#include "hbm.h" 25#include "hbm.h"
40#include "interface.h" 26#include "interface.h"
41 27
28
29/**
30 * mei_io_list_flush - removes list entry belonging to cl.
31 *
32 * @list: An instance of our list structure
33 * @cl: host client
34 */
35void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
36{
37 struct mei_cl_cb *cb;
38 struct mei_cl_cb *next;
39
40 list_for_each_entry_safe(cb, next, &list->list, list) {
41 if (cb->cl && mei_cl_cmp_id(cl, cb->cl))
42 list_del(&cb->list);
43 }
44}
45
42/** 46/**
43 * mei_io_cb_free - free mei_cb_private related memory 47 * mei_io_cb_free - free mei_cb_private related memory
44 * 48 *
@@ -53,6 +57,7 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
53 kfree(cb->response_buffer.data); 57 kfree(cb->response_buffer.data);
54 kfree(cb); 58 kfree(cb);
55} 59}
60
56/** 61/**
57 * mei_io_cb_init - allocate and initialize io callback 62 * mei_io_cb_init - allocate and initialize io callback
58 * 63 *
@@ -77,7 +82,6 @@ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
77 return cb; 82 return cb;
78} 83}
79 84
80
81/** 85/**
82 * mei_io_cb_alloc_req_buf - allocate request buffer 86 * mei_io_cb_alloc_req_buf - allocate request buffer
83 * 87 *
@@ -128,6 +132,50 @@ int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
128} 132}
129 133
130 134
135
136/**
137 * mei_cl_flush_queues - flushes queue lists belonging to cl.
138 *
139 * @dev: the device structure
140 * @cl: host client
141 */
142int mei_cl_flush_queues(struct mei_cl *cl)
143{
144 if (!cl || !cl->dev)
145 return -EINVAL;
146
147 dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n");
148 mei_io_list_flush(&cl->dev->read_list, cl);
149 mei_io_list_flush(&cl->dev->write_list, cl);
150 mei_io_list_flush(&cl->dev->write_waiting_list, cl);
151 mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
152 mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
153 mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
154 mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
155 return 0;
156}
157
158/**
159 * mei_me_cl_by_uuid - locate index of me client
160 *
161 * @dev: mei device
162 * returns me client index or -ENOENT if not found
163 */
164int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
165{
166 int i, res = -ENOENT;
167
168 for (i = 0; i < dev->me_clients_num; ++i)
169 if (uuid_le_cmp(*uuid,
170 dev->me_clients[i].props.protocol_name) == 0) {
171 res = i;
172 break;
173 }
174
175 return res;
176}
177
178
131/** 179/**
132 * mei_me_cl_by_id return index to me_clients for client_id 180 * mei_me_cl_by_id return index to me_clients for client_id
133 * 181 *
@@ -155,6 +203,301 @@ int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
155} 203}
156 204
157/** 205/**
206 * mei_cl_init - initializes intialize cl.
207 *
208 * @cl: host client to be initialized
209 * @dev: mei device
210 */
211void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
212{
213 memset(cl, 0, sizeof(struct mei_cl));
214 init_waitqueue_head(&cl->wait);
215 init_waitqueue_head(&cl->rx_wait);
216 init_waitqueue_head(&cl->tx_wait);
217 INIT_LIST_HEAD(&cl->link);
218 cl->reading_state = MEI_IDLE;
219 cl->writing_state = MEI_IDLE;
220 cl->dev = dev;
221}
222
223/**
224 * mei_cl_allocate - allocates cl structure and sets it up.
225 *
226 * @dev: mei device
227 * returns The allocated file or NULL on failure
228 */
229struct mei_cl *mei_cl_allocate(struct mei_device *dev)
230{
231 struct mei_cl *cl;
232
233 cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
234 if (!cl)
235 return NULL;
236
237 mei_cl_init(cl, dev);
238
239 return cl;
240}
241
242
243/**
244 * mei_me_cl_link - create link between host and me clinet and add
245 * me_cl to the list
246 *
247 * @dev: the device structure
248 * @cl: link between me and host client assocated with opened file descriptor
249 * @uuid: uuid of ME client
250 * @client_id: id of the host client
251 *
252 * returns ME client index if ME client
253 * -EINVAL on incorrect values
254 * -ENONET if client not found
255 */
256int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl,
257 const uuid_le *uuid, u8 host_cl_id)
258{
259 int i;
260
261 if (!dev || !cl || !uuid)
262 return -EINVAL;
263
264 /* check for valid client id */
265 i = mei_me_cl_by_uuid(dev, uuid);
266 if (i >= 0) {
267 cl->me_client_id = dev->me_clients[i].client_id;
268 cl->state = MEI_FILE_CONNECTING;
269 cl->host_client_id = host_cl_id;
270
271 list_add_tail(&cl->link, &dev->file_list);
272 return (u8)i;
273 }
274
275 return -ENOENT;
276}
277/**
278 * mei_me_cl_unlink - remove me_cl from the list
279 *
280 * @dev: the device structure
281 * @host_client_id: host client id to be removed
282 */
283void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl)
284{
285 struct mei_cl *pos, *next;
286 list_for_each_entry_safe(pos, next, &dev->file_list, link) {
287 if (cl->host_client_id == pos->host_client_id) {
288 dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n",
289 pos->host_client_id, pos->me_client_id);
290 list_del_init(&pos->link);
291 break;
292 }
293 }
294}
295
296
297void mei_host_client_init(struct work_struct *work)
298{
299 struct mei_device *dev = container_of(work,
300 struct mei_device, init_work);
301 struct mei_client_properties *client_props;
302 int i;
303
304 mutex_lock(&dev->device_lock);
305
306 bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
307 dev->open_handle_count = 0;
308
309 /*
310 * Reserving the first three client IDs
311 * 0: Reserved for MEI Bus Message communications
312 * 1: Reserved for Watchdog
313 * 2: Reserved for AMTHI
314 */
315 bitmap_set(dev->host_clients_map, 0, 3);
316
317 for (i = 0; i < dev->me_clients_num; i++) {
318 client_props = &dev->me_clients[i].props;
319
320 if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid))
321 mei_amthif_host_init(dev);
322 else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
323 mei_wd_host_init(dev);
324 }
325
326 dev->dev_state = MEI_DEV_ENABLED;
327
328 mutex_unlock(&dev->device_lock);
329}
330
331
332/**
333 * mei_disconnect_host_client - sends disconnect message to fw from host client.
334 *
335 * @dev: the device structure
336 * @cl: private data of the file object
337 *
338 * Locking: called under "dev->device_lock" lock
339 *
340 * returns 0 on success, <0 on failure.
341 */
342int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl)
343{
344 struct mei_cl_cb *cb;
345 int rets, err;
346
347 if (!dev || !cl)
348 return -ENODEV;
349
350 if (cl->state != MEI_FILE_DISCONNECTING)
351 return 0;
352
353 cb = mei_io_cb_init(cl, NULL);
354 if (!cb)
355 return -ENOMEM;
356
357 cb->fop_type = MEI_FOP_CLOSE;
358 if (dev->mei_host_buffer_is_empty) {
359 dev->mei_host_buffer_is_empty = false;
360 if (mei_hbm_cl_disconnect_req(dev, cl)) {
361 rets = -ENODEV;
362 dev_err(&dev->pdev->dev, "failed to disconnect.\n");
363 goto free;
364 }
365 mdelay(10); /* Wait for hardware disconnection ready */
366 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
367 } else {
368 dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
369 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
370
371 }
372 mutex_unlock(&dev->device_lock);
373
374 err = wait_event_timeout(dev->wait_recvd_msg,
375 MEI_FILE_DISCONNECTED == cl->state,
376 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
377
378 mutex_lock(&dev->device_lock);
379 if (MEI_FILE_DISCONNECTED == cl->state) {
380 rets = 0;
381 dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n");
382 } else {
383 rets = -ENODEV;
384 if (MEI_FILE_DISCONNECTED != cl->state)
385 dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n");
386
387 if (err)
388 dev_dbg(&dev->pdev->dev,
389 "wait failed disconnect err=%08x\n",
390 err);
391
392 dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
393 }
394
395 mei_io_list_flush(&dev->ctrl_rd_list, cl);
396 mei_io_list_flush(&dev->ctrl_wr_list, cl);
397free:
398 mei_io_cb_free(cb);
399 return rets;
400}
401
402
403/**
404 * mei_other_client_is_connecting - checks if other
405 * client with the same client id is connected.
406 *
407 * @dev: the device structure
408 * @cl: private data of the file object
409 *
410 * returns 1 if other client is connected, 0 - otherwise.
411 */
412int mei_other_client_is_connecting(struct mei_device *dev,
413 struct mei_cl *cl)
414{
415 struct mei_cl *cl_pos = NULL;
416 struct mei_cl *cl_next = NULL;
417
418 list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
419 if ((cl_pos->state == MEI_FILE_CONNECTING) &&
420 (cl_pos != cl) &&
421 cl->me_client_id == cl_pos->me_client_id)
422 return 1;
423
424 }
425 return 0;
426}
427
428/**
429 * mei_flow_ctrl_creds - checks flow_control credentials.
430 *
431 * @dev: the device structure
432 * @cl: private data of the file object
433 *
434 * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
435 * -ENOENT if mei_cl is not present
436 * -EINVAL if single_recv_buf == 0
437 */
438int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl)
439{
440 int i;
441
442 if (!dev->me_clients_num)
443 return 0;
444
445 if (cl->mei_flow_ctrl_creds > 0)
446 return 1;
447
448 for (i = 0; i < dev->me_clients_num; i++) {
449 struct mei_me_client *me_cl = &dev->me_clients[i];
450 if (me_cl->client_id == cl->me_client_id) {
451 if (me_cl->mei_flow_ctrl_creds) {
452 if (WARN_ON(me_cl->props.single_recv_buf == 0))
453 return -EINVAL;
454 return 1;
455 } else {
456 return 0;
457 }
458 }
459 }
460 return -ENOENT;
461}
462
463/**
464 * mei_flow_ctrl_reduce - reduces flow_control.
465 *
466 * @dev: the device structure
467 * @cl: private data of the file object
468 * @returns
469 * 0 on success
470 * -ENOENT when me client is not found
471 * -EINVAL when ctrl credits are <= 0
472 */
473int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl)
474{
475 int i;
476
477 if (!dev->me_clients_num)
478 return -ENOENT;
479
480 for (i = 0; i < dev->me_clients_num; i++) {
481 struct mei_me_client *me_cl = &dev->me_clients[i];
482 if (me_cl->client_id == cl->me_client_id) {
483 if (me_cl->props.single_recv_buf != 0) {
484 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
485 return -EINVAL;
486 dev->me_clients[i].mei_flow_ctrl_creds--;
487 } else {
488 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
489 return -EINVAL;
490 cl->mei_flow_ctrl_creds--;
491 }
492 return 0;
493 }
494 }
495 return -ENOENT;
496}
497
498
499
500/**
158 * mei_ioctl_connect_client - the connect to fw client IOCTL function 501 * mei_ioctl_connect_client - the connect to fw client IOCTL function
159 * 502 *
160 * @dev: the device structure 503 * @dev: the device structure
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 55895fc21ff1..6c1f1f838d2b 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -22,7 +22,6 @@
22#include <linux/mei.h> 22#include <linux/mei.h>
23 23
24#include "mei_dev.h" 24#include "mei_dev.h"
25#include "hbm.h"
26#include "interface.h" 25#include "interface.h"
27 26
28const char *mei_dev_state_str(int state) 27const char *mei_dev_state_str(int state)
@@ -45,47 +44,6 @@ const char *mei_dev_state_str(int state)
45 44
46 45
47 46
48/**
49 * mei_io_list_flush - removes list entry belonging to cl.
50 *
51 * @list: An instance of our list structure
52 * @cl: private data of the file object
53 */
54void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
55{
56 struct mei_cl_cb *pos;
57 struct mei_cl_cb *next;
58
59 list_for_each_entry_safe(pos, next, &list->list, list) {
60 if (pos->cl) {
61 if (mei_cl_cmp_id(cl, pos->cl))
62 list_del(&pos->list);
63 }
64 }
65}
66/**
67 * mei_cl_flush_queues - flushes queue lists belonging to cl.
68 *
69 * @dev: the device structure
70 * @cl: private data of the file object
71 */
72int mei_cl_flush_queues(struct mei_cl *cl)
73{
74 if (!cl || !cl->dev)
75 return -EINVAL;
76
77 dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n");
78 mei_io_list_flush(&cl->dev->read_list, cl);
79 mei_io_list_flush(&cl->dev->write_list, cl);
80 mei_io_list_flush(&cl->dev->write_waiting_list, cl);
81 mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
82 mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
83 mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
84 mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
85 return 0;
86}
87
88
89 47
90/** 48/**
91 * init_mei_device - allocates and initializes the mei device structure 49 * init_mei_device - allocates and initializes the mei device structure
@@ -360,215 +318,5 @@ void mei_allocate_me_clients_storage(struct mei_device *dev)
360 return ; 318 return ;
361} 319}
362 320
363void mei_host_client_init(struct work_struct *work)
364{
365 struct mei_device *dev = container_of(work,
366 struct mei_device, init_work);
367 struct mei_client_properties *client_props;
368 int i;
369
370 mutex_lock(&dev->device_lock);
371
372 bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
373 dev->open_handle_count = 0;
374
375 /*
376 * Reserving the first three client IDs
377 * 0: Reserved for MEI Bus Message communications
378 * 1: Reserved for Watchdog
379 * 2: Reserved for AMTHI
380 */
381 bitmap_set(dev->host_clients_map, 0, 3);
382
383 for (i = 0; i < dev->me_clients_num; i++) {
384 client_props = &dev->me_clients[i].props;
385
386 if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid))
387 mei_amthif_host_init(dev);
388 else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
389 mei_wd_host_init(dev);
390 }
391 321
392 dev->dev_state = MEI_DEV_ENABLED;
393
394 mutex_unlock(&dev->device_lock);
395}
396
397
398/**
399 * mei_init_file_private - initializes private file structure.
400 *
401 * @priv: private file structure to be initialized
402 * @file: the file structure
403 */
404void mei_cl_init(struct mei_cl *priv, struct mei_device *dev)
405{
406 memset(priv, 0, sizeof(struct mei_cl));
407 init_waitqueue_head(&priv->wait);
408 init_waitqueue_head(&priv->rx_wait);
409 init_waitqueue_head(&priv->tx_wait);
410 INIT_LIST_HEAD(&priv->link);
411 priv->reading_state = MEI_IDLE;
412 priv->writing_state = MEI_IDLE;
413 priv->dev = dev;
414}
415
416int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid)
417{
418 int i, res = -ENOENT;
419
420 for (i = 0; i < dev->me_clients_num; ++i)
421 if (uuid_le_cmp(*cuuid,
422 dev->me_clients[i].props.protocol_name) == 0) {
423 res = i;
424 break;
425 }
426
427 return res;
428}
429
430
431/**
432 * mei_me_cl_link - create link between host and me clinet and add
433 * me_cl to the list
434 *
435 * @dev: the device structure
436 * @cl: link between me and host client assocated with opened file descriptor
437 * @cuuid: uuid of ME client
438 * @client_id: id of the host client
439 *
440 * returns ME client index if ME client
441 * -EINVAL on incorrect values
442 * -ENONET if client not found
443 */
444int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl,
445 const uuid_le *cuuid, u8 host_cl_id)
446{
447 int i;
448
449 if (!dev || !cl || !cuuid)
450 return -EINVAL;
451
452 /* check for valid client id */
453 i = mei_me_cl_by_uuid(dev, cuuid);
454 if (i >= 0) {
455 cl->me_client_id = dev->me_clients[i].client_id;
456 cl->state = MEI_FILE_CONNECTING;
457 cl->host_client_id = host_cl_id;
458
459 list_add_tail(&cl->link, &dev->file_list);
460 return (u8)i;
461 }
462
463 return -ENOENT;
464}
465/**
466 * mei_me_cl_unlink - remove me_cl from the list
467 *
468 * @dev: the device structure
469 * @host_client_id: host client id to be removed
470 */
471void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl)
472{
473 struct mei_cl *pos, *next;
474 list_for_each_entry_safe(pos, next, &dev->file_list, link) {
475 if (cl->host_client_id == pos->host_client_id) {
476 dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n",
477 pos->host_client_id, pos->me_client_id);
478 list_del_init(&pos->link);
479 break;
480 }
481 }
482}
483
484/**
485 * mei_alloc_file_private - allocates a private file structure and sets it up.
486 * @file: the file structure
487 *
488 * returns The allocated file or NULL on failure
489 */
490struct mei_cl *mei_cl_allocate(struct mei_device *dev)
491{
492 struct mei_cl *cl;
493
494 cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
495 if (!cl)
496 return NULL;
497
498 mei_cl_init(cl, dev);
499
500 return cl;
501}
502
503
504
505/**
506 * mei_disconnect_host_client - sends disconnect message to fw from host client.
507 *
508 * @dev: the device structure
509 * @cl: private data of the file object
510 *
511 * Locking: called under "dev->device_lock" lock
512 *
513 * returns 0 on success, <0 on failure.
514 */
515int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl)
516{
517 struct mei_cl_cb *cb;
518 int rets, err;
519
520 if (!dev || !cl)
521 return -ENODEV;
522
523 if (cl->state != MEI_FILE_DISCONNECTING)
524 return 0;
525
526 cb = mei_io_cb_init(cl, NULL);
527 if (!cb)
528 return -ENOMEM;
529
530 cb->fop_type = MEI_FOP_CLOSE;
531 if (dev->mei_host_buffer_is_empty) {
532 dev->mei_host_buffer_is_empty = false;
533 if (mei_hbm_cl_disconnect_req(dev, cl)) {
534 rets = -ENODEV;
535 dev_err(&dev->pdev->dev, "failed to disconnect.\n");
536 goto free;
537 }
538 mdelay(10); /* Wait for hardware disconnection ready */
539 list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
540 } else {
541 dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
542 list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
543
544 }
545 mutex_unlock(&dev->device_lock);
546
547 err = wait_event_timeout(dev->wait_recvd_msg,
548 MEI_FILE_DISCONNECTED == cl->state,
549 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
550
551 mutex_lock(&dev->device_lock);
552 if (MEI_FILE_DISCONNECTED == cl->state) {
553 rets = 0;
554 dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n");
555 } else {
556 rets = -ENODEV;
557 if (MEI_FILE_DISCONNECTED != cl->state)
558 dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n");
559
560 if (err)
561 dev_dbg(&dev->pdev->dev,
562 "wait failed disconnect err=%08x\n",
563 err);
564
565 dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
566 }
567
568 mei_io_list_flush(&dev->ctrl_rd_list, cl);
569 mei_io_list_flush(&dev->ctrl_wr_list, cl);
570free:
571 mei_io_cb_free(cb);
572 return rets;
573}
574 322
diff --git a/drivers/misc/mei/interface.c b/drivers/misc/mei/interface.c
index 155bd7efe4e5..3cb0cff01285 100644
--- a/drivers/misc/mei/interface.c
+++ b/drivers/misc/mei/interface.c
@@ -297,99 +297,3 @@ void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
297 mei_hcsr_set(dev); 297 mei_hcsr_set(dev);
298} 298}
299 299
300/**
301 * mei_flow_ctrl_creds - checks flow_control credentials.
302 *
303 * @dev: the device structure
304 * @cl: private data of the file object
305 *
306 * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
307 * -ENOENT if mei_cl is not present
308 * -EINVAL if single_recv_buf == 0
309 */
310int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl)
311{
312 int i;
313
314 if (!dev->me_clients_num)
315 return 0;
316
317 if (cl->mei_flow_ctrl_creds > 0)
318 return 1;
319
320 for (i = 0; i < dev->me_clients_num; i++) {
321 struct mei_me_client *me_cl = &dev->me_clients[i];
322 if (me_cl->client_id == cl->me_client_id) {
323 if (me_cl->mei_flow_ctrl_creds) {
324 if (WARN_ON(me_cl->props.single_recv_buf == 0))
325 return -EINVAL;
326 return 1;
327 } else {
328 return 0;
329 }
330 }
331 }
332 return -ENOENT;
333}
334
335/**
336 * mei_flow_ctrl_reduce - reduces flow_control.
337 *
338 * @dev: the device structure
339 * @cl: private data of the file object
340 * @returns
341 * 0 on success
342 * -ENOENT when me client is not found
343 * -EINVAL when ctrl credits are <= 0
344 */
345int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl)
346{
347 int i;
348
349 if (!dev->me_clients_num)
350 return -ENOENT;
351
352 for (i = 0; i < dev->me_clients_num; i++) {
353 struct mei_me_client *me_cl = &dev->me_clients[i];
354 if (me_cl->client_id == cl->me_client_id) {
355 if (me_cl->props.single_recv_buf != 0) {
356 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
357 return -EINVAL;
358 dev->me_clients[i].mei_flow_ctrl_creds--;
359 } else {
360 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
361 return -EINVAL;
362 cl->mei_flow_ctrl_creds--;
363 }
364 return 0;
365 }
366 }
367 return -ENOENT;
368}
369
370
371/**
372 * mei_other_client_is_connecting - checks if other
373 * client with the same client id is connected.
374 *
375 * @dev: the device structure
376 * @cl: private data of the file object
377 *
378 * returns 1 if other client is connected, 0 - otherwise.
379 */
380int mei_other_client_is_connecting(struct mei_device *dev,
381 struct mei_cl *cl)
382{
383 struct mei_cl *cl_pos = NULL;
384 struct mei_cl *cl_next = NULL;
385
386 list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
387 if ((cl_pos->state == MEI_FILE_CONNECTING) &&
388 (cl_pos != cl) &&
389 cl->me_client_id == cl_pos->me_client_id)
390 return 1;
391
392 }
393 return 0;
394}
395