client.c 25.8 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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
/**
 * 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)
{
	if (me_cl)
		kref_get(&me_cl->refcnt);

	return me_cl;
}

/**
 * mei_me_cl_release - unlink and free me client
 *
 * 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);
	list_del(&me_cl->list);
	kfree(me_cl);
}
/**
 * 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 已提交
84
/**
85
 * mei_me_cl_by_uuid - locate me client by uuid
86
 *	increases ref count
T
Tomas Winkler 已提交
87 88
 *
 * @dev: mei device
89
 * @uuid: me client uuid
90 91 92
 *
 * Locking: called under "dev->device_lock" lock
 *
93
 * Return: me client or NULL if not found
T
Tomas Winkler 已提交
94
 */
95 96
struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
					const uuid_le *uuid)
T
Tomas Winkler 已提交
97
{
98
	struct mei_me_client *me_cl;
T
Tomas Winkler 已提交
99

100 101
	list_for_each_entry(me_cl, &dev->me_clients, list)
		if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
102
			return mei_me_cl_get(me_cl);
T
Tomas Winkler 已提交
103

104
	return NULL;
T
Tomas Winkler 已提交
105 106 107
}

/**
108
 * mei_me_cl_by_id - locate me client by client id
109
 *	increases ref count
T
Tomas Winkler 已提交
110 111 112 113 114 115
 *
 * @dev: the device structure
 * @client_id: me client id
 *
 * Locking: called under "dev->device_lock" lock
 *
116
 * Return: me client or NULL if not found
T
Tomas Winkler 已提交
117
 */
118
struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
T
Tomas Winkler 已提交
119
{
120

121
	struct mei_me_client *me_cl;
T
Tomas Winkler 已提交
122

123 124
	list_for_each_entry(me_cl, &dev->me_clients, list)
		if (me_cl->client_id == client_id)
125 126
			return mei_me_cl_get(me_cl);

127
	return NULL;
T
Tomas Winkler 已提交
128
}
129

130 131
/**
 * mei_me_cl_by_uuid_id - locate me client by client id and uuid
132
 *	increases ref count
133 134 135 136 137 138 139 140 141
 *
 * @dev: the device structure
 * @uuid: me client uuid
 * @client_id: me client id
 *
 * Locking: called under "dev->device_lock" lock
 *
 * Return: me client or NULL if not found
 */
142 143 144 145 146 147 148 149
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;

	list_for_each_entry(me_cl, &dev->me_clients, list)
		if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
		    me_cl->client_id == client_id)
150 151
			return mei_me_cl_get(me_cl);

152 153 154
	return NULL;
}

155
/**
156
 * mei_me_cl_rm_by_uuid - remove all me clients matching uuid
157 158 159
 *
 * @dev: the device structure
 * @uuid: me client uuid
160 161
 *
 * Locking: called under "dev->device_lock" lock
162
 */
163
void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid)
164 165 166
{
	struct mei_me_client *me_cl, *next;

167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
	dev_dbg(dev->dev, "remove %pUl\n", uuid);
	list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
		if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
			mei_me_cl_put(me_cl);
}

/**
 * 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)
{
	struct mei_me_client *me_cl, *next;
	const uuid_le *pn;

	dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id);
188
	list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
189 190 191
		pn =  &me_cl->props.protocol_name;
		if (me_cl->client_id == id && uuid_le_cmp(*uuid, *pn) == 0)
			mei_me_cl_put(me_cl);
192 193 194
	}
}

195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
/**
 * 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;

	list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
			mei_me_cl_put(me_cl);
}


211 212

/**
213
 * mei_cl_cmp_id - tells if the clients are the same
214
 *
215 216 217
 * @cl1: host client 1
 * @cl2: host client 2
 *
218
 * Return: true  - if the clients has same host and me ids
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
 *         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
235
 */
236 237
static void __mei_io_list_flush(struct mei_cl_cb *list,
				struct mei_cl *cl, bool free)
238 239 240 241
{
	struct mei_cl_cb *cb;
	struct mei_cl_cb *next;

242
	/* enable removing everything if no cl is specified */
243
	list_for_each_entry_safe(cb, next, &list->list, list) {
244
		if (!cl || mei_cl_cmp_id(cl, cb->cl)) {
245
			list_del(&cb->list);
246 247 248
			if (free)
				mei_io_cb_free(cb);
		}
249 250 251
	}
}

252 253 254 255 256 257
/**
 * mei_io_list_flush - removes list entry belonging to cl.
 *
 * @list:  An instance of our list structure
 * @cl: host client
 */
258
void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
{
	__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);
}

275 276 277 278 279 280 281 282 283 284 285 286 287 288
/**
 * 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);
}
289

290 291 292
/**
 * mei_io_cb_init - allocate and initialize io callback
 *
293
 * @cl: mei client
294
 * @fp: pointer to file structure
295
 *
296
 * Return: mei_cl_cb pointer or NULL;
297 298 299 300 301 302 303 304 305 306 307 308
 */
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;
309
	cb->cl = cl;
310 311 312 313 314 315 316
	cb->buf_idx = 0;
	return cb;
}

/**
 * mei_io_cb_alloc_req_buf - allocate request buffer
 *
317 318
 * @cb: io callback structure
 * @length: size of the buffer
319
 *
320
 * Return: 0 on success
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
 *         -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;
}
/**
339
 * mei_io_cb_alloc_resp_buf - allocate response buffer
340
 *
341 342
 * @cb: io callback structure
 * @length: size of the buffer
343
 *
344
 * Return: 0 on success
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
 *         -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;
}

363

364 365 366 367 368

/**
 * mei_cl_flush_queues - flushes queue lists belonging to cl.
 *
 * @cl: host client
A
Alexander Usyskin 已提交
369 370
 *
 * Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
371 372 373
 */
int mei_cl_flush_queues(struct mei_cl *cl)
{
374 375
	struct mei_device *dev;

T
Tomas Winkler 已提交
376
	if (WARN_ON(!cl || !cl->dev))
377 378
		return -EINVAL;

379 380 381
	dev = cl->dev;

	cl_dbg(dev, cl, "remove list entry belonging to cl\n");
382
	mei_io_list_flush(&cl->dev->read_list, cl);
383 384
	mei_io_list_free(&cl->dev->write_list, cl);
	mei_io_list_free(&cl->dev->write_waiting_list, cl);
385 386 387 388 389 390 391
	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;
}

392

393
/**
394
 * mei_cl_init - initializes cl.
395 396 397 398 399 400 401 402 403 404 405
 *
 * @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);
406
	INIT_LIST_HEAD(&cl->device_link);
407 408 409 410 411 412 413 414 415
	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
416
 * Return:  The allocated file or NULL on failure
417 418 419 420 421 422 423 424 425 426 427 428 429 430
 */
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 已提交
431 432 433
/**
 * mei_cl_find_read_cb - find this cl's callback in the read list
 *
434 435
 * @cl: host client
 *
436
 * Return: cb on success, NULL on error
T
Tomas Winkler 已提交
437 438 439 440
 */
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
{
	struct mei_device *dev = cl->dev;
441
	struct mei_cl_cb *cb;
T
Tomas Winkler 已提交
442

443
	list_for_each_entry(cb, &dev->read_list.list, list)
T
Tomas Winkler 已提交
444 445 446 447 448
		if (mei_cl_cmp_id(cl, cb->cl))
			return cb;
	return NULL;
}

449
/** mei_cl_link: allocate host id in the host map
450
 *
451
 * @cl - host client
452
 * @id - fixed host id or -1 for generic one
453
 *
454
 * Return: 0 on success
455 456 457
 *	-EINVAL on incorrect values
 *	-ENONET if client not found
 */
458
int mei_cl_link(struct mei_cl *cl, int id)
459
{
T
Tomas Winkler 已提交
460
	struct mei_device *dev;
T
Tomas Winkler 已提交
461
	long open_handle_count;
462

463
	if (WARN_ON(!cl || !cl->dev))
464 465
		return -EINVAL;

T
Tomas Winkler 已提交
466 467
	dev = cl->dev;

468
	/* If Id is not assigned get one*/
469 470 471
	if (id == MEI_HOST_CLIENT_ID_ANY)
		id = find_first_zero_bit(dev->host_clients_map,
					MEI_CLIENTS_MAX);
472

473
	if (id >= MEI_CLIENTS_MAX) {
474
		dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
475 476 477
		return -EMFILE;
	}

T
Tomas Winkler 已提交
478 479
	open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
	if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
480
		dev_err(dev->dev, "open_handle_count exceeded %d",
481 482
			MEI_MAX_OPEN_HANDLE_COUNT);
		return -EMFILE;
483 484
	}

485 486 487 488 489 490 491 492 493
	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;

494
	cl_dbg(dev, cl, "link cl\n");
495
	return 0;
496
}
497

498
/**
T
Tomas Winkler 已提交
499
 * mei_cl_unlink - remove me_cl from the list
500
 *
501
 * @cl: host client
A
Alexander Usyskin 已提交
502 503
 *
 * Return: always 0
504
 */
T
Tomas Winkler 已提交
505
int mei_cl_unlink(struct mei_cl *cl)
506
{
T
Tomas Winkler 已提交
507 508
	struct mei_device *dev;

509 510 511 512
	/* don't shout on error exit path */
	if (!cl)
		return 0;

513 514 515
	/* wd and amthif might not be initialized */
	if (!cl->dev)
		return 0;
T
Tomas Winkler 已提交
516 517 518

	dev = cl->dev;

519 520
	cl_dbg(dev, cl, "unlink client");

T
Tomas Winkler 已提交
521 522 523 524 525 526 527 528 529 530 531
	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 已提交
532
	return 0;
533 534 535 536 537 538 539
}


void mei_host_client_init(struct work_struct *work)
{
	struct mei_device *dev = container_of(work,
					      struct mei_device, init_work);
540 541
	struct mei_me_client *me_cl;
	struct mei_client_properties *props;
542 543 544

	mutex_lock(&dev->device_lock);

545 546
	list_for_each_entry(me_cl, &dev->me_clients, list) {
		props = &me_cl->props;
547

548
		if (!uuid_le_cmp(props->protocol_name, mei_amthif_guid))
549
			mei_amthif_host_init(dev);
550
		else if (!uuid_le_cmp(props->protocol_name, mei_wd_guid))
551
			mei_wd_host_init(dev);
552
		else if (!uuid_le_cmp(props->protocol_name, mei_nfc_guid))
553 554
			mei_nfc_host_init(dev);

555 556 557
	}

	dev->dev_state = MEI_DEV_ENABLED;
558
	dev->reset_count = 0;
559 560

	mutex_unlock(&dev->device_lock);
561

562 563 564
	pm_runtime_mark_last_busy(dev->dev);
	dev_dbg(dev->dev, "rpm: autosuspend\n");
	pm_runtime_autosuspend(dev->dev);
565 566
}

567
/**
568
 * mei_hbuf_acquire - try to acquire host buffer
569 570
 *
 * @dev: the device structure
571
 * Return: true if host buffer was acquired
572 573 574
 */
bool mei_hbuf_acquire(struct mei_device *dev)
{
575 576
	if (mei_pg_state(dev) == MEI_PG_ON ||
	    dev->pg_event == MEI_PG_EVENT_WAIT) {
577
		dev_dbg(dev->dev, "device is in pg\n");
578 579 580
		return false;
	}

581
	if (!dev->hbuf_is_ready) {
582
		dev_dbg(dev->dev, "hbuf is not ready\n");
583 584 585 586 587 588 589
		return false;
	}

	dev->hbuf_is_ready = false;

	return true;
}
590 591

/**
592
 * mei_cl_disconnect - disconnect host client from the me one
593
 *
T
Tomas Winkler 已提交
594
 * @cl: host client
595 596 597
 *
 * Locking: called under "dev->device_lock" lock
 *
598
 * Return: 0 on success, <0 on failure.
599
 */
T
Tomas Winkler 已提交
600
int mei_cl_disconnect(struct mei_cl *cl)
601
{
T
Tomas Winkler 已提交
602
	struct mei_device *dev;
603
	struct mei_cl_cb *cb;
604
	int rets;
605

T
Tomas Winkler 已提交
606
	if (WARN_ON(!cl || !cl->dev))
607 608
		return -ENODEV;

T
Tomas Winkler 已提交
609 610
	dev = cl->dev;

611 612
	cl_dbg(dev, cl, "disconnecting");

613 614 615
	if (cl->state != MEI_FILE_DISCONNECTING)
		return 0;

616
	rets = pm_runtime_get(dev->dev);
617
	if (rets < 0 && rets != -EINPROGRESS) {
618
		pm_runtime_put_noidle(dev->dev);
619 620 621 622
		cl_err(dev, cl, "rpm: get failed %d\n", rets);
		return rets;
	}

623
	cb = mei_io_cb_init(cl, NULL);
624 625 626 627
	if (!cb) {
		rets = -ENOMEM;
		goto free;
	}
628

629 630
	cb->fop_type = MEI_FOP_DISCONNECT;

631
	if (mei_hbuf_acquire(dev)) {
632 633
		if (mei_hbm_cl_disconnect_req(dev, cl)) {
			rets = -ENODEV;
634
			cl_err(dev, cl, "failed to disconnect.\n");
635 636
			goto free;
		}
637
		cl->timer_count = MEI_CONNECT_TIMEOUT;
638 639 640
		mdelay(10); /* Wait for hardware disconnection ready */
		list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
	} else {
641
		cl_dbg(dev, cl, "add disconnect cb to control write list\n");
642 643 644 645 646
		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);

	}
	mutex_unlock(&dev->device_lock);

647
	wait_event_timeout(cl->wait,
648 649 650 651
			MEI_FILE_DISCONNECTED == cl->state,
			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));

	mutex_lock(&dev->device_lock);
652

653 654
	if (MEI_FILE_DISCONNECTED == cl->state) {
		rets = 0;
655
		cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
656
	} else {
657 658
		cl_dbg(dev, cl, "timeout on disconnect from FW client.\n");
		rets = -ETIME;
659 660 661 662 663
	}

	mei_io_list_flush(&dev->ctrl_rd_list, cl);
	mei_io_list_flush(&dev->ctrl_wr_list, cl);
free:
664
	cl_dbg(dev, cl, "rpm: autosuspend\n");
665 666
	pm_runtime_mark_last_busy(dev->dev);
	pm_runtime_put_autosuspend(dev->dev);
667

668 669 670 671 672 673
	mei_io_cb_free(cb);
	return rets;
}


/**
T
Tomas Winkler 已提交
674 675
 * mei_cl_is_other_connecting - checks if other
 *    client with the same me client id is connecting
676 677 678
 *
 * @cl: private data of the file object
 *
679
 * Return: true if other client is connected, false - otherwise.
680
 */
T
Tomas Winkler 已提交
681
bool mei_cl_is_other_connecting(struct mei_cl *cl)
682
{
T
Tomas Winkler 已提交
683
	struct mei_device *dev;
684
	struct mei_cl *ocl; /* the other client */
685

T
Tomas Winkler 已提交
686 687 688 689 690
	if (WARN_ON(!cl || !cl->dev))
		return false;

	dev = cl->dev;

691 692 693 694
	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 已提交
695
			return true;
696 697

	}
T
Tomas Winkler 已提交
698 699

	return false;
700 701
}

702
/**
703
 * mei_cl_connect - connect host client to the me one
704 705
 *
 * @cl: host client
706
 * @file: pointer to file structure
707 708 709
 *
 * Locking: called under "dev->device_lock" lock
 *
710
 * Return: 0 on success, <0 on failure.
711 712 713 714 715 716 717 718 719 720 721 722
 */
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;

723
	rets = pm_runtime_get(dev->dev);
724
	if (rets < 0 && rets != -EINPROGRESS) {
725
		pm_runtime_put_noidle(dev->dev);
726 727 728 729
		cl_err(dev, cl, "rpm: get failed %d\n", rets);
		return rets;
	}

730 731 732 733 734 735
	cb = mei_io_cb_init(cl, file);
	if (!cb) {
		rets = -ENOMEM;
		goto out;
	}

736
	cb->fop_type = MEI_FOP_CONNECT;
737

738 739
	/* run hbuf acquire last so we don't have to undo */
	if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
740
		cl->state = MEI_FILE_CONNECTING;
741 742 743 744 745 746 747
		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 {
748
		cl->state = MEI_FILE_INITIALIZING;
749 750 751 752
		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
	}

	mutex_unlock(&dev->device_lock);
753
	wait_event_timeout(cl->wait,
754 755 756
			(cl->state == MEI_FILE_CONNECTED ||
			 cl->state == MEI_FILE_DISCONNECTED),
			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
757 758 759
	mutex_lock(&dev->device_lock);

	if (cl->state != MEI_FILE_CONNECTED) {
760
		cl->state = MEI_FILE_DISCONNECTED;
761 762 763
		/* something went really wrong */
		if (!cl->status)
			cl->status = -EFAULT;
764 765 766 767 768 769 770 771

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

	rets = cl->status;

out:
772
	cl_dbg(dev, cl, "rpm: autosuspend\n");
773 774
	pm_runtime_mark_last_busy(dev->dev);
	pm_runtime_put_autosuspend(dev->dev);
775

776 777 778 779
	mei_io_cb_free(cb);
	return rets;
}

780
/**
T
Tomas Winkler 已提交
781
 * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
782 783 784
 *
 * @cl: private data of the file object
 *
785
 * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
786 787 788
 *	-ENOENT if mei_cl is not present
 *	-EINVAL if single_recv_buf == 0
 */
T
Tomas Winkler 已提交
789
int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
790
{
T
Tomas Winkler 已提交
791
	struct mei_device *dev;
792
	struct mei_me_client *me_cl;
793
	int rets = 0;
794

T
Tomas Winkler 已提交
795 796 797 798 799
	if (WARN_ON(!cl || !cl->dev))
		return -EINVAL;

	dev = cl->dev;

800 801 802
	if (cl->mei_flow_ctrl_creds > 0)
		return 1;

803
	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
804
	if (!me_cl) {
805
		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
806
		return -ENOENT;
807
	}
808

809 810
	if (me_cl->mei_flow_ctrl_creds > 0) {
		rets = 1;
811
		if (WARN_ON(me_cl->props.single_recv_buf == 0))
812
			rets = -EINVAL;
813
	}
814 815
	mei_me_cl_put(me_cl);
	return rets;
816 817 818
}

/**
T
Tomas Winkler 已提交
819
 * mei_cl_flow_ctrl_reduce - reduces flow_control.
820 821
 *
 * @cl: private data of the file object
822
 *
823
 * Return:
824 825 826 827
 *	0 on success
 *	-ENOENT when me client is not found
 *	-EINVAL when ctrl credits are <= 0
 */
T
Tomas Winkler 已提交
828
int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
829
{
T
Tomas Winkler 已提交
830
	struct mei_device *dev;
831
	struct mei_me_client *me_cl;
832
	int rets;
833

T
Tomas Winkler 已提交
834 835 836 837 838
	if (WARN_ON(!cl || !cl->dev))
		return -EINVAL;

	dev = cl->dev;

839
	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
840
	if (!me_cl) {
841
		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
842
		return -ENOENT;
843
	}
844

845
	if (me_cl->props.single_recv_buf) {
846 847 848 849
		if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
			rets = -EINVAL;
			goto out;
		}
850 851
		me_cl->mei_flow_ctrl_creds--;
	} else {
852 853 854 855
		if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
			rets = -EINVAL;
			goto out;
		}
856
		cl->mei_flow_ctrl_creds--;
857
	}
858 859 860 861
	rets = 0;
out:
	mei_me_cl_put(me_cl);
	return rets;
862 863
}

864
/**
865
 * mei_cl_read_start - the start read client message function.
866
 *
T
Tomas Winkler 已提交
867
 * @cl: host client
A
Alexander Usyskin 已提交
868
 * @length: number of bytes to read
869
 *
870
 * Return: 0 on success, <0 on failure.
871
 */
T
Tomas Winkler 已提交
872
int mei_cl_read_start(struct mei_cl *cl, size_t length)
873
{
T
Tomas Winkler 已提交
874
	struct mei_device *dev;
875
	struct mei_cl_cb *cb;
876
	struct mei_me_client *me_cl;
877
	int rets;
878

T
Tomas Winkler 已提交
879 880 881 882 883
	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

	dev = cl->dev;

884
	if (!mei_cl_is_connected(cl))
885 886
		return -ENODEV;

887
	if (cl->read_cb) {
888
		cl_dbg(dev, cl, "read is pending.\n");
889 890
		return -EBUSY;
	}
891
	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
892
	if (!me_cl) {
893
		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
894
		return  -ENOTTY;
895
	}
896 897 898
	/* 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);
899

900
	rets = pm_runtime_get(dev->dev);
901
	if (rets < 0 && rets != -EINPROGRESS) {
902
		pm_runtime_put_noidle(dev->dev);
903 904 905 906
		cl_err(dev, cl, "rpm: get failed %d\n", rets);
		return rets;
	}

907
	cb = mei_io_cb_init(cl, NULL);
908 909 910 911
	if (!cb) {
		rets = -ENOMEM;
		goto out;
	}
912

T
Tomas Winkler 已提交
913
	rets = mei_io_cb_alloc_resp_buf(cb, length);
914
	if (rets)
915
		goto out;
916

917
	cb->fop_type = MEI_FOP_READ;
918
	if (mei_hbuf_acquire(dev)) {
919 920
		rets = mei_hbm_cl_flow_control_req(dev, cl);
		if (rets < 0)
921 922
			goto out;

923
		list_add_tail(&cb->list, &dev->read_list.list);
924
	} else {
925
		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
926
	}
927 928 929

	cl->read_cb = cb;

930 931
out:
	cl_dbg(dev, cl, "rpm: autosuspend\n");
932 933
	pm_runtime_mark_last_busy(dev->dev);
	pm_runtime_put_autosuspend(dev->dev);
934 935 936 937

	if (rets)
		mei_io_cb_free(cb);

938 939 940
	return rets;
}

941
/**
942
 * mei_cl_irq_write - write a message to device
943 944 945 946 947 948
 *	from the interrupt thread context
 *
 * @cl: client
 * @cb: callback block.
 * @cmpl_list: complete list.
 *
949
 * Return: 0, OK; otherwise error.
950
 */
951 952
int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
		     struct mei_cl_cb *cmpl_list)
953
{
954 955
	struct mei_device *dev;
	struct mei_msg_data *buf;
956
	struct mei_msg_hdr mei_hdr;
957 958
	size_t len;
	u32 msg_slots;
959
	int slots;
960
	int rets;
961

962 963 964 965 966 967 968 969 970 971 972 973
	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) {
974
		cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
975 976 977
		return 0;
	}

978
	slots = mei_hbuf_empty_slots(dev);
979 980 981
	len = buf->size - cb->buf_idx;
	msg_slots = mei_data2slots(len);

982 983 984
	mei_hdr.host_addr = cl->host_client_id;
	mei_hdr.me_addr = cl->me_client_id;
	mei_hdr.reserved = 0;
985
	mei_hdr.internal = cb->internal;
986

987
	if (slots >= msg_slots) {
988 989 990
		mei_hdr.length = len;
		mei_hdr.msg_complete = 1;
	/* Split the message only if we can write the whole host buffer */
991 992 993
	} else if (slots == dev->hbuf_depth) {
		msg_slots = slots;
		len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
994 995 996 997 998 999 1000
		mei_hdr.length = len;
		mei_hdr.msg_complete = 0;
	} else {
		/* wait for next time the host buffer is empty */
		return 0;
	}

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

1004
	rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
1005 1006
	if (rets) {
		cl->status = rets;
1007
		list_move_tail(&cb->list, &cmpl_list->list);
1008
		return rets;
1009 1010 1011
	}

	cl->status = 0;
1012
	cl->writing_state = MEI_WRITING;
1013
	cb->buf_idx += mei_hdr.length;
1014

1015 1016
	if (mei_hdr.msg_complete) {
		if (mei_cl_flow_ctrl_reduce(cl))
1017
			return -EIO;
1018 1019 1020 1021 1022 1023
		list_move_tail(&cb->list, &dev->write_waiting_list.list);
	}

	return 0;
}

T
Tomas Winkler 已提交
1024 1025
/**
 * mei_cl_write - submit a write cb to mei device
1026
 *	assumes device_lock is locked
T
Tomas Winkler 已提交
1027 1028
 *
 * @cl: host client
1029
 * @cb: write callback with filled data
A
Alexander Usyskin 已提交
1030
 * @blocking: block until completed
T
Tomas Winkler 已提交
1031
 *
1032
 * Return: number of bytes sent on success, <0 on failure.
T
Tomas Winkler 已提交
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
 */
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;

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

1055
	rets = pm_runtime_get(dev->dev);
1056
	if (rets < 0 && rets != -EINPROGRESS) {
1057
		pm_runtime_put_noidle(dev->dev);
1058 1059 1060
		cl_err(dev, cl, "rpm: get failed %d\n", rets);
		return rets;
	}
T
Tomas Winkler 已提交
1061 1062

	cb->fop_type = MEI_FOP_WRITE;
1063 1064 1065 1066 1067 1068 1069 1070
	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 已提交
1071 1072 1073 1074 1075

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

1076 1077 1078 1079 1080 1081 1082
	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 已提交
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
		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;
	}

1096 1097
	rets = mei_write_message(dev, &mei_hdr, buf->data);
	if (rets)
T
Tomas Winkler 已提交
1098 1099 1100 1101 1102 1103 1104
		goto err;

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

out:
	if (mei_hdr.msg_complete) {
1105 1106
		rets = mei_cl_flow_ctrl_reduce(cl);
		if (rets < 0)
T
Tomas Winkler 已提交
1107
			goto err;
1108

T
Tomas Winkler 已提交
1109 1110 1111 1112 1113 1114 1115 1116 1117
		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);
1118 1119
		rets = wait_event_interruptible(cl->tx_wait,
				cl->writing_state == MEI_WRITE_COMPLETE);
T
Tomas Winkler 已提交
1120
		mutex_lock(&dev->device_lock);
1121 1122 1123 1124 1125 1126
		/* wait_event_interruptible returns -ERESTARTSYS */
		if (rets) {
			if (signal_pending(current))
				rets = -EINTR;
			goto err;
		}
T
Tomas Winkler 已提交
1127
	}
1128 1129

	rets = buf->size;
T
Tomas Winkler 已提交
1130
err:
1131
	cl_dbg(dev, cl, "rpm: autosuspend\n");
1132 1133
	pm_runtime_mark_last_busy(dev->dev);
	pm_runtime_put_autosuspend(dev->dev);
1134

T
Tomas Winkler 已提交
1135 1136 1137 1138
	return rets;
}


1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
/**
 * 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 已提交
1165

1166 1167 1168
/**
 * mei_cl_all_disconnect - disconnect forcefully all connected clients
 *
1169
 * @dev: mei device
1170 1171 1172 1173
 */

void mei_cl_all_disconnect(struct mei_device *dev)
{
1174
	struct mei_cl *cl;
1175

1176
	list_for_each_entry(cl, &dev->file_list, link) {
1177 1178 1179 1180 1181 1182 1183 1184
		cl->state = MEI_FILE_DISCONNECTED;
		cl->mei_flow_ctrl_creds = 0;
		cl->timer_count = 0;
	}
}


/**
T
Tomas Winkler 已提交
1185
 * mei_cl_all_wakeup  - wake up all readers and writers they can be interrupted
1186
 *
1187
 * @dev: mei device
1188
 */
T
Tomas Winkler 已提交
1189
void mei_cl_all_wakeup(struct mei_device *dev)
1190
{
1191
	struct mei_cl *cl;
1192

1193
	list_for_each_entry(cl, &dev->file_list, link) {
1194
		if (waitqueue_active(&cl->rx_wait)) {
1195
			cl_dbg(dev, cl, "Waking up reading client!\n");
1196 1197
			wake_up_interruptible(&cl->rx_wait);
		}
T
Tomas Winkler 已提交
1198
		if (waitqueue_active(&cl->tx_wait)) {
1199
			cl_dbg(dev, cl, "Waking up writing client!\n");
T
Tomas Winkler 已提交
1200 1201
			wake_up_interruptible(&cl->tx_wait);
		}
1202 1203 1204 1205 1206
	}
}

/**
 * mei_cl_all_write_clear - clear all pending writes
1207 1208
 *
 * @dev: mei device
1209 1210 1211
 */
void mei_cl_all_write_clear(struct mei_device *dev)
{
1212 1213
	mei_io_list_free(&dev->write_list, NULL);
	mei_io_list_free(&dev->write_waiting_list, NULL);
1214 1215 1216
}