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
 *         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);
}

/**
324
 * __mei_io_list_flush - removes and frees cbs belonging to cl.
325 326 327 328
 *
 * @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
/**
 * 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;

379
	kfree(cb->buf.data);
380 381
	kfree(cb);
}
382

383 384 385
/**
 * mei_io_cb_init - allocate and initialize io callback
 *
386
 * @cl: mei client
387
 * @type: operation type
388
 * @fp: pointer to file structure
389
 *
390
 * Return: mei_cl_cb pointer or NULL;
391
 */
392 393
struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
				 struct file *fp)
394 395 396 397 398 399 400 401 402 403
{
	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;
404
	cb->cl = cl;
405
	cb->buf_idx = 0;
406
	cb->fop_type = type;
407 408 409 410
	return cb;
}

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

	if (length == 0)
		return 0;

428 429
	cb->buf.data = kmalloc(length, GFP_KERNEL);
	if (!cb->buf.data)
430
		return -ENOMEM;
431
	cb->buf.size = length;
432 433
	return 0;
}
434

435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
/**
 * mei_cl_alloc_cb - a convenient wrapper for allocating read cb
 *
 * @cl: host client
 * @length: size of the buffer
 * @type: operation type
 * @fp: associated file pointer (might be NULL)
 *
 * Return: cb on success and NULL on failure
 */
struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
				  enum mei_cb_file_ops type, struct file *fp)
{
	struct mei_cl_cb *cb;

	cb = mei_io_cb_init(cl, type, fp);
	if (!cb)
		return NULL;

	if (mei_io_cb_alloc_buf(cb, length)) {
		mei_io_cb_free(cb);
		return NULL;
	}

	return cb;
}

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

T
Tomas Winkler 已提交
473
	if (WARN_ON(!cl || !cl->dev))
474 475
		return -EINVAL;

476 477 478
	dev = cl->dev;

	cl_dbg(dev, cl, "remove list entry belonging to cl\n");
479
	mei_io_list_flush(&cl->dev->read_list, cl);
480 481
	mei_io_list_free(&cl->dev->write_list, cl);
	mei_io_list_free(&cl->dev->write_waiting_list, cl);
482 483 484 485 486 487 488
	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;
}

489

490
/**
491
 * mei_cl_init - initializes cl.
492 493 494 495 496 497 498 499 500 501 502
 *
 * @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);
503
	INIT_LIST_HEAD(&cl->device_link);
504 505 506 507 508 509 510 511 512
	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
513
 * Return:  The allocated file or NULL on failure
514 515 516 517 518 519 520 521 522 523 524 525 526 527
 */
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 已提交
528 529 530
/**
 * mei_cl_find_read_cb - find this cl's callback in the read list
 *
531 532
 * @cl: host client
 *
533
 * Return: cb on success, NULL on error
T
Tomas Winkler 已提交
534 535 536 537
 */
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
{
	struct mei_device *dev = cl->dev;
538
	struct mei_cl_cb *cb;
T
Tomas Winkler 已提交
539

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

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

561
	if (WARN_ON(!cl || !cl->dev))
562 563
		return -EINVAL;

T
Tomas Winkler 已提交
564 565
	dev = cl->dev;

566
	/* If Id is not assigned get one*/
567 568 569
	if (id == MEI_HOST_CLIENT_ID_ANY)
		id = find_first_zero_bit(dev->host_clients_map,
					MEI_CLIENTS_MAX);
570

571
	if (id >= MEI_CLIENTS_MAX) {
572
		dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
573 574 575
		return -EMFILE;
	}

T
Tomas Winkler 已提交
576 577
	open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
	if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
578
		dev_err(dev->dev, "open_handle_count exceeded %d",
579 580
			MEI_MAX_OPEN_HANDLE_COUNT);
		return -EMFILE;
581 582
	}

583 584 585 586 587 588 589 590 591
	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;

592
	cl_dbg(dev, cl, "link cl\n");
593
	return 0;
594
}
595

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

607 608 609 610
	/* don't shout on error exit path */
	if (!cl)
		return 0;

611 612 613
	/* wd and amthif might not be initialized */
	if (!cl->dev)
		return 0;
T
Tomas Winkler 已提交
614 615 616

	dev = cl->dev;

617 618
	cl_dbg(dev, cl, "unlink client");

T
Tomas Winkler 已提交
619 620 621 622 623 624 625 626 627 628 629
	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 已提交
630
	return 0;
631 632 633 634 635
}


void mei_host_client_init(struct work_struct *work)
{
636 637
	struct mei_device *dev =
		container_of(work, struct mei_device, init_work);
638
	struct mei_me_client *me_cl;
639 640 641 642

	mutex_lock(&dev->device_lock);


643 644 645 646 647 648 649 650 651 652 653
	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);
654

655 656

	dev->dev_state = MEI_DEV_ENABLED;
657
	dev->reset_count = 0;
658
	mutex_unlock(&dev->device_lock);
659

660 661 662
	pm_runtime_mark_last_busy(dev->dev);
	dev_dbg(dev->dev, "rpm: autosuspend\n");
	pm_runtime_autosuspend(dev->dev);
663 664
}

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

679
	if (!dev->hbuf_is_ready) {
680
		dev_dbg(dev->dev, "hbuf is not ready\n");
681 682 683 684 685 686 687
		return false;
	}

	dev->hbuf_is_ready = false;

	return true;
}
688 689

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

T
Tomas Winkler 已提交
704
	if (WARN_ON(!cl || !cl->dev))
705 706
		return -ENODEV;

T
Tomas Winkler 已提交
707 708
	dev = cl->dev;

709 710
	cl_dbg(dev, cl, "disconnecting");

711 712 713
	if (cl->state != MEI_FILE_DISCONNECTING)
		return 0;

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

721 722 723
	cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT, NULL);
	rets = cb ? 0 : -ENOMEM;
	if (rets)
724
		goto free;
725

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

	}
	mutex_unlock(&dev->device_lock);

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

	mutex_lock(&dev->device_lock);
747

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

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

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


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

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

	dev = cl->dev;

786 787 788 789
	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 已提交
790
			return true;
791 792

	}
T
Tomas Winkler 已提交
793 794

	return false;
795 796
}

797
/**
798
 * mei_cl_connect - connect host client to the me one
799 800
 *
 * @cl: host client
801
 * @file: pointer to file structure
802 803 804
 *
 * Locking: called under "dev->device_lock" lock
 *
805
 * Return: 0 on success, <0 on failure.
806 807 808 809 810 811 812 813 814 815 816 817
 */
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;

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

825 826 827
	cb = mei_io_cb_init(cl, MEI_FOP_CONNECT, file);
	rets = cb ? 0 : -ENOMEM;
	if (rets)
828 829
		goto out;

830 831
	/* run hbuf acquire last so we don't have to undo */
	if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
832
		cl->state = MEI_FILE_CONNECTING;
833 834 835 836 837 838 839
		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 {
840
		cl->state = MEI_FILE_INITIALIZING;
841 842 843 844
		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
	}

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

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

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

	rets = cl->status;

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

868 869 870 871
	mei_io_cb_free(cb);
	return rets;
}

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

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

	dev = cl->dev;

892 893 894
	if (cl->mei_flow_ctrl_creds > 0)
		return 1;

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

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

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

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

	dev = cl->dev;

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

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

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

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

	dev = cl->dev;

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

980
	if (cl->read_cb) {
981
		cl_dbg(dev, cl, "read is pending.\n");
982 983
		return -EBUSY;
	}
984
	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
985
	if (!me_cl) {
986
		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
987
		return  -ENOTTY;
988
	}
989 990 991
	/* 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);
992

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

1000 1001
	cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp);
	rets = cb ? 0 : -ENOMEM;
1002
	if (rets)
1003
		goto out;
1004

1005
	if (mei_hbuf_acquire(dev)) {
1006 1007
		rets = mei_hbm_cl_flow_control_req(dev, cl);
		if (rets < 0)
1008 1009
			goto out;

1010
		list_add_tail(&cb->list, &dev->read_list.list);
1011
	} else {
1012
		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
1013
	}
1014 1015 1016

	cl->read_cb = cb;

1017 1018
out:
	cl_dbg(dev, cl, "rpm: autosuspend\n");
1019 1020
	pm_runtime_mark_last_busy(dev->dev);
	pm_runtime_put_autosuspend(dev->dev);
1021 1022 1023 1024

	if (rets)
		mei_io_cb_free(cb);

1025 1026 1027
	return rets;
}

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

1049 1050 1051 1052 1053
	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

	dev = cl->dev;

1054
	buf = &cb->buf;
1055 1056 1057 1058 1059 1060

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

	if (rets == 0) {
1061
		cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
1062 1063 1064
		return 0;
	}

1065
	slots = mei_hbuf_empty_slots(dev);
1066 1067 1068
	len = buf->size - cb->buf_idx;
	msg_slots = mei_data2slots(len);

1069 1070 1071
	mei_hdr.host_addr = cl->host_client_id;
	mei_hdr.me_addr = cl->me_client_id;
	mei_hdr.reserved = 0;
1072
	mei_hdr.internal = cb->internal;
1073

1074
	if (slots >= msg_slots) {
1075 1076 1077
		mei_hdr.length = len;
		mei_hdr.msg_complete = 1;
	/* Split the message only if we can write the whole host buffer */
1078 1079 1080
	} else if (slots == dev->hbuf_depth) {
		msg_slots = slots;
		len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
1081 1082 1083 1084 1085 1086 1087
		mei_hdr.length = len;
		mei_hdr.msg_complete = 0;
	} else {
		/* wait for next time the host buffer is empty */
		return 0;
	}

1088
	cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
1089
			cb->buf.size, cb->buf_idx);
1090

1091
	rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
1092 1093
	if (rets) {
		cl->status = rets;
1094
		list_move_tail(&cb->list, &cmpl_list->list);
1095
		return rets;
1096 1097 1098
	}

	cl->status = 0;
1099
	cl->writing_state = MEI_WRITING;
1100
	cb->buf_idx += mei_hdr.length;
1101
	cb->completed = mei_hdr.msg_complete == 1;
1102

1103 1104
	if (mei_hdr.msg_complete) {
		if (mei_cl_flow_ctrl_reduce(cl))
1105
			return -EIO;
1106 1107 1108 1109 1110 1111
		list_move_tail(&cb->list, &dev->write_waiting_list.list);
	}

	return 0;
}

T
Tomas Winkler 已提交
1112 1113
/**
 * mei_cl_write - submit a write cb to mei device
1114
 *	assumes device_lock is locked
T
Tomas Winkler 已提交
1115 1116
 *
 * @cl: host client
1117
 * @cb: write callback with filled data
A
Alexander Usyskin 已提交
1118
 * @blocking: block until completed
T
Tomas Winkler 已提交
1119
 *
1120
 * Return: number of bytes sent on success, <0 on failure.
T
Tomas Winkler 已提交
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
 */
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;


1139
	buf = &cb->buf;
T
Tomas Winkler 已提交
1140

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

1143
	rets = pm_runtime_get(dev->dev);
1144
	if (rets < 0 && rets != -EINPROGRESS) {
1145
		pm_runtime_put_noidle(dev->dev);
1146 1147 1148
		cl_err(dev, cl, "rpm: get failed %d\n", rets);
		return rets;
	}
T
Tomas Winkler 已提交
1149

1150 1151 1152 1153 1154 1155 1156 1157
	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 已提交
1158 1159 1160 1161 1162

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

1163 1164 1165 1166 1167 1168 1169
	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 已提交
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182
		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;
	}

1183 1184
	rets = mei_write_message(dev, &mei_hdr, buf->data);
	if (rets)
T
Tomas Winkler 已提交
1185 1186 1187 1188
		goto err;

	cl->writing_state = MEI_WRITING;
	cb->buf_idx = mei_hdr.length;
1189
	cb->completed = mei_hdr.msg_complete == 1;
T
Tomas Winkler 已提交
1190 1191 1192

out:
	if (mei_hdr.msg_complete) {
1193 1194
		rets = mei_cl_flow_ctrl_reduce(cl);
		if (rets < 0)
T
Tomas Winkler 已提交
1195
			goto err;
1196

T
Tomas Winkler 已提交
1197 1198 1199 1200 1201 1202 1203 1204 1205
		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);
1206 1207
		rets = wait_event_interruptible(cl->tx_wait,
				cl->writing_state == MEI_WRITE_COMPLETE);
T
Tomas Winkler 已提交
1208
		mutex_lock(&dev->device_lock);
1209 1210 1211 1212 1213 1214
		/* wait_event_interruptible returns -ERESTARTSYS */
		if (rets) {
			if (signal_pending(current))
				rets = -EINTR;
			goto err;
		}
T
Tomas Winkler 已提交
1215
	}
1216 1217

	rets = buf->size;
T
Tomas Winkler 已提交
1218
err:
1219
	cl_dbg(dev, cl, "rpm: autosuspend\n");
1220 1221
	pm_runtime_mark_last_busy(dev->dev);
	pm_runtime_put_autosuspend(dev->dev);
1222

T
Tomas Winkler 已提交
1223 1224 1225 1226
	return rets;
}


1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252
/**
 * 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 已提交
1253

1254 1255 1256
/**
 * mei_cl_all_disconnect - disconnect forcefully all connected clients
 *
1257
 * @dev: mei device
1258 1259 1260 1261
 */

void mei_cl_all_disconnect(struct mei_device *dev)
{
1262
	struct mei_cl *cl;
1263

1264
	list_for_each_entry(cl, &dev->file_list, link) {
1265 1266 1267 1268 1269 1270 1271 1272
		cl->state = MEI_FILE_DISCONNECTED;
		cl->mei_flow_ctrl_creds = 0;
		cl->timer_count = 0;
	}
}


/**
T
Tomas Winkler 已提交
1273
 * mei_cl_all_wakeup  - wake up all readers and writers they can be interrupted
1274
 *
1275
 * @dev: mei device
1276
 */
T
Tomas Winkler 已提交
1277
void mei_cl_all_wakeup(struct mei_device *dev)
1278
{
1279
	struct mei_cl *cl;
1280

1281
	list_for_each_entry(cl, &dev->file_list, link) {
1282
		if (waitqueue_active(&cl->rx_wait)) {
1283
			cl_dbg(dev, cl, "Waking up reading client!\n");
1284 1285
			wake_up_interruptible(&cl->rx_wait);
		}
T
Tomas Winkler 已提交
1286
		if (waitqueue_active(&cl->tx_wait)) {
1287
			cl_dbg(dev, cl, "Waking up writing client!\n");
T
Tomas Winkler 已提交
1288 1289
			wake_up_interruptible(&cl->tx_wait);
		}
1290 1291 1292 1293 1294
	}
}

/**
 * mei_cl_all_write_clear - clear all pending writes
1295 1296
 *
 * @dev: mei device
1297 1298 1299
 */
void mei_cl_all_write_clear(struct mei_device *dev)
{
1300 1301
	mei_io_list_free(&dev->write_list, NULL);
	mei_io_list_free(&dev->write_waiting_list, NULL);
1302 1303 1304
}