amthif.c 14.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*
 *
 * Intel Management Engine Interface (Intel MEI) Linux driver
 * Copyright (c) 2003-2012, Intel Corporation.
 *
 * 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/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/aio.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/list.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/uuid.h>
#include <linux/jiffies.h>
#include <linux/uaccess.h>
31
#include <linux/slab.h>
32

33
#include <linux/mei.h>
34 35

#include "mei_dev.h"
36
#include "hbm.h"
T
Tomas Winkler 已提交
37
#include "client.h"
38

39 40 41
const uuid_le mei_amthif_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
					 0xac, 0xa8, 0x46, 0xe0,
					 0xff, 0x65, 0x81, 0x4c);
42 43 44 45 46 47 48 49 50 51 52 53 54

/**
 * mei_amthif_reset_params - initializes mei device iamthif
 *
 * @dev: the device structure
 */
void mei_amthif_reset_params(struct mei_device *dev)
{
	/* reset iamthif parameters. */
	dev->iamthif_current_cb = NULL;
	dev->iamthif_canceled = false;
	dev->iamthif_state = MEI_IAMTHIF_IDLE;
	dev->iamthif_timer = 0;
55
	dev->iamthif_stall_timer = 0;
T
Tomas Winkler 已提交
56
	dev->iamthif_open_count = 0;
57 58 59
}

/**
60
 * mei_amthif_host_init - mei initialization amthif client.
61 62 63
 *
 * @dev: the device structure
 *
A
Alexander Usyskin 已提交
64
 * Return: 0 on success, <0 on failure.
65
 */
66
int mei_amthif_host_init(struct mei_device *dev)
67
{
68
	struct mei_cl *cl = &dev->iamthif_cl;
69 70
	struct mei_me_client *me_cl;
	int ret;
71

72 73
	dev->iamthif_state = MEI_IAMTHIF_IDLE;

74
	mei_cl_init(cl, dev);
75

76 77
	me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
	if (!me_cl) {
78
		dev_info(dev->dev, "amthif: failed to find the client");
79
		return -ENOTTY;
80 81
	}

82
	cl->me_client_id = me_cl->client_id;
83
	cl->cl_uuid = me_cl->props.protocol_name;
84

85 86
	/* Assign iamthif_mtu to the value received from ME  */

87
	dev->iamthif_mtu = me_cl->props.max_msg_length;
88
	dev_dbg(dev->dev, "IAMTHIF_MTU = %d\n", dev->iamthif_mtu);
89 90


91 92
	ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
	if (ret < 0) {
93 94
		dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
		goto out;
95 96
	}

97 98 99 100
	ret = mei_cl_connect(cl, NULL);

	dev->iamthif_state = MEI_IAMTHIF_IDLE;

101 102
out:
	mei_me_cl_put(me_cl);
103
	return ret;
104 105 106 107 108 109 110 111
}

/**
 * mei_amthif_find_read_list_entry - finds a amthilist entry for current file
 *
 * @dev: the device structure
 * @file: pointer to file object
 *
112
 * Return:   returned a list entry on success, NULL on failure.
113 114 115 116
 */
struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
						struct file *file)
{
117
	struct mei_cl_cb *cb;
118

119 120
	list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list)
		if (cb->file_object == file)
121
			return cb;
122 123 124 125 126 127 128 129 130
	return NULL;
}


/**
 * mei_amthif_read - read data from AMTHIF client
 *
 * @dev: the device structure
 * @file: pointer to file object
131
 * @ubuf: pointer to user data in user space
132 133 134 135 136
 * @length: data length to read
 * @offset: data read offset
 *
 * Locking: called under "dev->device_lock" lock
 *
137
 * Return:
138 139 140 141 142 143 144 145
 *  returned data length on success,
 *  zero if no data to read,
 *  negative on failure.
 */
int mei_amthif_read(struct mei_device *dev, struct file *file,
	       char __user *ubuf, size_t length, loff_t *offset)
{
	struct mei_cl *cl = file->private_data;
146
	struct mei_cl_cb *cb;
147
	unsigned long timeout;
148 149
	int rets;
	int wait_ret;
150

151
	/* Only possible if we are in timeout */
152
	if (!cl) {
153
		dev_err(dev->dev, "bad file ext.\n");
154
		return -ETIME;
155 156
	}

157
	dev_dbg(dev->dev, "checking amthif data\n");
158 159 160 161 162 163 164
	cb = mei_amthif_find_read_list_entry(dev, file);

	/* Check for if we can block or not*/
	if (cb == NULL && file->f_flags & O_NONBLOCK)
		return -EAGAIN;


165
	dev_dbg(dev->dev, "waiting for amthif data\n");
166 167 168 169 170 171 172
	while (cb == NULL) {
		/* unlock the Mutex */
		mutex_unlock(&dev->device_lock);

		wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
			(cb = mei_amthif_find_read_list_entry(dev, file)));

173 174 175
		/* Locking again the Mutex */
		mutex_lock(&dev->device_lock);

176 177 178
		if (wait_ret)
			return -ERESTARTSYS;

179
		dev_dbg(dev->dev, "woke up from sleep\n");
180 181
	}

182 183 184 185 186
	if (cb->status) {
		rets = cb->status;
		dev_dbg(dev->dev, "read operation failed %d\n", rets);
		goto free;
	}
187

188
	dev_dbg(dev->dev, "Got amthif data\n");
189 190
	dev->iamthif_timer = 0;

191 192 193 194 195 196 197 198 199 200 201
	timeout = cb->read_time +
		mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
	dev_dbg(dev->dev, "amthif timeout = %lud\n",
			timeout);

	if  (time_after(jiffies, timeout)) {
		dev_dbg(dev->dev, "amthif Time out\n");
		/* 15 sec for the message has expired */
		list_del(&cb->list);
		rets = -ETIME;
		goto free;
202 203 204 205 206 207 208 209 210 211 212 213 214 215
	}
	/* if the whole message will fit remove it from the list */
	if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset))
		list_del(&cb->list);
	else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) {
		/* end of the message has been reached */
		list_del(&cb->list);
		rets = 0;
		goto free;
	}
		/* else means that not full buffer will be read and do not
		 * remove message from deletion list
		 */

216
	dev_dbg(dev->dev, "amthif cb->response_buffer size - %d\n",
217
	    cb->response_buffer.size);
218
	dev_dbg(dev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
219

220
	/* length is being truncated to PAGE_SIZE, however,
221 222 223
	 * the buf_idx may point beyond */
	length = min_t(size_t, length, (cb->buf_idx - *offset));

224
	if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
225
		dev_dbg(dev->dev, "failed to copy data to userland\n");
226
		rets = -EFAULT;
227
	} else {
228 229 230 231 232 233 234
		rets = length;
		if ((*offset + length) < cb->buf_idx) {
			*offset += length;
			goto out;
		}
	}
free:
235
	dev_dbg(dev->dev, "free amthif cb memory.\n");
236 237 238 239 240 241
	*offset = 0;
	mei_io_cb_free(cb);
out:
	return rets;
}

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
/**
 * mei_amthif_read_start - queue message for sending read credential
 *
 * @cl: host client
 * @file: file pointer of message recipient
 *
 * Return: 0 on success, <0 on failure.
 */
static int mei_amthif_read_start(struct mei_cl *cl, struct file *file)
{
	struct mei_device *dev = cl->dev;
	struct mei_cl_cb *cb;
	size_t length = dev->iamthif_mtu;
	int rets;

	cb = mei_io_cb_init(cl, file);
	if (!cb) {
		rets = -ENOMEM;
		goto err;
	}

	rets = mei_io_cb_alloc_resp_buf(cb, length);
	if (rets)
		goto err;

	cb->fop_type = MEI_FOP_READ;
	list_add_tail(&cb->list, &dev->ctrl_wr_list.list);

	dev->iamthif_state = MEI_IAMTHIF_READING;
	dev->iamthif_file_object = cb->file_object;
	dev->iamthif_current_cb = cb;

	return 0;
err:
	mei_io_cb_free(cb);
	return rets;
}

280
/**
281
 * mei_amthif_send_cmd - send amthif command to the ME
282
 *
283
 * @cl: the host client
284 285
 * @cb: mei call back struct
 *
286
 * Return: 0 on success, <0 on failure.
287
 */
288
static int mei_amthif_send_cmd(struct mei_cl *cl, struct mei_cl_cb *cb)
289
{
290
	struct mei_device *dev;
291 292
	int ret;

293
	if (!cl->dev || !cb)
294 295
		return -ENODEV;

296
	dev = cl->dev;
297 298 299 300 301 302

	dev->iamthif_state = MEI_IAMTHIF_WRITING;
	dev->iamthif_current_cb = cb;
	dev->iamthif_file_object = cb->file_object;
	dev->iamthif_canceled = false;

303
	ret = mei_cl_write(cl, cb, false);
304 305 306
	if (ret < 0)
		return ret;

307 308
	if (cb->completed)
		cb->status = mei_amthif_read_start(cl, cb->file_object);
309

310 311 312
	return 0;
}

313
/**
314
 * mei_amthif_run_next_cmd - send next amt command from queue
315 316 317
 *
 * @dev: the device structure
 *
318
 * Return: 0 on success, <0 on failure.
319
 */
320
int mei_amthif_run_next_cmd(struct mei_device *dev)
321
{
322
	struct mei_cl *cl = &dev->iamthif_cl;
323
	struct mei_cl_cb *cb;
324 325 326 327 328 329

	dev->iamthif_canceled = false;
	dev->iamthif_state = MEI_IAMTHIF_IDLE;
	dev->iamthif_timer = 0;
	dev->iamthif_file_object = NULL;

330
	dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
331

332 333 334
	cb = list_first_entry_or_null(&dev->amthif_cmd_list.list,
					typeof(*cb), list);
	if (!cb)
335 336
		return 0;

337
	list_del_init(&cb->list);
338
	return mei_amthif_send_cmd(cl, cb);
339 340
}

341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
/**
 * mei_amthif_write - write amthif data to amthif client
 *
 * @cl: host client
 * @cb: mei call back struct
 *
 * Return: 0 on success, <0 on failure.
 */
int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
{

	struct mei_device *dev;

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

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

	dev = cl->dev;

	cb->fop_type = MEI_FOP_WRITE;
	list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
	return mei_amthif_run_next_cmd(dev);
}
366 367 368 369 370

unsigned int mei_amthif_poll(struct mei_device *dev,
		struct file *file, poll_table *wait)
{
	unsigned int mask = 0;
371

372
	poll_wait(file, &dev->iamthif_cl.wait, wait);
373

374
	mutex_lock(&dev->device_lock);
375 376 377 378 379 380 381
	if (!mei_cl_is_connected(&dev->iamthif_cl)) {

		mask = POLLERR;

	} else if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
		   dev->iamthif_file_object == file) {

382
		mask |= (POLLIN | POLLRDNORM);
383
		dev_dbg(dev->dev, "run next amthif cb\n");
384 385
		mei_amthif_run_next_cmd(dev);
	}
386 387
	mutex_unlock(&dev->device_lock);

388 389 390 391 392
	return mask;
}



393
/**
394
 * mei_amthif_irq_write - write iamthif command in irq thread context.
395 396
 *
 * @cl: private data of the file object.
397
 * @cb: callback block.
398 399
 * @cmpl_list: complete list.
 *
400
 * Return: 0, OK; otherwise, error.
401
 */
402 403
int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
			 struct mei_cl_cb *cmpl_list)
404
{
405
	int ret;
406

407 408 409
	ret = mei_cl_irq_write(cl, cb, cmpl_list);
	if (ret)
		return ret;
410

411
	if (cb->completed)
412
		cb->status = mei_amthif_read_start(cl, cb->file_object);
413

414 415 416 417
	return 0;
}

/**
A
Alexander Usyskin 已提交
418
 * mei_amthif_irq_read_msg - read routine after ISR to
419
 *			handle the read amthif message
420
 *
421
 * @cl: mei client
422
 * @mei_hdr: header of amthif message
423
 * @cmpl_list: completed callbacks list
424
 *
425
 * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status
426
 */
427
int mei_amthif_irq_read_msg(struct mei_cl *cl,
428
			    struct mei_msg_hdr *mei_hdr,
429
			    struct mei_cl_cb *cmpl_list)
430
{
431
	struct mei_device *dev;
432
	int ret;
433

434
	dev = cl->dev;
435

436
	if (dev->iamthif_state != MEI_IAMTHIF_READING)
437
		return 0;
438

439 440 441
	ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
	if (ret)
		return ret;
442 443 444 445

	if (!mei_hdr->msg_complete)
		return 0;

446
	dev_dbg(dev->dev, "completed amthif read.\n ");
447 448
	dev->iamthif_current_cb = NULL;
	dev->iamthif_stall_timer = 0;
449

450 451 452 453 454 455 456
	return 0;
}

/**
 * mei_amthif_complete - complete amthif callback.
 *
 * @dev: the device structure.
457
 * @cb: callback block.
458 459 460
 */
void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
{
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476

	if (cb->fop_type == MEI_FOP_WRITE) {
		if (!cb->status) {
			dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
			mei_io_cb_free(cb);
			return;
		}
		/*
		 * in case of error enqueue the write cb to complete read list
		 * so it can be propagated to the reader
		 */
		list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
		wake_up_interruptible(&dev->iamthif_cl.wait);
		return;
	}

477 478 479
	if (dev->iamthif_canceled != 1) {
		dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
		dev->iamthif_stall_timer = 0;
480
		list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
481
		dev_dbg(dev->dev, "amthif read completed\n");
482
		dev->iamthif_timer = jiffies;
483
		dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n",
484
			dev->iamthif_timer);
485 486 487 488
	} else {
		mei_amthif_run_next_cmd(dev);
	}

489
	dev_dbg(dev->dev, "completing amthif call back.\n");
490 491 492
	wake_up_interruptible(&dev->iamthif_cl.wait);
}

493 494 495 496 497 498 499 500 501 502 503
/**
 * mei_clear_list - removes all callbacks associated with file
 *		from mei_cb_list
 *
 * @dev: device structure.
 * @file: file structure
 * @mei_cb_list: callbacks list
 *
 * mei_clear_list is called to clear resources associated with file
 * when application calls close function or Ctrl-C was pressed
 *
504
 * Return: true if callback removed from the list, false otherwise
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
 */
static bool mei_clear_list(struct mei_device *dev,
		const struct file *file, struct list_head *mei_cb_list)
{
	struct mei_cl_cb *cb_pos = NULL;
	struct mei_cl_cb *cb_next = NULL;
	bool removed = false;

	/* list all list member */
	list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, list) {
		/* check if list member associated with a file */
		if (file == cb_pos->file_object) {
			/* remove member from the list */
			list_del(&cb_pos->list);
			/* check if cb equal to current iamthif cb */
			if (dev->iamthif_current_cb == cb_pos) {
				dev->iamthif_current_cb = NULL;
				/* send flow control to iamthif client */
523 524
				mei_hbm_cl_flow_control_req(dev,
							&dev->iamthif_cl);
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
			}
			/* free all allocated buffers */
			mei_io_cb_free(cb_pos);
			cb_pos = NULL;
			removed = true;
		}
	}
	return removed;
}

/**
 * mei_clear_lists - removes all callbacks associated with file
 *
 * @dev: device structure
 * @file: file structure
 *
 * mei_clear_lists is called to clear resources associated with file
 * when application calls close function or Ctrl-C was pressed
 *
544
 * Return: true if callback removed from the list, false otherwise
545 546 547 548 549 550 551 552 553
 */
static bool mei_clear_lists(struct mei_device *dev, struct file *file)
{
	bool removed = false;

	/* remove callbacks associated with a file */
	mei_clear_list(dev, file, &dev->amthif_cmd_list.list);
	if (mei_clear_list(dev, file, &dev->amthif_rd_complete_list.list))
		removed = true;
554

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
	mei_clear_list(dev, file, &dev->ctrl_rd_list.list);

	if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list))
		removed = true;

	if (mei_clear_list(dev, file, &dev->write_waiting_list.list))
		removed = true;

	if (mei_clear_list(dev, file, &dev->write_list.list))
		removed = true;

	/* check if iamthif_current_cb not NULL */
	if (dev->iamthif_current_cb && !removed) {
		/* check file and iamthif current cb association */
		if (dev->iamthif_current_cb->file_object == file) {
			/* remove cb */
			mei_io_cb_free(dev->iamthif_current_cb);
			dev->iamthif_current_cb = NULL;
			removed = true;
		}
	}
	return removed;
}

/**
* mei_amthif_release - the release function
*
582
*  @dev: device structure
583 584
*  @file: pointer to file structure
*
585
*  Return: 0 on success, <0 on error
586 587 588
*/
int mei_amthif_release(struct mei_device *dev, struct file *file)
{
T
Tomas Winkler 已提交
589 590
	if (dev->iamthif_open_count > 0)
		dev->iamthif_open_count--;
591 592 593 594

	if (dev->iamthif_file_object == file &&
	    dev->iamthif_state != MEI_IAMTHIF_IDLE) {

595
		dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
596 597 598
		    dev->iamthif_state);
		dev->iamthif_canceled = true;
		if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
599
			dev_dbg(dev->dev, "run next amthif iamthif cb\n");
600 601 602 603 604 605 606 607 608
			mei_amthif_run_next_cmd(dev);
		}
	}

	if (mei_clear_lists(dev, file))
		dev->iamthif_state = MEI_IAMTHIF_IDLE;

	return 0;
}