amthif.c 18.6 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 31 32
/*
 *
 * 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/pci.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>

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 55 56 57

/**
 * 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_msg_buf_size = 0;
	dev->iamthif_msg_buf_index = 0;
	dev->iamthif_canceled = false;
	dev->iamthif_ioctl = false;
	dev->iamthif_state = MEI_IAMTHIF_IDLE;
	dev->iamthif_timer = 0;
58
	dev->iamthif_stall_timer = 0;
T
Tomas Winkler 已提交
59
	dev->iamthif_open_count = 0;
60 61 62
}

/**
63
 * mei_amthif_host_init - mei initialization amthif client.
64 65 66 67
 *
 * @dev: the device structure
 *
 */
68
int mei_amthif_host_init(struct mei_device *dev)
69
{
70
	struct mei_cl *cl = &dev->iamthif_cl;
71
	unsigned char *msg_buf;
72
	int ret, i;
73

74 75
	dev->iamthif_state = MEI_IAMTHIF_IDLE;

76
	mei_cl_init(cl, dev);
77

78
	i = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
79
	if (i < 0) {
80
		dev_info(&dev->pdev->dev,
81 82
			"amthif: failed to find the client %d\n", i);
		return -ENOTTY;
83 84
	}

85 86
	cl->me_client_id = dev->me_clients[i].client_id;

87 88 89 90 91 92 93 94 95 96 97 98 99
	/* Assign iamthif_mtu to the value received from ME  */

	dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length;
	dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n",
			dev->me_clients[i].props.max_msg_length);

	kfree(dev->iamthif_msg_buf);
	dev->iamthif_msg_buf = NULL;

	/* allocate storage for ME message buffer */
	msg_buf = kcalloc(dev->iamthif_mtu,
			sizeof(unsigned char), GFP_KERNEL);
	if (!msg_buf) {
100 101
		dev_err(&dev->pdev->dev, "amthif: memory allocation for ME message buffer failed.\n");
		return -ENOMEM;
102 103 104 105
	}

	dev->iamthif_msg_buf = msg_buf;

106 107 108
	ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);

	if (ret < 0) {
109 110 111
		dev_err(&dev->pdev->dev,
			"amthif: failed link client %d\n", ret);
		return ret;
112 113
	}

114 115 116 117 118
	ret = mei_cl_connect(cl, NULL);

	dev->iamthif_state = MEI_IAMTHIF_IDLE;

	return ret;
119 120 121 122 123 124 125 126 127 128 129 130 131
}

/**
 * mei_amthif_find_read_list_entry - finds a amthilist entry for current file
 *
 * @dev: the device structure
 * @file: pointer to file object
 *
 * returns   returned a list entry on success, NULL on failure.
 */
struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
						struct file *file)
{
132 133 134 135 136 137
	struct mei_cl_cb *cb;

	list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list) {
		if (cb->cl && cb->cl == &dev->iamthif_cl &&
			cb->file_object == file)
			return cb;
138 139 140 141 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 167 168 169
	}
	return NULL;
}


/**
 * mei_amthif_read - read data from AMTHIF client
 *
 * @dev: the device structure
 * @if_num:  minor number
 * @file: pointer to file object
 * @*ubuf: pointer to user data in user space
 * @length: data length to read
 * @offset: data read offset
 *
 * Locking: called under "dev->device_lock" lock
 *
 * returns
 *  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)
{
	int rets;
	int wait_ret;
	struct mei_cl_cb *cb = NULL;
	struct mei_cl *cl = file->private_data;
	unsigned long timeout;
	int i;

170
	/* Only possible if we are in timeout */
171 172
	if (!cl || cl != &dev->iamthif_cl) {
		dev_dbg(&dev->pdev->dev, "bad file ext.\n");
173
		return -ETIME;
174 175 176 177
	}

	i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
	if (i < 0) {
178
		dev_dbg(&dev->pdev->dev, "amthif client not found.\n");
179
		return -ENOTTY;
180
	}
181
	dev_dbg(&dev->pdev->dev, "checking amthif data\n");
182 183 184 185 186 187 188
	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;


189
	dev_dbg(&dev->pdev->dev, "waiting for amthif data\n");
190 191 192 193 194 195 196
	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)));

197 198 199
		/* Locking again the Mutex */
		mutex_lock(&dev->device_lock);

200 201 202 203 204 205 206
		if (wait_ret)
			return -ERESTARTSYS;

		dev_dbg(&dev->pdev->dev, "woke up from sleep\n");
	}


207
	dev_dbg(&dev->pdev->dev, "Got amthif data\n");
208 209 210 211 212
	dev->iamthif_timer = 0;

	if (cb) {
		timeout = cb->read_time +
			mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
213
		dev_dbg(&dev->pdev->dev, "amthif timeout = %lud\n",
214 215 216
				timeout);

		if  (time_after(jiffies, timeout)) {
217
			dev_dbg(&dev->pdev->dev, "amthif Time out\n");
218 219
			/* 15 sec for the message has expired */
			list_del(&cb->list);
220
			rets = -ETIME;
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
			goto free;
		}
	}
	/* 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
		 */

237
	dev_dbg(&dev->pdev->dev, "amthif cb->response_buffer size - %d\n",
238
	    cb->response_buffer.size);
239
	dev_dbg(&dev->pdev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
240

241
	/* length is being truncated to PAGE_SIZE, however,
242 243 244
	 * the buf_idx may point beyond */
	length = min_t(size_t, length, (cb->buf_idx - *offset));

245 246
	if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
		dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
247
		rets = -EFAULT;
248
	} else {
249 250 251 252 253 254 255
		rets = length;
		if ((*offset + length) < cb->buf_idx) {
			*offset += length;
			goto out;
		}
	}
free:
256
	dev_dbg(&dev->pdev->dev, "free amthif cb memory.\n");
257 258 259 260 261 262 263
	*offset = 0;
	mei_io_cb_free(cb);
out:
	return rets;
}

/**
264
 * mei_amthif_send_cmd - send amthif command to the ME
265 266 267 268 269
 *
 * @dev: the device structure
 * @cb: mei call back struct
 *
 * returns 0 on success, <0 on failure.
270
 *
271
 */
272
static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
273 274 275 276 277 278 279
{
	struct mei_msg_hdr mei_hdr;
	int ret;

	if (!dev || !cb)
		return -ENODEV;

280
	dev_dbg(&dev->pdev->dev, "write data to amthif client.\n");
281 282 283 284 285 286 287 288 289 290

	dev->iamthif_state = MEI_IAMTHIF_WRITING;
	dev->iamthif_current_cb = cb;
	dev->iamthif_file_object = cb->file_object;
	dev->iamthif_canceled = false;
	dev->iamthif_ioctl = true;
	dev->iamthif_msg_buf_size = cb->request_buffer.size;
	memcpy(dev->iamthif_msg_buf, cb->request_buffer.data,
	       cb->request_buffer.size);

T
Tomas Winkler 已提交
291
	ret = mei_cl_flow_ctrl_creds(&dev->iamthif_cl);
292 293 294
	if (ret < 0)
		return ret;

295
	if (ret && mei_hbuf_acquire(dev)) {
296
		ret = 0;
297 298
		if (cb->request_buffer.size > mei_hbuf_max_len(dev)) {
			mei_hdr.length = mei_hbuf_max_len(dev);
299 300 301 302 303 304 305 306 307
			mei_hdr.msg_complete = 0;
		} else {
			mei_hdr.length = cb->request_buffer.size;
			mei_hdr.msg_complete = 1;
		}

		mei_hdr.host_addr = dev->iamthif_cl.host_client_id;
		mei_hdr.me_addr = dev->iamthif_cl.me_client_id;
		mei_hdr.reserved = 0;
308
		mei_hdr.internal = 0;
309
		dev->iamthif_msg_buf_index += mei_hdr.length;
310 311 312
		ret = mei_write_message(dev, &mei_hdr, dev->iamthif_msg_buf);
		if (ret)
			return ret;
313 314

		if (mei_hdr.msg_complete) {
T
Tomas Winkler 已提交
315
			if (mei_cl_flow_ctrl_reduce(&dev->iamthif_cl))
316
				return -EIO;
317 318
			dev->iamthif_flow_control_pending = true;
			dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
319
			dev_dbg(&dev->pdev->dev, "add amthif cb to write waiting list\n");
320 321 322 323
			dev->iamthif_current_cb = cb;
			dev->iamthif_file_object = cb->file_object;
			list_add_tail(&cb->list, &dev->write_waiting_list.list);
		} else {
324
			dev_dbg(&dev->pdev->dev, "message does not complete, so add amthif cb to write list.\n");
325 326 327 328 329 330 331 332
			list_add_tail(&cb->list, &dev->write_list.list);
		}
	} else {
		list_add_tail(&cb->list, &dev->write_list.list);
	}
	return 0;
}

333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
/**
 * mei_amthif_write - write amthif data to amthif client
 *
 * @dev: the device structure
 * @cb: mei call back struct
 *
 * returns 0 on success, <0 on failure.
 *
 */
int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb)
{
	int ret;

	if (!dev || !cb)
		return -ENODEV;

	ret = mei_io_cb_alloc_resp_buf(cb, dev->iamthif_mtu);
	if (ret)
		return ret;

353
	cb->fop_type = MEI_FOP_WRITE;
354

355
	if (!list_empty(&dev->amthif_cmd_list.list) ||
356 357 358 359
	    dev->iamthif_state != MEI_IAMTHIF_IDLE) {
		dev_dbg(&dev->pdev->dev,
			"amthif state = %d\n", dev->iamthif_state);
		dev_dbg(&dev->pdev->dev, "AMTHIF: add cb to the wait list\n");
360
		list_add_tail(&cb->list, &dev->amthif_cmd_list.list);
361 362 363 364
		return 0;
	}
	return mei_amthif_send_cmd(dev, cb);
}
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
/**
 * mei_amthif_run_next_cmd
 *
 * @dev: the device structure
 *
 * returns 0 on success, <0 on failure.
 */
void mei_amthif_run_next_cmd(struct mei_device *dev)
{
	struct mei_cl_cb *pos = NULL;
	struct mei_cl_cb *next = NULL;
	int status;

	if (!dev)
		return;

	dev->iamthif_msg_buf_size = 0;
	dev->iamthif_msg_buf_index = 0;
	dev->iamthif_canceled = false;
	dev->iamthif_ioctl = true;
	dev->iamthif_state = MEI_IAMTHIF_IDLE;
	dev->iamthif_timer = 0;
	dev->iamthif_file_object = NULL;

389
	dev_dbg(&dev->pdev->dev, "complete amthif cmd_list cb.\n");
390

391
	list_for_each_entry_safe(pos, next, &dev->amthif_cmd_list.list, list) {
392 393
		list_del(&pos->list);

394
		if (pos->cl && pos->cl == &dev->iamthif_cl) {
395
			status = mei_amthif_send_cmd(dev, pos);
396 397
			if (status) {
				dev_dbg(&dev->pdev->dev,
398
					"amthif write failed status = %d\n",
399 400 401 402 403 404 405 406
						status);
				return;
			}
			break;
		}
	}
}

407 408 409 410 411

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

413
	poll_wait(file, &dev->iamthif_cl.wait, wait);
414

415
	mutex_lock(&dev->device_lock);
416 417 418 419 420 421 422
	if (!mei_cl_is_connected(&dev->iamthif_cl)) {

		mask = POLLERR;

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

423
		mask |= (POLLIN | POLLRDNORM);
424
		dev_dbg(&dev->pdev->dev, "run next amthif cb\n");
425 426
		mei_amthif_run_next_cmd(dev);
	}
427 428
	mutex_unlock(&dev->device_lock);

429 430 431 432 433
	return mask;
}



434
/**
435
 * mei_amthif_irq_write - write iamthif command in irq thread context.
436 437 438 439 440 441 442 443
 *
 * @dev: the device structure.
 * @cb_pos: callback block.
 * @cl: private data of the file object.
 * @cmpl_list: complete list.
 *
 * returns 0, OK; otherwise, error.
 */
444 445
int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
			 struct mei_cl_cb *cmpl_list)
446
{
447
	struct mei_device *dev = cl->dev;
448
	struct mei_msg_hdr mei_hdr;
449
	size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index;
T
Tomas Winkler 已提交
450
	u32 msg_slots = mei_data2slots(len);
451
	int slots;
452
	int rets;
453

454 455 456 457 458 459 460 461 462
	rets = mei_cl_flow_ctrl_creds(cl);
	if (rets < 0)
		return rets;

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

463 464 465
	mei_hdr.host_addr = cl->host_client_id;
	mei_hdr.me_addr = cl->me_client_id;
	mei_hdr.reserved = 0;
466
	mei_hdr.internal = 0;
467

468 469 470
	slots = mei_hbuf_empty_slots(dev);

	if (slots >= msg_slots) {
471 472
		mei_hdr.length = len;
		mei_hdr.msg_complete = 1;
473
	/* Split the message only if we can write the whole host buffer */
474 475 476
	} else if (slots == dev->hbuf_depth) {
		msg_slots = slots;
		len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
477 478
		mei_hdr.length = len;
		mei_hdr.msg_complete = 0;
479 480 481 482
	} else {
		/* wait for next time the host buffer is empty */
		return 0;
	}
483

484
	dev_dbg(&dev->pdev->dev, MEI_HDR_FMT,  MEI_HDR_PRM(&mei_hdr));
485

486 487 488 489 490 491 492
	rets = mei_write_message(dev, &mei_hdr,
			dev->iamthif_msg_buf + dev->iamthif_msg_buf_index);
	if (rets) {
		dev->iamthif_state = MEI_IAMTHIF_IDLE;
		cl->status = rets;
		list_del(&cb->list);
		return rets;
493
	}
494

T
Tomas Winkler 已提交
495
	if (mei_cl_flow_ctrl_reduce(cl))
496
		return -EIO;
497

498
	dev->iamthif_msg_buf_index += mei_hdr.length;
499
	cl->status = 0;
500

501
	if (mei_hdr.msg_complete) {
502 503 504
		dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
		dev->iamthif_flow_control_pending = true;

505
		/* save iamthif cb sent to amthif client */
506 507 508 509
		cb->buf_idx = dev->iamthif_msg_buf_index;
		dev->iamthif_current_cb = cb;

		list_move_tail(&cb->list, &dev->write_waiting_list.list);
510 511
	}

512

513 514 515 516 517
	return 0;
}

/**
 * mei_amthif_irq_read_message - read routine after ISR to
518
 *			handle the read amthif message
519 520
 *
 * @dev: the device structure
521
 * @mei_hdr: header of amthif message
522
 * @complete_list: An instance of our list structure
523 524 525
 *
 * returns 0 on success, <0 on failure.
 */
526 527 528
int mei_amthif_irq_read_msg(struct mei_device *dev,
			    struct mei_msg_hdr *mei_hdr,
			    struct mei_cl_cb *complete_list)
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
{
	struct mei_cl_cb *cb;
	unsigned char *buffer;

	BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id);
	BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING);

	buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index;
	BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length);

	mei_read_slots(dev, buffer, mei_hdr->length);

	dev->iamthif_msg_buf_index += mei_hdr->length;

	if (!mei_hdr->msg_complete)
		return 0;

546
	dev_dbg(&dev->pdev->dev, "amthif_message_buffer_index =%d\n",
547 548
			mei_hdr->length);

549
	dev_dbg(&dev->pdev->dev, "completed amthif read.\n ");
550 551 552 553 554 555
	if (!dev->iamthif_current_cb)
		return -ENODEV;

	cb = dev->iamthif_current_cb;
	dev->iamthif_current_cb = NULL;

556
	if (!cb->cl)
557 558 559 560 561
		return -ENODEV;

	dev->iamthif_stall_timer = 0;
	cb->buf_idx = dev->iamthif_msg_buf_index;
	cb->read_time = jiffies;
562
	if (dev->iamthif_ioctl && cb->cl == &dev->iamthif_cl) {
563
		/* found the iamthif cb */
564 565
		dev_dbg(&dev->pdev->dev, "complete the amthif read cb.\n ");
		dev_dbg(&dev->pdev->dev, "add the amthif read cb to complete.\n ");
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
		list_add_tail(&cb->list, &complete_list->list);
	}
	return 0;
}

/**
 * mei_amthif_irq_read - prepares to read amthif data.
 *
 * @dev: the device structure.
 * @slots: free slots.
 *
 * returns 0, OK; otherwise, error.
 */
int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
{
T
Tomas Winkler 已提交
581
	u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
582

T
Tomas Winkler 已提交
583
	if (*slots < msg_slots)
584
		return -EMSGSIZE;
T
Tomas Winkler 已提交
585 586 587

	*slots -= msg_slots;

588
	if (mei_hbm_cl_flow_control_req(dev, &dev->iamthif_cl)) {
589 590 591 592 593 594 595 596 597 598
		dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
		return -EIO;
	}

	dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
	dev->iamthif_state = MEI_IAMTHIF_READING;
	dev->iamthif_flow_control_pending = false;
	dev->iamthif_msg_buf_index = 0;
	dev->iamthif_msg_buf_size = 0;
	dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
599
	dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
	return 0;
}

/**
 * mei_amthif_complete - complete amthif callback.
 *
 * @dev: the device structure.
 * @cb_pos: callback block.
 */
void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb)
{
	if (dev->iamthif_canceled != 1) {
		dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
		dev->iamthif_stall_timer = 0;
		memcpy(cb->response_buffer.data,
				dev->iamthif_msg_buf,
				dev->iamthif_msg_buf_index);
617
		list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list);
618
		dev_dbg(&dev->pdev->dev, "amthif read completed\n");
619 620 621 622 623 624 625
		dev->iamthif_timer = jiffies;
		dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
				dev->iamthif_timer);
	} else {
		mei_amthif_run_next_cmd(dev);
	}

626
	dev_dbg(&dev->pdev->dev, "completing amthif call back.\n");
627 628 629
	wake_up_interruptible(&dev->iamthif_cl.wait);
}

630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
/**
 * 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
 *
 * returns true if callback removed from the list, false otherwise
 */
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 */
660 661
				mei_hbm_cl_flow_control_req(dev,
							&dev->iamthif_cl);
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
			}
			/* 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
 *
 * returns true if callback removed from the list, false otherwise
 */
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;
691

692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
	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
*
719
*  @dev: device structure
720 721 722 723 724 725
*  @file: pointer to file structure
*
*  returns 0 on success, <0 on error
*/
int mei_amthif_release(struct mei_device *dev, struct file *file)
{
T
Tomas Winkler 已提交
726 727
	if (dev->iamthif_open_count > 0)
		dev->iamthif_open_count--;
728 729 730 731

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

732
		dev_dbg(&dev->pdev->dev, "amthif canceled iamthif state %d\n",
733 734 735
		    dev->iamthif_state);
		dev->iamthif_canceled = true;
		if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
736
			dev_dbg(&dev->pdev->dev, "run next amthif iamthif cb\n");
737 738 739 740 741 742 743 744 745
			mei_amthif_run_next_cmd(dev);
		}
	}

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

	return 0;
}