client.c 27.5 KB
Newer Older
1 2 3
/*
 *
 * Intel Management Engine Interface (Intel MEI) Linux driver
4
 * Copyright (c) 2003-2012, Intel Corporation.
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 */

#include <linux/sched.h>
18 19
#include <linux/wait.h>
#include <linux/delay.h>
20
#include <linux/slab.h>
21
#include <linux/pm_runtime.h>
22

23
#include <linux/mei.h>
24 25

#include "mei_dev.h"
26
#include "hbm.h"
T
Tomas Winkler 已提交
27 28
#include "client.h"

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
/**
 * mei_me_cl_init - initialize me client
 *
 * @me_cl: me client
 */
void mei_me_cl_init(struct mei_me_client *me_cl)
{
	INIT_LIST_HEAD(&me_cl->list);
	kref_init(&me_cl->refcnt);
}

/**
 * mei_me_cl_get - increases me client refcount
 *
 * @me_cl: me client
 *
 * Locking: called under "dev->device_lock" lock
 *
 * Return: me client or NULL
 */
struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl)
{
51 52
	if (me_cl && kref_get_unless_zero(&me_cl->refcnt))
		return me_cl;
53

54
	return NULL;
55 56 57
}

/**
58
 * mei_me_cl_release - free me client
59 60 61 62 63 64 65 66 67
 *
 * Locking: called under "dev->device_lock" lock
 *
 * @ref: me_client refcount
 */
static void mei_me_cl_release(struct kref *ref)
{
	struct mei_me_client *me_cl =
		container_of(ref, struct mei_me_client, refcnt);
68

69 70
	kfree(me_cl);
}
71

72 73 74 75 76 77 78 79 80 81 82 83 84
/**
 * mei_me_cl_put - decrease me client refcount and free client if necessary
 *
 * Locking: called under "dev->device_lock" lock
 *
 * @me_cl: me client
 */
void mei_me_cl_put(struct mei_me_client *me_cl)
{
	if (me_cl)
		kref_put(&me_cl->refcnt, mei_me_cl_release);
}

T
Tomas Winkler 已提交
85
/**
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
 * __mei_me_cl_del  - delete me client form the list and decrease
 *     reference counter
 *
 * @dev: mei device
 * @me_cl: me client
 *
 * Locking: dev->me_clients_rwsem
 */
static void __mei_me_cl_del(struct mei_device *dev, struct mei_me_client *me_cl)
{
	if (!me_cl)
		return;

	list_del(&me_cl->list);
	mei_me_cl_put(me_cl);
}

/**
 * mei_me_cl_add - add me client to the list
 *
 * @dev: mei device
 * @me_cl: me client
 */
void mei_me_cl_add(struct mei_device *dev, struct mei_me_client *me_cl)
{
	down_write(&dev->me_clients_rwsem);
	list_add(&me_cl->list, &dev->me_clients);
	up_write(&dev->me_clients_rwsem);
}

/**
 * __mei_me_cl_by_uuid - locate me client by uuid
118
 *	increases ref count
T
Tomas Winkler 已提交
119 120
 *
 * @dev: mei device
121
 * @uuid: me client uuid
122
 *
123
 * Return: me client or NULL if not found
124 125
 *
 * Locking: dev->me_clients_rwsem
T
Tomas Winkler 已提交
126
 */
127
static struct mei_me_client *__mei_me_cl_by_uuid(struct mei_device *dev,
128
					const uuid_le *uuid)
T
Tomas Winkler 已提交
129
{
130
	struct mei_me_client *me_cl;
131
	const uuid_le *pn;
T
Tomas Winkler 已提交
132

133 134 135 136 137
	WARN_ON(!rwsem_is_locked(&dev->me_clients_rwsem));

	list_for_each_entry(me_cl, &dev->me_clients, list) {
		pn = &me_cl->props.protocol_name;
		if (uuid_le_cmp(*uuid, *pn) == 0)
138
			return mei_me_cl_get(me_cl);
139
	}
T
Tomas Winkler 已提交
140

141
	return NULL;
T
Tomas Winkler 已提交
142 143
}

144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
/**
 * mei_me_cl_by_uuid - locate me client by uuid
 *	increases ref count
 *
 * @dev: mei device
 * @uuid: me client uuid
 *
 * Return: me client or NULL if not found
 *
 * Locking: dev->me_clients_rwsem
 */
struct mei_me_client *mei_me_cl_by_uuid(struct mei_device *dev,
					const uuid_le *uuid)
{
	struct mei_me_client *me_cl;

	down_read(&dev->me_clients_rwsem);
	me_cl = __mei_me_cl_by_uuid(dev, uuid);
	up_read(&dev->me_clients_rwsem);

	return me_cl;
}

T
Tomas Winkler 已提交
167
/**
168
 * mei_me_cl_by_id - locate me client by client id
169
 *	increases ref count
T
Tomas Winkler 已提交
170 171 172 173
 *
 * @dev: the device structure
 * @client_id: me client id
 *
174
 * Return: me client or NULL if not found
175 176
 *
 * Locking: dev->me_clients_rwsem
T
Tomas Winkler 已提交
177
 */
178
struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
T
Tomas Winkler 已提交
179
{
180

181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
	struct mei_me_client *__me_cl, *me_cl = NULL;

	down_read(&dev->me_clients_rwsem);
	list_for_each_entry(__me_cl, &dev->me_clients, list) {
		if (__me_cl->client_id == client_id) {
			me_cl = mei_me_cl_get(__me_cl);
			break;
		}
	}
	up_read(&dev->me_clients_rwsem);

	return me_cl;
}

/**
 * __mei_me_cl_by_uuid_id - locate me client by client id and uuid
 *	increases ref count
 *
 * @dev: the device structure
 * @uuid: me client uuid
 * @client_id: me client id
 *
 * Return: me client or null if not found
 *
 * Locking: dev->me_clients_rwsem
 */
static struct mei_me_client *__mei_me_cl_by_uuid_id(struct mei_device *dev,
					   const uuid_le *uuid, u8 client_id)
{
210
	struct mei_me_client *me_cl;
211 212 213
	const uuid_le *pn;

	WARN_ON(!rwsem_is_locked(&dev->me_clients_rwsem));
T
Tomas Winkler 已提交
214

215 216 217 218
	list_for_each_entry(me_cl, &dev->me_clients, list) {
		pn = &me_cl->props.protocol_name;
		if (uuid_le_cmp(*uuid, *pn) == 0 &&
		    me_cl->client_id == client_id)
219
			return mei_me_cl_get(me_cl);
220
	}
221

222
	return NULL;
T
Tomas Winkler 已提交
223
}
224

225

226 227
/**
 * mei_me_cl_by_uuid_id - locate me client by client id and uuid
228
 *	increases ref count
229 230 231 232 233
 *
 * @dev: the device structure
 * @uuid: me client uuid
 * @client_id: me client id
 *
234
 * Return: me client or null if not found
235
 */
236 237 238 239 240
struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
					   const uuid_le *uuid, u8 client_id)
{
	struct mei_me_client *me_cl;

241 242 243
	down_read(&dev->me_clients_rwsem);
	me_cl = __mei_me_cl_by_uuid_id(dev, uuid, client_id);
	up_read(&dev->me_clients_rwsem);
244

245
	return me_cl;
246 247
}

248
/**
249
 * mei_me_cl_rm_by_uuid - remove all me clients matching uuid
250 251 252
 *
 * @dev: the device structure
 * @uuid: me client uuid
253 254
 *
 * Locking: called under "dev->device_lock" lock
255
 */
256
void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid)
257
{
258
	struct mei_me_client *me_cl;
259

260
	dev_dbg(dev->dev, "remove %pUl\n", uuid);
261 262 263 264 265

	down_write(&dev->me_clients_rwsem);
	me_cl = __mei_me_cl_by_uuid(dev, uuid);
	__mei_me_cl_del(dev, me_cl);
	up_write(&dev->me_clients_rwsem);
266 267 268 269 270 271 272 273 274 275 276 277 278
}

/**
 * mei_me_cl_rm_by_uuid_id - remove all me clients matching client id
 *
 * @dev: the device structure
 * @uuid: me client uuid
 * @id: me client id
 *
 * Locking: called under "dev->device_lock" lock
 */
void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 id)
{
279
	struct mei_me_client *me_cl;
280 281

	dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id);
282 283 284 285 286

	down_write(&dev->me_clients_rwsem);
	me_cl = __mei_me_cl_by_uuid_id(dev, uuid, id);
	__mei_me_cl_del(dev, me_cl);
	up_write(&dev->me_clients_rwsem);
287 288
}

289 290 291 292 293 294 295 296 297 298 299
/**
 * mei_me_cl_rm_all - remove all me clients
 *
 * @dev: the device structure
 *
 * Locking: called under "dev->device_lock" lock
 */
void mei_me_cl_rm_all(struct mei_device *dev)
{
	struct mei_me_client *me_cl, *next;

300
	down_write(&dev->me_clients_rwsem);
301
	list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
302 303
		__mei_me_cl_del(dev, me_cl);
	up_write(&dev->me_clients_rwsem);
304 305
}

306
/**
307
 * mei_cl_cmp_id - tells if the clients are the same
308
 *
309 310 311
 * @cl1: host client 1
 * @cl2: host client 2
 *
312
 * Return: true  - if the clients has same host and me ids
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
 *         false - otherwise
 */
static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
				const struct mei_cl *cl2)
{
	return cl1 && cl2 &&
		(cl1->host_client_id == cl2->host_client_id) &&
		(cl1->me_client_id == cl2->me_client_id);
}

/**
 * mei_io_list_flush - removes cbs belonging to cl.
 *
 * @list:  an instance of our list structure
 * @cl:    host client, can be NULL for flushing the whole list
 * @free:  whether to free the cbs
329
 */
330 331
static void __mei_io_list_flush(struct mei_cl_cb *list,
				struct mei_cl *cl, bool free)
332 333 334 335
{
	struct mei_cl_cb *cb;
	struct mei_cl_cb *next;

336
	/* enable removing everything if no cl is specified */
337
	list_for_each_entry_safe(cb, next, &list->list, list) {
338
		if (!cl || mei_cl_cmp_id(cl, cb->cl)) {
339
			list_del(&cb->list);
340 341 342
			if (free)
				mei_io_cb_free(cb);
		}
343 344 345
	}
}

346 347 348 349 350 351
/**
 * mei_io_list_flush - removes list entry belonging to cl.
 *
 * @list:  An instance of our list structure
 * @cl: host client
 */
352
void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
{
	__mei_io_list_flush(list, cl, false);
}


/**
 * mei_io_list_free - removes cb belonging to cl and free them
 *
 * @list:  An instance of our list structure
 * @cl: host client
 */
static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
{
	__mei_io_list_flush(list, cl, true);
}

369 370 371 372 373 374 375 376 377 378 379 380 381 382
/**
 * mei_io_cb_free - free mei_cb_private related memory
 *
 * @cb: mei callback struct
 */
void mei_io_cb_free(struct mei_cl_cb *cb)
{
	if (cb == NULL)
		return;

	kfree(cb->request_buffer.data);
	kfree(cb->response_buffer.data);
	kfree(cb);
}
383

384 385 386
/**
 * mei_io_cb_init - allocate and initialize io callback
 *
387
 * @cl: mei client
388
 * @fp: pointer to file structure
389
 *
390
 * Return: mei_cl_cb pointer or NULL;
391 392 393 394 395 396 397 398 399 400 401 402
 */
struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
{
	struct mei_cl_cb *cb;

	cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
	if (!cb)
		return NULL;

	mei_io_list_init(cb);

	cb->file_object = fp;
403
	cb->cl = cl;
404 405 406 407 408 409 410
	cb->buf_idx = 0;
	return cb;
}

/**
 * mei_io_cb_alloc_req_buf - allocate request buffer
 *
411 412
 * @cb: io callback structure
 * @length: size of the buffer
413
 *
414
 * Return: 0 on success
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
 *         -EINVAL if cb is NULL
 *         -ENOMEM if allocation failed
 */
int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
{
	if (!cb)
		return -EINVAL;

	if (length == 0)
		return 0;

	cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
	if (!cb->request_buffer.data)
		return -ENOMEM;
	cb->request_buffer.size = length;
	return 0;
}
/**
433
 * mei_io_cb_alloc_resp_buf - allocate response buffer
434
 *
435 436
 * @cb: io callback structure
 * @length: size of the buffer
437
 *
438
 * Return: 0 on success
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
 *         -EINVAL if cb is NULL
 *         -ENOMEM if allocation failed
 */
int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
{
	if (!cb)
		return -EINVAL;

	if (length == 0)
		return 0;

	cb->response_buffer.data = kmalloc(length, GFP_KERNEL);
	if (!cb->response_buffer.data)
		return -ENOMEM;
	cb->response_buffer.size = length;
	return 0;
}

457

458 459 460 461 462

/**
 * mei_cl_flush_queues - flushes queue lists belonging to cl.
 *
 * @cl: host client
A
Alexander Usyskin 已提交
463 464
 *
 * Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
465 466 467
 */
int mei_cl_flush_queues(struct mei_cl *cl)
{
468 469
	struct mei_device *dev;

T
Tomas Winkler 已提交
470
	if (WARN_ON(!cl || !cl->dev))
471 472
		return -EINVAL;

473 474 475
	dev = cl->dev;

	cl_dbg(dev, cl, "remove list entry belonging to cl\n");
476
	mei_io_list_flush(&cl->dev->read_list, cl);
477 478
	mei_io_list_free(&cl->dev->write_list, cl);
	mei_io_list_free(&cl->dev->write_waiting_list, cl);
479 480 481 482 483 484 485
	mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
	mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
	mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
	mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
	return 0;
}

486

487
/**
488
 * mei_cl_init - initializes cl.
489 490 491 492 493 494 495 496 497 498 499
 *
 * @cl: host client to be initialized
 * @dev: mei device
 */
void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
{
	memset(cl, 0, sizeof(struct mei_cl));
	init_waitqueue_head(&cl->wait);
	init_waitqueue_head(&cl->rx_wait);
	init_waitqueue_head(&cl->tx_wait);
	INIT_LIST_HEAD(&cl->link);
500
	INIT_LIST_HEAD(&cl->device_link);
501 502 503 504 505 506 507 508 509
	cl->reading_state = MEI_IDLE;
	cl->writing_state = MEI_IDLE;
	cl->dev = dev;
}

/**
 * mei_cl_allocate - allocates cl  structure and sets it up.
 *
 * @dev: mei device
510
 * Return:  The allocated file or NULL on failure
511 512 513 514 515 516 517 518 519 520 521 522 523 524
 */
struct mei_cl *mei_cl_allocate(struct mei_device *dev)
{
	struct mei_cl *cl;

	cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
	if (!cl)
		return NULL;

	mei_cl_init(cl, dev);

	return cl;
}

T
Tomas Winkler 已提交
525 526 527
/**
 * mei_cl_find_read_cb - find this cl's callback in the read list
 *
528 529
 * @cl: host client
 *
530
 * Return: cb on success, NULL on error
T
Tomas Winkler 已提交
531 532 533 534
 */
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
{
	struct mei_device *dev = cl->dev;
535
	struct mei_cl_cb *cb;
T
Tomas Winkler 已提交
536

537
	list_for_each_entry(cb, &dev->read_list.list, list)
T
Tomas Winkler 已提交
538 539 540 541 542
		if (mei_cl_cmp_id(cl, cb->cl))
			return cb;
	return NULL;
}

543
/** mei_cl_link: allocate host id in the host map
544
 *
545
 * @cl - host client
546
 * @id - fixed host id or -1 for generic one
547
 *
548
 * Return: 0 on success
549 550 551
 *	-EINVAL on incorrect values
 *	-ENONET if client not found
 */
552
int mei_cl_link(struct mei_cl *cl, int id)
553
{
T
Tomas Winkler 已提交
554
	struct mei_device *dev;
T
Tomas Winkler 已提交
555
	long open_handle_count;
556

557
	if (WARN_ON(!cl || !cl->dev))
558 559
		return -EINVAL;

T
Tomas Winkler 已提交
560 561
	dev = cl->dev;

562
	/* If Id is not assigned get one*/
563 564 565
	if (id == MEI_HOST_CLIENT_ID_ANY)
		id = find_first_zero_bit(dev->host_clients_map,
					MEI_CLIENTS_MAX);
566

567
	if (id >= MEI_CLIENTS_MAX) {
568
		dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
569 570 571
		return -EMFILE;
	}

T
Tomas Winkler 已提交
572 573
	open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
	if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
574
		dev_err(dev->dev, "open_handle_count exceeded %d",
575 576
			MEI_MAX_OPEN_HANDLE_COUNT);
		return -EMFILE;
577 578
	}

579 580 581 582 583 584 585 586 587
	dev->open_handle_count++;

	cl->host_client_id = id;
	list_add_tail(&cl->link, &dev->file_list);

	set_bit(id, dev->host_clients_map);

	cl->state = MEI_FILE_INITIALIZING;

588
	cl_dbg(dev, cl, "link cl\n");
589
	return 0;
590
}
591

592
/**
T
Tomas Winkler 已提交
593
 * mei_cl_unlink - remove me_cl from the list
594
 *
595
 * @cl: host client
A
Alexander Usyskin 已提交
596 597
 *
 * Return: always 0
598
 */
T
Tomas Winkler 已提交
599
int mei_cl_unlink(struct mei_cl *cl)
600
{
T
Tomas Winkler 已提交
601 602
	struct mei_device *dev;

603 604 605 606
	/* don't shout on error exit path */
	if (!cl)
		return 0;

607 608 609
	/* wd and amthif might not be initialized */
	if (!cl->dev)
		return 0;
T
Tomas Winkler 已提交
610 611 612

	dev = cl->dev;

613 614
	cl_dbg(dev, cl, "unlink client");

T
Tomas Winkler 已提交
615 616 617 618 619 620 621 622 623 624 625
	if (dev->open_handle_count > 0)
		dev->open_handle_count--;

	/* never clear the 0 bit */
	if (cl->host_client_id)
		clear_bit(cl->host_client_id, dev->host_clients_map);

	list_del_init(&cl->link);

	cl->state = MEI_FILE_INITIALIZING;

T
Tomas Winkler 已提交
626
	return 0;
627 628 629 630 631
}


void mei_host_client_init(struct work_struct *work)
{
632 633
	struct mei_device *dev =
		container_of(work, struct mei_device, init_work);
634
	struct mei_me_client *me_cl;
635 636 637 638

	mutex_lock(&dev->device_lock);


639 640 641 642 643 644 645 646 647 648 649
	me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
	if (me_cl)
		mei_amthif_host_init(dev);

	me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid);
	if (me_cl)
		mei_wd_host_init(dev);

	me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
	if (me_cl)
		mei_nfc_host_init(dev);
650

651 652

	dev->dev_state = MEI_DEV_ENABLED;
653
	dev->reset_count = 0;
654
	mutex_unlock(&dev->device_lock);
655

656 657 658
	pm_runtime_mark_last_busy(dev->dev);
	dev_dbg(dev->dev, "rpm: autosuspend\n");
	pm_runtime_autosuspend(dev->dev);
659 660
}

661
/**
662
 * mei_hbuf_acquire - try to acquire host buffer
663 664
 *
 * @dev: the device structure
665
 * Return: true if host buffer was acquired
666 667 668
 */
bool mei_hbuf_acquire(struct mei_device *dev)
{
669 670
	if (mei_pg_state(dev) == MEI_PG_ON ||
	    dev->pg_event == MEI_PG_EVENT_WAIT) {
671
		dev_dbg(dev->dev, "device is in pg\n");
672 673 674
		return false;
	}

675
	if (!dev->hbuf_is_ready) {
676
		dev_dbg(dev->dev, "hbuf is not ready\n");
677 678 679 680 681 682 683
		return false;
	}

	dev->hbuf_is_ready = false;

	return true;
}
684 685

/**
686
 * mei_cl_disconnect - disconnect host client from the me one
687
 *
T
Tomas Winkler 已提交
688
 * @cl: host client
689 690 691
 *
 * Locking: called under "dev->device_lock" lock
 *
692
 * Return: 0 on success, <0 on failure.
693
 */
T
Tomas Winkler 已提交
694
int mei_cl_disconnect(struct mei_cl *cl)
695
{
T
Tomas Winkler 已提交
696
	struct mei_device *dev;
697
	struct mei_cl_cb *cb;
698
	int rets;
699

T
Tomas Winkler 已提交
700
	if (WARN_ON(!cl || !cl->dev))
701 702
		return -ENODEV;

T
Tomas Winkler 已提交
703 704
	dev = cl->dev;

705 706
	cl_dbg(dev, cl, "disconnecting");

707 708 709
	if (cl->state != MEI_FILE_DISCONNECTING)
		return 0;

710
	rets = pm_runtime_get(dev->dev);
711
	if (rets < 0 && rets != -EINPROGRESS) {
712
		pm_runtime_put_noidle(dev->dev);
713 714 715 716
		cl_err(dev, cl, "rpm: get failed %d\n", rets);
		return rets;
	}

717
	cb = mei_io_cb_init(cl, NULL);
718 719 720 721
	if (!cb) {
		rets = -ENOMEM;
		goto free;
	}
722

723 724
	cb->fop_type = MEI_FOP_DISCONNECT;

725
	if (mei_hbuf_acquire(dev)) {
726 727
		if (mei_hbm_cl_disconnect_req(dev, cl)) {
			rets = -ENODEV;
728
			cl_err(dev, cl, "failed to disconnect.\n");
729 730
			goto free;
		}
731
		cl->timer_count = MEI_CONNECT_TIMEOUT;
732 733 734
		mdelay(10); /* Wait for hardware disconnection ready */
		list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
	} else {
735
		cl_dbg(dev, cl, "add disconnect cb to control write list\n");
736 737 738 739 740
		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);

	}
	mutex_unlock(&dev->device_lock);

741
	wait_event_timeout(cl->wait,
742 743 744 745
			MEI_FILE_DISCONNECTED == cl->state,
			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));

	mutex_lock(&dev->device_lock);
746

747 748
	if (MEI_FILE_DISCONNECTED == cl->state) {
		rets = 0;
749
		cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
750
	} else {
751 752
		cl_dbg(dev, cl, "timeout on disconnect from FW client.\n");
		rets = -ETIME;
753 754 755 756 757
	}

	mei_io_list_flush(&dev->ctrl_rd_list, cl);
	mei_io_list_flush(&dev->ctrl_wr_list, cl);
free:
758
	cl_dbg(dev, cl, "rpm: autosuspend\n");
759 760
	pm_runtime_mark_last_busy(dev->dev);
	pm_runtime_put_autosuspend(dev->dev);
761

762 763 764 765 766 767
	mei_io_cb_free(cb);
	return rets;
}


/**
T
Tomas Winkler 已提交
768 769
 * mei_cl_is_other_connecting - checks if other
 *    client with the same me client id is connecting
770 771 772
 *
 * @cl: private data of the file object
 *
773
 * Return: true if other client is connected, false - otherwise.
774
 */
T
Tomas Winkler 已提交
775
bool mei_cl_is_other_connecting(struct mei_cl *cl)
776
{
T
Tomas Winkler 已提交
777
	struct mei_device *dev;
778
	struct mei_cl *ocl; /* the other client */
779

T
Tomas Winkler 已提交
780 781 782 783 784
	if (WARN_ON(!cl || !cl->dev))
		return false;

	dev = cl->dev;

785 786 787 788
	list_for_each_entry(ocl, &dev->file_list, link) {
		if (ocl->state == MEI_FILE_CONNECTING &&
		    ocl != cl &&
		    cl->me_client_id == ocl->me_client_id)
T
Tomas Winkler 已提交
789
			return true;
790 791

	}
T
Tomas Winkler 已提交
792 793

	return false;
794 795
}

796
/**
797
 * mei_cl_connect - connect host client to the me one
798 799
 *
 * @cl: host client
800
 * @file: pointer to file structure
801 802 803
 *
 * Locking: called under "dev->device_lock" lock
 *
804
 * Return: 0 on success, <0 on failure.
805 806 807 808 809 810 811 812 813 814 815 816
 */
int mei_cl_connect(struct mei_cl *cl, struct file *file)
{
	struct mei_device *dev;
	struct mei_cl_cb *cb;
	int rets;

	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

	dev = cl->dev;

817
	rets = pm_runtime_get(dev->dev);
818
	if (rets < 0 && rets != -EINPROGRESS) {
819
		pm_runtime_put_noidle(dev->dev);
820 821 822 823
		cl_err(dev, cl, "rpm: get failed %d\n", rets);
		return rets;
	}

824 825 826 827 828 829
	cb = mei_io_cb_init(cl, file);
	if (!cb) {
		rets = -ENOMEM;
		goto out;
	}

830
	cb->fop_type = MEI_FOP_CONNECT;
831

832 833
	/* run hbuf acquire last so we don't have to undo */
	if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
834
		cl->state = MEI_FILE_CONNECTING;
835 836 837 838 839 840 841
		if (mei_hbm_cl_connect_req(dev, cl)) {
			rets = -ENODEV;
			goto out;
		}
		cl->timer_count = MEI_CONNECT_TIMEOUT;
		list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
	} else {
842
		cl->state = MEI_FILE_INITIALIZING;
843 844 845 846
		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
	}

	mutex_unlock(&dev->device_lock);
847
	wait_event_timeout(cl->wait,
848 849 850
			(cl->state == MEI_FILE_CONNECTED ||
			 cl->state == MEI_FILE_DISCONNECTED),
			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
851 852 853
	mutex_lock(&dev->device_lock);

	if (cl->state != MEI_FILE_CONNECTED) {
854
		cl->state = MEI_FILE_DISCONNECTED;
855 856 857
		/* something went really wrong */
		if (!cl->status)
			cl->status = -EFAULT;
858 859 860 861 862 863 864 865

		mei_io_list_flush(&dev->ctrl_rd_list, cl);
		mei_io_list_flush(&dev->ctrl_wr_list, cl);
	}

	rets = cl->status;

out:
866
	cl_dbg(dev, cl, "rpm: autosuspend\n");
867 868
	pm_runtime_mark_last_busy(dev->dev);
	pm_runtime_put_autosuspend(dev->dev);
869

870 871 872 873
	mei_io_cb_free(cb);
	return rets;
}

874
/**
T
Tomas Winkler 已提交
875
 * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
876 877 878
 *
 * @cl: private data of the file object
 *
879
 * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
880 881 882
 *	-ENOENT if mei_cl is not present
 *	-EINVAL if single_recv_buf == 0
 */
T
Tomas Winkler 已提交
883
int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
884
{
T
Tomas Winkler 已提交
885
	struct mei_device *dev;
886
	struct mei_me_client *me_cl;
887
	int rets = 0;
888

T
Tomas Winkler 已提交
889 890 891 892 893
	if (WARN_ON(!cl || !cl->dev))
		return -EINVAL;

	dev = cl->dev;

894 895 896
	if (cl->mei_flow_ctrl_creds > 0)
		return 1;

897
	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
898
	if (!me_cl) {
899
		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
900
		return -ENOENT;
901
	}
902

903 904
	if (me_cl->mei_flow_ctrl_creds > 0) {
		rets = 1;
905
		if (WARN_ON(me_cl->props.single_recv_buf == 0))
906
			rets = -EINVAL;
907
	}
908 909
	mei_me_cl_put(me_cl);
	return rets;
910 911 912
}

/**
T
Tomas Winkler 已提交
913
 * mei_cl_flow_ctrl_reduce - reduces flow_control.
914 915
 *
 * @cl: private data of the file object
916
 *
917
 * Return:
918 919 920 921
 *	0 on success
 *	-ENOENT when me client is not found
 *	-EINVAL when ctrl credits are <= 0
 */
T
Tomas Winkler 已提交
922
int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
923
{
T
Tomas Winkler 已提交
924
	struct mei_device *dev;
925
	struct mei_me_client *me_cl;
926
	int rets;
927

T
Tomas Winkler 已提交
928 929 930 931 932
	if (WARN_ON(!cl || !cl->dev))
		return -EINVAL;

	dev = cl->dev;

933
	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
934
	if (!me_cl) {
935
		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
936
		return -ENOENT;
937
	}
938

939
	if (me_cl->props.single_recv_buf) {
940 941 942 943
		if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
			rets = -EINVAL;
			goto out;
		}
944 945
		me_cl->mei_flow_ctrl_creds--;
	} else {
946 947 948 949
		if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
			rets = -EINVAL;
			goto out;
		}
950
		cl->mei_flow_ctrl_creds--;
951
	}
952 953 954 955
	rets = 0;
out:
	mei_me_cl_put(me_cl);
	return rets;
956 957
}

958
/**
959
 * mei_cl_read_start - the start read client message function.
960
 *
T
Tomas Winkler 已提交
961
 * @cl: host client
A
Alexander Usyskin 已提交
962
 * @length: number of bytes to read
963
 *
964
 * Return: 0 on success, <0 on failure.
965
 */
T
Tomas Winkler 已提交
966
int mei_cl_read_start(struct mei_cl *cl, size_t length)
967
{
T
Tomas Winkler 已提交
968
	struct mei_device *dev;
969
	struct mei_cl_cb *cb;
970
	struct mei_me_client *me_cl;
971
	int rets;
972

T
Tomas Winkler 已提交
973 974 975 976 977
	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

	dev = cl->dev;

978
	if (!mei_cl_is_connected(cl))
979 980
		return -ENODEV;

981
	if (cl->read_cb) {
982
		cl_dbg(dev, cl, "read is pending.\n");
983 984
		return -EBUSY;
	}
985
	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
986
	if (!me_cl) {
987
		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
988
		return  -ENOTTY;
989
	}
990 991 992
	/* always allocate at least client max message */
	length = max_t(size_t, length, me_cl->props.max_msg_length);
	mei_me_cl_put(me_cl);
993

994
	rets = pm_runtime_get(dev->dev);
995
	if (rets < 0 && rets != -EINPROGRESS) {
996
		pm_runtime_put_noidle(dev->dev);
997 998 999 1000
		cl_err(dev, cl, "rpm: get failed %d\n", rets);
		return rets;
	}

1001
	cb = mei_io_cb_init(cl, NULL);
1002 1003 1004 1005
	if (!cb) {
		rets = -ENOMEM;
		goto out;
	}
1006

T
Tomas Winkler 已提交
1007
	rets = mei_io_cb_alloc_resp_buf(cb, length);
1008
	if (rets)
1009
		goto out;
1010

1011
	cb->fop_type = MEI_FOP_READ;
1012
	if (mei_hbuf_acquire(dev)) {
1013 1014
		rets = mei_hbm_cl_flow_control_req(dev, cl);
		if (rets < 0)
1015 1016
			goto out;

1017
		list_add_tail(&cb->list, &dev->read_list.list);
1018
	} else {
1019
		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
1020
	}
1021 1022 1023

	cl->read_cb = cb;

1024 1025
out:
	cl_dbg(dev, cl, "rpm: autosuspend\n");
1026 1027
	pm_runtime_mark_last_busy(dev->dev);
	pm_runtime_put_autosuspend(dev->dev);
1028 1029 1030 1031

	if (rets)
		mei_io_cb_free(cb);

1032 1033 1034
	return rets;
}

1035
/**
1036
 * mei_cl_irq_write - write a message to device
1037 1038 1039 1040 1041 1042
 *	from the interrupt thread context
 *
 * @cl: client
 * @cb: callback block.
 * @cmpl_list: complete list.
 *
1043
 * Return: 0, OK; otherwise error.
1044
 */
1045 1046
int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
		     struct mei_cl_cb *cmpl_list)
1047
{
1048 1049
	struct mei_device *dev;
	struct mei_msg_data *buf;
1050
	struct mei_msg_hdr mei_hdr;
1051 1052
	size_t len;
	u32 msg_slots;
1053
	int slots;
1054
	int rets;
1055

1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

	dev = cl->dev;

	buf = &cb->request_buffer;

	rets = mei_cl_flow_ctrl_creds(cl);
	if (rets < 0)
		return rets;

	if (rets == 0) {
1068
		cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
1069 1070 1071
		return 0;
	}

1072
	slots = mei_hbuf_empty_slots(dev);
1073 1074 1075
	len = buf->size - cb->buf_idx;
	msg_slots = mei_data2slots(len);

1076 1077 1078
	mei_hdr.host_addr = cl->host_client_id;
	mei_hdr.me_addr = cl->me_client_id;
	mei_hdr.reserved = 0;
1079
	mei_hdr.internal = cb->internal;
1080

1081
	if (slots >= msg_slots) {
1082 1083 1084
		mei_hdr.length = len;
		mei_hdr.msg_complete = 1;
	/* Split the message only if we can write the whole host buffer */
1085 1086 1087
	} else if (slots == dev->hbuf_depth) {
		msg_slots = slots;
		len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
1088 1089 1090 1091 1092 1093 1094
		mei_hdr.length = len;
		mei_hdr.msg_complete = 0;
	} else {
		/* wait for next time the host buffer is empty */
		return 0;
	}

1095
	cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
1096 1097
			cb->request_buffer.size, cb->buf_idx);

1098
	rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
1099 1100
	if (rets) {
		cl->status = rets;
1101
		list_move_tail(&cb->list, &cmpl_list->list);
1102
		return rets;
1103 1104 1105
	}

	cl->status = 0;
1106
	cl->writing_state = MEI_WRITING;
1107
	cb->buf_idx += mei_hdr.length;
1108

1109 1110
	if (mei_hdr.msg_complete) {
		if (mei_cl_flow_ctrl_reduce(cl))
1111
			return -EIO;
1112 1113 1114 1115 1116 1117
		list_move_tail(&cb->list, &dev->write_waiting_list.list);
	}

	return 0;
}

T
Tomas Winkler 已提交
1118 1119
/**
 * mei_cl_write - submit a write cb to mei device
1120
 *	assumes device_lock is locked
T
Tomas Winkler 已提交
1121 1122
 *
 * @cl: host client
1123
 * @cb: write callback with filled data
A
Alexander Usyskin 已提交
1124
 * @blocking: block until completed
T
Tomas Winkler 已提交
1125
 *
1126
 * Return: number of bytes sent on success, <0 on failure.
T
Tomas Winkler 已提交
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
 */
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
{
	struct mei_device *dev;
	struct mei_msg_data *buf;
	struct mei_msg_hdr mei_hdr;
	int rets;


	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

	if (WARN_ON(!cb))
		return -EINVAL;

	dev = cl->dev;


	buf = &cb->request_buffer;

1147
	cl_dbg(dev, cl, "size=%d\n", buf->size);
T
Tomas Winkler 已提交
1148

1149
	rets = pm_runtime_get(dev->dev);
1150
	if (rets < 0 && rets != -EINPROGRESS) {
1151
		pm_runtime_put_noidle(dev->dev);
1152 1153 1154
		cl_err(dev, cl, "rpm: get failed %d\n", rets);
		return rets;
	}
T
Tomas Winkler 已提交
1155 1156

	cb->fop_type = MEI_FOP_WRITE;
1157 1158 1159 1160 1161 1162 1163 1164
	cb->buf_idx = 0;
	cl->writing_state = MEI_IDLE;

	mei_hdr.host_addr = cl->host_client_id;
	mei_hdr.me_addr = cl->me_client_id;
	mei_hdr.reserved = 0;
	mei_hdr.msg_complete = 0;
	mei_hdr.internal = cb->internal;
T
Tomas Winkler 已提交
1165 1166 1167 1168 1169

	rets = mei_cl_flow_ctrl_creds(cl);
	if (rets < 0)
		goto err;

1170 1171 1172 1173 1174 1175 1176
	if (rets == 0) {
		cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
		rets = buf->size;
		goto out;
	}
	if (!mei_hbuf_acquire(dev)) {
		cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
T
Tomas Winkler 已提交
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189
		rets = buf->size;
		goto out;
	}

	/* Check for a maximum length */
	if (buf->size > mei_hbuf_max_len(dev)) {
		mei_hdr.length = mei_hbuf_max_len(dev);
		mei_hdr.msg_complete = 0;
	} else {
		mei_hdr.length = buf->size;
		mei_hdr.msg_complete = 1;
	}

1190 1191
	rets = mei_write_message(dev, &mei_hdr, buf->data);
	if (rets)
T
Tomas Winkler 已提交
1192 1193 1194 1195 1196 1197 1198
		goto err;

	cl->writing_state = MEI_WRITING;
	cb->buf_idx = mei_hdr.length;

out:
	if (mei_hdr.msg_complete) {
1199 1200
		rets = mei_cl_flow_ctrl_reduce(cl);
		if (rets < 0)
T
Tomas Winkler 已提交
1201
			goto err;
1202

T
Tomas Winkler 已提交
1203 1204 1205 1206 1207 1208 1209 1210 1211
		list_add_tail(&cb->list, &dev->write_waiting_list.list);
	} else {
		list_add_tail(&cb->list, &dev->write_list.list);
	}


	if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {

		mutex_unlock(&dev->device_lock);
1212 1213
		rets = wait_event_interruptible(cl->tx_wait,
				cl->writing_state == MEI_WRITE_COMPLETE);
T
Tomas Winkler 已提交
1214
		mutex_lock(&dev->device_lock);
1215 1216 1217 1218 1219 1220
		/* wait_event_interruptible returns -ERESTARTSYS */
		if (rets) {
			if (signal_pending(current))
				rets = -EINTR;
			goto err;
		}
T
Tomas Winkler 已提交
1221
	}
1222 1223

	rets = buf->size;
T
Tomas Winkler 已提交
1224
err:
1225
	cl_dbg(dev, cl, "rpm: autosuspend\n");
1226 1227
	pm_runtime_mark_last_busy(dev->dev);
	pm_runtime_put_autosuspend(dev->dev);
1228

T
Tomas Winkler 已提交
1229 1230 1231 1232
	return rets;
}


1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
/**
 * mei_cl_complete - processes completed operation for a client
 *
 * @cl: private data of the file object.
 * @cb: callback block.
 */
void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
{
	if (cb->fop_type == MEI_FOP_WRITE) {
		mei_io_cb_free(cb);
		cb = NULL;
		cl->writing_state = MEI_WRITE_COMPLETE;
		if (waitqueue_active(&cl->tx_wait))
			wake_up_interruptible(&cl->tx_wait);

	} else if (cb->fop_type == MEI_FOP_READ &&
			MEI_READING == cl->reading_state) {
		cl->reading_state = MEI_READ_COMPLETE;
		if (waitqueue_active(&cl->rx_wait))
			wake_up_interruptible(&cl->rx_wait);
		else
			mei_cl_bus_rx_event(cl);

	}
}

T
Tomas Winkler 已提交
1259

1260 1261 1262
/**
 * mei_cl_all_disconnect - disconnect forcefully all connected clients
 *
1263
 * @dev: mei device
1264 1265 1266 1267
 */

void mei_cl_all_disconnect(struct mei_device *dev)
{
1268
	struct mei_cl *cl;
1269

1270
	list_for_each_entry(cl, &dev->file_list, link) {
1271 1272 1273 1274 1275 1276 1277 1278
		cl->state = MEI_FILE_DISCONNECTED;
		cl->mei_flow_ctrl_creds = 0;
		cl->timer_count = 0;
	}
}


/**
T
Tomas Winkler 已提交
1279
 * mei_cl_all_wakeup  - wake up all readers and writers they can be interrupted
1280
 *
1281
 * @dev: mei device
1282
 */
T
Tomas Winkler 已提交
1283
void mei_cl_all_wakeup(struct mei_device *dev)
1284
{
1285
	struct mei_cl *cl;
1286

1287
	list_for_each_entry(cl, &dev->file_list, link) {
1288
		if (waitqueue_active(&cl->rx_wait)) {
1289
			cl_dbg(dev, cl, "Waking up reading client!\n");
1290 1291
			wake_up_interruptible(&cl->rx_wait);
		}
T
Tomas Winkler 已提交
1292
		if (waitqueue_active(&cl->tx_wait)) {
1293
			cl_dbg(dev, cl, "Waking up writing client!\n");
T
Tomas Winkler 已提交
1294 1295
			wake_up_interruptible(&cl->tx_wait);
		}
1296 1297 1298 1299 1300
	}
}

/**
 * mei_cl_all_write_clear - clear all pending writes
1301 1302
 *
 * @dev: mei device
1303 1304 1305
 */
void mei_cl_all_write_clear(struct mei_device *dev)
{
1306 1307
	mei_io_list_free(&dev->write_list, NULL);
	mei_io_list_free(&dev->write_waiting_list, NULL);
1308 1309 1310
}