interrupt.c 15.7 KB
Newer Older
O
Oren Weil 已提交
1 2 3
/*
 *
 * Intel Management Engine Interface (Intel MEI) Linux driver
4
 * Copyright (c) 2003-2012, Intel Corporation.
O
Oren Weil 已提交
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.
 *
 */


18
#include <linux/export.h>
O
Oren Weil 已提交
19 20 21 22 23 24
#include <linux/pci.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/jiffies.h>

25
#include <linux/mei.h>
26 27

#include "mei_dev.h"
28
#include "hbm.h"
T
Tomas Winkler 已提交
29
#include "hw-me.h"
T
Tomas Winkler 已提交
30
#include "client.h"
O
Oren Weil 已提交
31 32


33
/**
34
 * mei_irq_compl_handler - dispatch complete handlers
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
 *	for the completed callbacks
 *
 * @dev - mei device
 * @compl_list - list of completed cbs
 */
void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list)
{
	struct mei_cl_cb *cb, *next;
	struct mei_cl *cl;

	list_for_each_entry_safe(cb, next, &compl_list->list, list) {
		cl = cb->cl;
		list_del(&cb->list);
		if (!cl)
			continue;

		dev_dbg(&dev->pdev->dev, "completing call back.\n");
		if (cl == &dev->iamthif_cl)
			mei_amthif_complete(dev, cb);
		else
55
			mei_cl_complete(cl, cb);
56 57
	}
}
58
EXPORT_SYMBOL_GPL(mei_irq_compl_handler);
59

O
Oren Weil 已提交
60
/**
61
 * mei_cl_hbm_equal - check if hbm is addressed to the client
O
Oren Weil 已提交
62
 *
63
 * @cl: host client
O
Oren Weil 已提交
64 65
 * @mei_hdr: header of mei client message
 *
66
 * returns true if matches, false otherwise
O
Oren Weil 已提交
67
 */
68 69
static inline int mei_cl_hbm_equal(struct mei_cl *cl,
			struct mei_msg_hdr *mei_hdr)
O
Oren Weil 已提交
70
{
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
	return cl->host_client_id == mei_hdr->host_addr &&
		cl->me_client_id == mei_hdr->me_addr;
}
/**
 * mei_cl_is_reading - checks if the client
		is the one to read this message
 *
 * @cl: mei client
 * @mei_hdr: header of mei message
 *
 * returns true on match and false otherwise
 */
static bool mei_cl_is_reading(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr)
{
	return mei_cl_hbm_equal(cl, mei_hdr) &&
O
Oren Weil 已提交
86
		cl->state == MEI_FILE_CONNECTED &&
87
		cl->reading_state != MEI_READ_COMPLETE;
O
Oren Weil 已提交
88 89 90
}

/**
91
 * mei_irq_read_client_message - process client message
O
Oren Weil 已提交
92 93 94
 *
 * @dev: the device structure
 * @mei_hdr: header of mei client message
95
 * @complete_list: An instance of our list structure
O
Oren Weil 已提交
96 97 98
 *
 * returns 0 on success, <0 on failure.
 */
99 100 101
static int mei_cl_irq_read_msg(struct mei_device *dev,
			       struct mei_msg_hdr *mei_hdr,
			       struct mei_cl_cb *complete_list)
O
Oren Weil 已提交
102 103
{
	struct mei_cl *cl;
104
	struct mei_cl_cb *cb, *next;
105
	unsigned char *buffer = NULL;
O
Oren Weil 已提交
106

107 108 109 110 111 112 113 114 115
	list_for_each_entry_safe(cb, next, &dev->read_list.list, list) {
		cl = cb->cl;
		if (!cl || !mei_cl_is_reading(cl, mei_hdr))
			continue;

		cl->reading_state = MEI_READING;

		if (cb->response_buffer.size == 0 ||
		    cb->response_buffer.data == NULL) {
116
			cl_err(dev, cl, "response buffer is not allocated.\n");
117 118 119 120 121
			list_del(&cb->list);
			return -ENOMEM;
		}

		if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) {
122
			cl_dbg(dev, cl, "message overflow. size %d len %d idx %ld\n",
T
Tomas Winkler 已提交
123 124
				cb->response_buffer.size,
				mei_hdr->length, cb->buf_idx);
125 126 127
			buffer = krealloc(cb->response_buffer.data,
					  mei_hdr->length + cb->buf_idx,
					  GFP_KERNEL);
T
Tomas Winkler 已提交
128

129
			if (!buffer) {
130
				cl_err(dev, cl, "allocation failed.\n");
T
Tomas Winkler 已提交
131 132 133
				list_del(&cb->list);
				return -ENOMEM;
			}
134
			cb->response_buffer.data = buffer;
T
Tomas Winkler 已提交
135 136
			cb->response_buffer.size =
				mei_hdr->length + cb->buf_idx;
O
Oren Weil 已提交
137 138
		}

139 140 141 142 143 144 145
		buffer = cb->response_buffer.data + cb->buf_idx;
		mei_read_slots(dev, buffer, mei_hdr->length);

		cb->buf_idx += mei_hdr->length;
		if (mei_hdr->msg_complete) {
			cl->status = 0;
			list_del(&cb->list);
146
			cl_dbg(dev, cl, "completed read length = %lu\n",
147 148 149 150
				cb->buf_idx);
			list_add_tail(&cb->list, &complete_list->list);
		}
		break;
O
Oren Weil 已提交
151 152 153 154
	}

	dev_dbg(&dev->pdev->dev, "message read\n");
	if (!buffer) {
155
		mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
156 157
		dev_dbg(&dev->pdev->dev, "discarding message " MEI_HDR_FMT "\n",
				MEI_HDR_PRM(mei_hdr));
O
Oren Weil 已提交
158 159 160 161 162
	}

	return 0;
}

T
Tomas Winkler 已提交
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
/**
 * mei_cl_irq_disconnect_rsp - send disconnection response message
 *
 * @cl: client
 * @cb: callback block.
 * @slots: free slots.
 * @cmpl_list: complete list.
 *
 * returns 0, OK; otherwise, error.
 */
static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
			s32 *slots, struct mei_cl_cb *cmpl_list)
{
	struct mei_device *dev = cl->dev;
	int ret;

	u32 msg_slots =
		mei_data2slots(sizeof(struct hbm_client_connect_response));

	if (*slots < msg_slots)
		return -EMSGSIZE;

	*slots -= msg_slots;

	ret = mei_hbm_cl_disconnect_rsp(dev, cl);

	cl->state = MEI_FILE_DISCONNECTED;
	cl->status = 0;
	mei_io_cb_free(cb);

	return ret;
}



O
Oren Weil 已提交
198
/**
199 200
 * mei_cl_irq_close - processes close related operation from
 *	interrupt thread context - send disconnect request
O
Oren Weil 已提交
201
 *
202 203
 * @cl: client
 * @cb: callback block.
O
Oren Weil 已提交
204 205 206 207 208
 * @slots: free slots.
 * @cmpl_list: complete list.
 *
 * returns 0, OK; otherwise, error.
 */
209 210
static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
			s32 *slots, struct mei_cl_cb *cmpl_list)
O
Oren Weil 已提交
211
{
212 213
	struct mei_device *dev = cl->dev;

T
Tomas Winkler 已提交
214 215
	u32 msg_slots =
		mei_data2slots(sizeof(struct hbm_client_connect_request));
O
Oren Weil 已提交
216

T
Tomas Winkler 已提交
217 218 219 220
	if (*slots < msg_slots)
		return -EMSGSIZE;

	*slots -= msg_slots;
221

222
	if (mei_hbm_cl_disconnect_req(dev, cl)) {
223
		cl->status = 0;
224 225
		cb->buf_idx = 0;
		list_move_tail(&cb->list, &cmpl_list->list);
T
Tomas Winkler 已提交
226
		return -EIO;
O
Oren Weil 已提交
227 228
	}

T
Tomas Winkler 已提交
229 230
	cl->state = MEI_FILE_DISCONNECTING;
	cl->status = 0;
231 232
	cb->buf_idx = 0;
	list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
T
Tomas Winkler 已提交
233 234
	cl->timer_count = MEI_CONNECT_TIMEOUT;

O
Oren Weil 已提交
235 236 237 238 239
	return 0;
}


/**
240 241
 * mei_cl_irq_close - processes client read related operation from the
 *	interrupt thread context - request for flow control credits
O
Oren Weil 已提交
242
 *
243 244
 * @cl: client
 * @cb: callback block.
O
Oren Weil 已提交
245 246 247 248 249
 * @slots: free slots.
 * @cmpl_list: complete list.
 *
 * returns 0, OK; otherwise, error.
 */
250 251
static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
			   s32 *slots, struct mei_cl_cb *cmpl_list)
O
Oren Weil 已提交
252
{
253
	struct mei_device *dev = cl->dev;
T
Tomas Winkler 已提交
254 255
	u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));

256 257 258
	int ret;


T
Tomas Winkler 已提交
259
	if (*slots < msg_slots) {
O
Oren Weil 已提交
260
		/* return the cancel routine */
261
		list_del(&cb->list);
T
Tomas Winkler 已提交
262
		return -EMSGSIZE;
O
Oren Weil 已提交
263 264
	}

T
Tomas Winkler 已提交
265
	*slots -= msg_slots;
266

267 268 269
	ret = mei_hbm_cl_flow_control_req(dev, cl);
	if (ret) {
		cl->status = ret;
270 271
		cb->buf_idx = 0;
		list_move_tail(&cb->list, &cmpl_list->list);
272
		return ret;
273
	}
274

275
	list_move_tail(&cb->list, &dev->read_list.list);
276

O
Oren Weil 已提交
277 278 279 280 281
	return 0;
}


/**
282
 * mei_cl_irq_connect - send connect request in irq_thread context
O
Oren Weil 已提交
283
 *
284 285
 * @cl: client
 * @cb: callback block.
O
Oren Weil 已提交
286 287 288 289 290
 * @slots: free slots.
 * @cmpl_list: complete list.
 *
 * returns 0, OK; otherwise, error.
 */
291
static int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
292
			   s32 *slots, struct mei_cl_cb *cmpl_list)
O
Oren Weil 已提交
293
{
294
	struct mei_device *dev = cl->dev;
295
	int ret;
296

T
Tomas Winkler 已提交
297 298 299
	u32 msg_slots =
		mei_data2slots(sizeof(struct hbm_client_connect_request));

300 301 302
	if (mei_cl_is_other_connecting(cl))
		return 0;

T
Tomas Winkler 已提交
303
	if (*slots < msg_slots) {
O
Oren Weil 已提交
304
		/* return the cancel routine */
305
		list_del(&cb->list);
T
Tomas Winkler 已提交
306
		return -EMSGSIZE;
O
Oren Weil 已提交
307 308
	}

T
Tomas Winkler 已提交
309 310
	*slots -=  msg_slots;

311
	cl->state = MEI_FILE_CONNECTING;
T
Tomas Winkler 已提交
312

313 314 315
	ret = mei_hbm_cl_connect_req(dev, cl);
	if (ret) {
		cl->status = ret;
316 317
		cb->buf_idx = 0;
		list_del(&cb->list);
318
		return ret;
319
	}
320 321 322

	list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
	cl->timer_count = MEI_CONNECT_TIMEOUT;
O
Oren Weil 已提交
323 324 325 326 327
	return 0;
}


/**
328
 * mei_irq_read_handler - bottom half read routine after ISR to
O
Oren Weil 已提交
329 330 331
 * handle the read processing.
 *
 * @dev: the device structure
332
 * @cmpl_list: An instance of our list structure
O
Oren Weil 已提交
333 334 335 336
 * @slots: slots to read.
 *
 * returns 0 on success, <0 on failure.
 */
337 338
int mei_irq_read_handler(struct mei_device *dev,
		struct mei_cl_cb *cmpl_list, s32 *slots)
O
Oren Weil 已提交
339 340
{
	struct mei_msg_hdr *mei_hdr;
T
Tomas Winkler 已提交
341 342
	struct mei_cl *cl;
	int ret;
O
Oren Weil 已提交
343 344

	if (!dev->rd_msg_hdr) {
345
		dev->rd_msg_hdr = mei_read_hdr(dev);
O
Oren Weil 已提交
346 347 348 349
		(*slots)--;
		dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
	}
	mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr;
350
	dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
O
Oren Weil 已提交
351 352

	if (mei_hdr->reserved || !dev->rd_msg_hdr) {
T
Tomas Winkler 已提交
353 354
		dev_err(&dev->pdev->dev, "corrupted message header 0x%08X\n",
				dev->rd_msg_hdr);
O
Oren Weil 已提交
355 356 357 358
		ret = -EBADMSG;
		goto end;
	}

T
Tomas Winkler 已提交
359 360
	if (mei_slots2data(*slots) < mei_hdr->length) {
		dev_err(&dev->pdev->dev, "less data available than length=%08x.\n",
O
Oren Weil 已提交
361 362 363 364 365 366
				*slots);
		/* we can't read the message */
		ret = -ERANGE;
		goto end;
	}

T
Tomas Winkler 已提交
367 368
	/*  HBM message */
	if (mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0) {
369 370 371 372 373 374
		ret = mei_hbm_dispatch(dev, mei_hdr);
		if (ret) {
			dev_dbg(&dev->pdev->dev, "mei_hbm_dispatch failed ret = %d\n",
					ret);
			goto end;
		}
T
Tomas Winkler 已提交
375 376
		goto reset_slots;
	}
377

378
	/* find recipient cl */
T
Tomas Winkler 已提交
379 380 381 382 383 384 385
	list_for_each_entry(cl, &dev->file_list, link) {
		if (mei_cl_hbm_equal(cl, mei_hdr)) {
			cl_dbg(dev, cl, "got a message\n");
			break;
		}
	}

386
	/* if no recipient cl was found we assume corrupted header */
T
Tomas Winkler 已提交
387 388 389 390 391 392 393 394 395 396
	if (&cl->link == &dev->file_list) {
		dev_err(&dev->pdev->dev, "no destination client found 0x%08X\n",
				dev->rd_msg_hdr);
		ret = -EBADMSG;
		goto end;
	}

	if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
	    MEI_FILE_CONNECTED == dev->iamthif_cl.state &&
	    dev->iamthif_state == MEI_IAMTHIF_READING) {
397

398
		ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list);
T
Tomas Winkler 已提交
399 400 401
		if (ret) {
			dev_err(&dev->pdev->dev, "mei_amthif_irq_read_msg failed = %d\n",
					ret);
O
Oren Weil 已提交
402
			goto end;
T
Tomas Winkler 已提交
403
		}
O
Oren Weil 已提交
404
	} else {
405
		ret = mei_cl_irq_read_msg(dev, mei_hdr, cmpl_list);
T
Tomas Winkler 已提交
406 407 408
		if (ret) {
			dev_err(&dev->pdev->dev, "mei_cl_irq_read_msg failed = %d\n",
					ret);
O
Oren Weil 已提交
409
			goto end;
T
Tomas Winkler 已提交
410
		}
O
Oren Weil 已提交
411 412
	}

T
Tomas Winkler 已提交
413
reset_slots:
O
Oren Weil 已提交
414 415 416 417 418 419
	/* reset the number of slots and header */
	*slots = mei_count_full_read_slots(dev);
	dev->rd_msg_hdr = 0;

	if (*slots == -EOVERFLOW) {
		/* overflow - reset */
420
		dev_err(&dev->pdev->dev, "resetting due to slots overflow.\n");
O
Oren Weil 已提交
421 422 423 424 425 426 427
		/* set the event since message has been read */
		ret = -ERANGE;
		goto end;
	}
end:
	return ret;
}
428
EXPORT_SYMBOL_GPL(mei_irq_read_handler);
O
Oren Weil 已提交
429 430 431


/**
432 433
 * mei_irq_write_handler -  dispatch write requests
 *  after irq received
O
Oren Weil 已提交
434 435
 *
 * @dev: the device structure
436
 * @cmpl_list: An instance of our list structure
O
Oren Weil 已提交
437 438 439
 *
 * returns 0 on success, <0 on failure.
 */
T
Tomas Winkler 已提交
440
int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
O
Oren Weil 已提交
441 442 443
{

	struct mei_cl *cl;
444
	struct mei_cl_cb *cb, *next;
445
	struct mei_cl_cb *list;
446
	s32 slots;
O
Oren Weil 已提交
447 448
	int ret;

449
	if (!mei_hbuf_is_ready(dev)) {
O
Oren Weil 已提交
450 451 452
		dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
		return 0;
	}
453 454
	slots = mei_hbuf_empty_slots(dev);
	if (slots <= 0)
455 456
		return -EMSGSIZE;

O
Oren Weil 已提交
457 458 459 460
	/* complete all waiting for write CB */
	dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");

	list = &dev->write_waiting_list;
461 462
	list_for_each_entry_safe(cb, next, &list->list, list) {
		cl = cb->cl;
463 464 465 466
		if (cl == NULL)
			continue;

		cl->status = 0;
467
		list_del(&cb->list);
468
		if (MEI_WRITING == cl->writing_state &&
469
		    cb->fop_type == MEI_FOP_WRITE &&
470
		    cl != &dev->iamthif_cl) {
471
			cl_dbg(dev, cl, "MEI WRITE COMPLETE\n");
472
			cl->writing_state = MEI_WRITE_COMPLETE;
473
			list_add_tail(&cb->list, &cmpl_list->list);
474 475
		}
		if (cl == &dev->iamthif_cl) {
476
			cl_dbg(dev, cl, "check iamthif flow control.\n");
477
			if (dev->iamthif_flow_control_pending) {
478
				ret = mei_amthif_irq_read(dev, &slots);
479 480
				if (ret)
					return ret;
O
Oren Weil 已提交
481 482 483 484
			}
		}
	}

485 486
	if (dev->wd_state == MEI_WD_STOPPING) {
		dev->wd_state = MEI_WD_IDLE;
O
Oren Weil 已提交
487 488 489
		wake_up_interruptible(&dev->wait_stop_wd);
	}

490
	if (mei_cl_is_connected(&dev->wd_cl)) {
O
Oren Weil 已提交
491
		if (dev->wd_pending &&
T
Tomas Winkler 已提交
492
		    mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
O
Oren Weil 已提交
493 494
			if (mei_wd_send(dev))
				dev_dbg(&dev->pdev->dev, "wd send failed.\n");
T
Tomas Winkler 已提交
495
			else if (mei_cl_flow_ctrl_reduce(&dev->wd_cl))
496
				return -ENODEV;
O
Oren Weil 已提交
497

498
			dev->wd_pending = false;
O
Oren Weil 已提交
499

500
			if (dev->wd_state == MEI_WD_RUNNING)
501
				slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
502
			else
503
				slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE);
O
Oren Weil 已提交
504 505 506 507
		}
	}

	/* complete control write list CB */
508
	dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
509 510
	list_for_each_entry_safe(cb, next, &dev->ctrl_wr_list.list, list) {
		cl = cb->cl;
511
		if (!cl) {
512
			list_del(&cb->list);
513 514
			return -ENODEV;
		}
515
		switch (cb->fop_type) {
516
		case MEI_FOP_CLOSE:
517
			/* send disconnect message */
518
			ret = mei_cl_irq_close(cl, cb, &slots, cmpl_list);
519 520
			if (ret)
				return ret;
O
Oren Weil 已提交
521

522
			break;
523
		case MEI_FOP_READ:
524
			/* send flow control message */
525
			ret = mei_cl_irq_read(cl, cb, &slots, cmpl_list);
526 527
			if (ret)
				return ret;
O
Oren Weil 已提交
528

529
			break;
530
		case MEI_FOP_CONNECT:
531
			/* connect message */
532
			ret = mei_cl_irq_connect(cl, cb, &slots, cmpl_list);
533 534
			if (ret)
				return ret;
O
Oren Weil 已提交
535

536
			break;
T
Tomas Winkler 已提交
537 538 539 540 541
		case MEI_FOP_DISCONNECT_RSP:
			/* send disconnect resp */
			ret = mei_cl_irq_disconnect_rsp(cl, cb, &slots, cmpl_list);
			if (ret)
				return ret;
542 543
		default:
			BUG();
O
Oren Weil 已提交
544
		}
545

O
Oren Weil 已提交
546 547
	}
	/* complete  write list CB */
548
	dev_dbg(&dev->pdev->dev, "complete write list cb.\n");
549 550
	list_for_each_entry_safe(cb, next, &dev->write_list.list, list) {
		cl = cb->cl;
551 552
		if (cl == NULL)
			continue;
553
		if (cl == &dev->iamthif_cl)
554 555
			ret = mei_amthif_irq_write_complete(cl, cb,
						&slots, cmpl_list);
556
		else
557 558
			ret = mei_cl_irq_write_complete(cl, cb,
						&slots, cmpl_list);
559 560
		if (ret)
			return ret;
O
Oren Weil 已提交
561 562 563
	}
	return 0;
}
564
EXPORT_SYMBOL_GPL(mei_irq_write_handler);
O
Oren Weil 已提交
565 566 567 568 569 570 571 572 573



/**
 * mei_timer - timer function.
 *
 * @work: pointer to the work_struct structure
 *
 */
574
void mei_timer(struct work_struct *work)
O
Oren Weil 已提交
575 576 577 578 579 580 581 582
{
	unsigned long timeout;
	struct mei_cl *cl_pos = NULL;
	struct mei_cl *cl_next = NULL;
	struct mei_cl_cb  *cb_pos = NULL;
	struct mei_cl_cb  *cb_next = NULL;

	struct mei_device *dev = container_of(work,
583
					struct mei_device, timer_work.work);
O
Oren Weil 已提交
584 585 586


	mutex_lock(&dev->device_lock);
587 588 589 590 591 592 593 594 595

	/* Catch interrupt stalls during HBM init handshake */
	if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
	    dev->hbm_state != MEI_HBM_IDLE) {

		if (dev->init_clients_timer) {
			if (--dev->init_clients_timer == 0) {
				dev_err(&dev->pdev->dev, "timer: init clients timeout hbm_state = %d.\n",
					dev->hbm_state);
596
				mei_reset(dev);
597
				goto out;
O
Oren Weil 已提交
598 599 600
			}
		}
	}
601 602 603 604

	if (dev->dev_state != MEI_DEV_ENABLED)
		goto out;

O
Oren Weil 已提交
605 606 607 608
	/*** connect/disconnect timeouts ***/
	list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
		if (cl_pos->timer_count) {
			if (--cl_pos->timer_count == 0) {
609 610
				dev_err(&dev->pdev->dev, "timer: connect/disconnect timeout.\n");
				mei_reset(dev);
O
Oren Weil 已提交
611 612 613 614 615
				goto out;
			}
		}
	}

616 617 618
	if (!mei_cl_is_connected(&dev->iamthif_cl))
		goto out;

O
Oren Weil 已提交
619 620
	if (dev->iamthif_stall_timer) {
		if (--dev->iamthif_stall_timer == 0) {
621 622
			dev_err(&dev->pdev->dev, "timer: amthif  hanged.\n");
			mei_reset(dev);
O
Oren Weil 已提交
623 624
			dev->iamthif_msg_buf_size = 0;
			dev->iamthif_msg_buf_index = 0;
625 626
			dev->iamthif_canceled = false;
			dev->iamthif_ioctl = true;
O
Oren Weil 已提交
627 628 629
			dev->iamthif_state = MEI_IAMTHIF_IDLE;
			dev->iamthif_timer = 0;

630 631
			mei_io_cb_free(dev->iamthif_current_cb);
			dev->iamthif_current_cb = NULL;
O
Oren Weil 已提交
632 633

			dev->iamthif_file_object = NULL;
634
			mei_amthif_run_next_cmd(dev);
O
Oren Weil 已提交
635 636 637 638 639 640
		}
	}

	if (dev->iamthif_timer) {

		timeout = dev->iamthif_timer +
641
			mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
O
Oren Weil 已提交
642 643 644 645 646 647 648 649 650 651 652 653 654

		dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
				dev->iamthif_timer);
		dev_dbg(&dev->pdev->dev, "timeout = %ld\n", timeout);
		dev_dbg(&dev->pdev->dev, "jiffies = %ld\n", jiffies);
		if (time_after(jiffies, timeout)) {
			/*
			 * User didn't read the AMTHI data on time (15sec)
			 * freeing AMTHI for other requests
			 */

			dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n");

655 656
			list_for_each_entry_safe(cb_pos, cb_next,
				&dev->amthif_rd_complete_list.list, list) {
O
Oren Weil 已提交
657

658
				cl_pos = cb_pos->file_object->private_data;
O
Oren Weil 已提交
659

660 661
				/* Finding the AMTHI entry. */
				if (cl_pos == &dev->iamthif_cl)
662
					list_del(&cb_pos->list);
O
Oren Weil 已提交
663
			}
664 665
			mei_io_cb_free(dev->iamthif_current_cb);
			dev->iamthif_current_cb = NULL;
O
Oren Weil 已提交
666 667 668 669

			dev->iamthif_file_object->private_data = NULL;
			dev->iamthif_file_object = NULL;
			dev->iamthif_timer = 0;
670
			mei_amthif_run_next_cmd(dev);
O
Oren Weil 已提交
671 672 673 674

		}
	}
out:
675 676
	if (dev->dev_state != MEI_DEV_DISABLED)
		schedule_delayed_work(&dev->timer_work, 2 * HZ);
677
	mutex_unlock(&dev->device_lock);
O
Oren Weil 已提交
678 679
}