interrupt.c 20.2 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 18 19 20 21 22 23
 *
 * 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/pci.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/jiffies.h>

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

#include "mei_dev.h"
27
#include "hbm.h"
O
Oren Weil 已提交
28 29 30 31 32 33 34 35 36 37 38
#include "interface.h"


/**
 * _mei_cmpl - processes completed operation.
 *
 * @cl: private data of the file object.
 * @cb_pos: callback block.
 */
static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
{
39
	if (cb_pos->fop_type == MEI_FOP_WRITE) {
40
		mei_io_cb_free(cb_pos);
O
Oren Weil 已提交
41 42 43 44 45
		cb_pos = NULL;
		cl->writing_state = MEI_WRITE_COMPLETE;
		if (waitqueue_active(&cl->tx_wait))
			wake_up_interruptible(&cl->tx_wait);

46
	} else if (cb_pos->fop_type == MEI_FOP_READ &&
O
Oren Weil 已提交
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
			MEI_READING == cl->reading_state) {
		cl->reading_state = MEI_READ_COMPLETE;
		if (waitqueue_active(&cl->rx_wait))
			wake_up_interruptible(&cl->rx_wait);

	}
}

/**
 * _mei_irq_thread_state_ok - checks if mei header matches file private data
 *
 * @cl: private data of the file object
 * @mei_hdr: header of mei client message
 *
 * returns !=0 if matches, 0 if no match.
 */
static int _mei_irq_thread_state_ok(struct mei_cl *cl,
				struct mei_msg_hdr *mei_hdr)
{
	return (cl->host_client_id == mei_hdr->host_addr &&
		cl->me_client_id == mei_hdr->me_addr &&
		cl->state == MEI_FILE_CONNECTED &&
		MEI_READ_COMPLETE != cl->reading_state);
}

/**
 * mei_irq_thread_read_client_message - bottom half read routine after ISR to
 * handle the read mei client message data processing.
 *
 * @complete_list: An instance of our list structure
 * @dev: the device structure
 * @mei_hdr: header of mei client message
 *
 * returns 0 on success, <0 on failure.
 */
82
static int mei_irq_thread_read_client_message(struct mei_cl_cb *complete_list,
O
Oren Weil 已提交
83 84 85 86 87
		struct mei_device *dev,
		struct mei_msg_hdr *mei_hdr)
{
	struct mei_cl *cl;
	struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
88
	unsigned char *buffer = NULL;
O
Oren Weil 已提交
89 90

	dev_dbg(&dev->pdev->dev, "start client msg\n");
91
	if (list_empty(&dev->read_list.list))
O
Oren Weil 已提交
92 93
		goto quit;

94
	list_for_each_entry_safe(cb_pos, cb_next, &dev->read_list.list, list) {
95
		cl = cb_pos->cl;
O
Oren Weil 已提交
96 97
		if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
			cl->reading_state = MEI_READING;
98
			buffer = cb_pos->response_buffer.data + cb_pos->buf_idx;
O
Oren Weil 已提交
99 100

			if (cb_pos->response_buffer.size <
101
					mei_hdr->length + cb_pos->buf_idx) {
O
Oren Weil 已提交
102
				dev_dbg(&dev->pdev->dev, "message overflow.\n");
103
				list_del(&cb_pos->list);
O
Oren Weil 已提交
104 105 106 107 108
				return -ENOMEM;
			}
			if (buffer)
				mei_read_slots(dev, buffer, mei_hdr->length);

109
			cb_pos->buf_idx += mei_hdr->length;
O
Oren Weil 已提交
110 111
			if (mei_hdr->msg_complete) {
				cl->status = 0;
112
				list_del(&cb_pos->list);
O
Oren Weil 已提交
113
				dev_dbg(&dev->pdev->dev,
114
					"completed read H cl = %d, ME cl = %d, length = %lu\n",
O
Oren Weil 已提交
115 116
					cl->host_client_id,
					cl->me_client_id,
117 118
					cb_pos->buf_idx);

119 120
				list_add_tail(&cb_pos->list,
						&complete_list->list);
O
Oren Weil 已提交
121 122 123 124 125 126 127 128 129 130
			}

			break;
		}

	}

quit:
	dev_dbg(&dev->pdev->dev, "message read\n");
	if (!buffer) {
131
		mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
132 133
		dev_dbg(&dev->pdev->dev, "discarding message " MEI_HDR_FMT "\n",
				MEI_HDR_PRM(mei_hdr));
O
Oren Weil 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
	}

	return 0;
}

/**
 * _mei_irq_thread_close - processes close related operation.
 *
 * @dev: the device structure.
 * @slots: free slots.
 * @cb_pos: callback block.
 * @cl: private data of the file object.
 * @cmpl_list: complete list.
 *
 * returns 0, OK; otherwise, error.
 */
static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots,
				struct mei_cl_cb *cb_pos,
				struct mei_cl *cl,
153
				struct mei_cl_cb *cmpl_list)
O
Oren Weil 已提交
154
{
155
	if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) +
156
			sizeof(struct hbm_client_connect_request)))
157
		return -EBADMSG;
O
Oren Weil 已提交
158

159
	*slots -= mei_data2slots(sizeof(struct hbm_client_connect_request));
160

161
	if (mei_hbm_cl_disconnect_req(dev, cl)) {
162
		cl->status = 0;
163
		cb_pos->buf_idx = 0;
164
		list_move_tail(&cb_pos->list, &cmpl_list->list);
165
		return -EMSGSIZE;
O
Oren Weil 已提交
166
	} else {
167 168
		cl->state = MEI_FILE_DISCONNECTING;
		cl->status = 0;
169
		cb_pos->buf_idx = 0;
170
		list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list);
171
		cl->timer_count = MEI_CONNECT_TIMEOUT;
O
Oren Weil 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
	}

	return 0;
}


/**
 * _mei_hb_read - processes read related operation.
 *
 * @dev: the device structure.
 * @slots: free slots.
 * @cb_pos: callback block.
 * @cl: private data of the file object.
 * @cmpl_list: complete list.
 *
 * returns 0, OK; otherwise, error.
 */
static int _mei_irq_thread_read(struct mei_device *dev,	s32 *slots,
			struct mei_cl_cb *cb_pos,
			struct mei_cl *cl,
192
			struct mei_cl_cb *cmpl_list)
O
Oren Weil 已提交
193
{
T
Tomas Winkler 已提交
194
	if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) +
O
Oren Weil 已提交
195 196
			sizeof(struct hbm_flow_control))) {
		/* return the cancel routine */
197
		list_del(&cb_pos->list);
O
Oren Weil 已提交
198 199 200
		return -EBADMSG;
	}

201 202
	*slots -= mei_data2slots(sizeof(struct hbm_flow_control));

203
	if (mei_hbm_cl_flow_control_req(dev, cl)) {
204
		cl->status = -ENODEV;
205
		cb_pos->buf_idx = 0;
206
		list_move_tail(&cb_pos->list, &cmpl_list->list);
207 208
		return -ENODEV;
	}
209
	list_move_tail(&cb_pos->list, &dev->read_list.list);
210

O
Oren Weil 已提交
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
	return 0;
}


/**
 * _mei_irq_thread_ioctl - processes ioctl related operation.
 *
 * @dev: the device structure.
 * @slots: free slots.
 * @cb_pos: callback block.
 * @cl: private data of the file object.
 * @cmpl_list: complete list.
 *
 * returns 0, OK; otherwise, error.
 */
static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots,
			struct mei_cl_cb *cb_pos,
			struct mei_cl *cl,
229
			struct mei_cl_cb *cmpl_list)
O
Oren Weil 已提交
230
{
231
	if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) +
O
Oren Weil 已提交
232 233
			sizeof(struct hbm_client_connect_request))) {
		/* return the cancel routine */
234
		list_del(&cb_pos->list);
O
Oren Weil 已提交
235 236 237
		return -EBADMSG;
	}

238
	cl->state = MEI_FILE_CONNECTING;
239 240
	*slots -= mei_data2slots(sizeof(struct hbm_client_connect_request));
	if (mei_hbm_cl_connect_req(dev, cl)) {
241
		cl->status = -ENODEV;
242
		cb_pos->buf_idx = 0;
243
		list_del(&cb_pos->list);
244 245
		return -ENODEV;
	} else {
246
		list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list);
247 248
		cl->timer_count = MEI_CONNECT_TIMEOUT;
	}
O
Oren Weil 已提交
249 250 251 252
	return 0;
}

/**
253
 * mei_irq_thread_write_complete - write messages to device.
O
Oren Weil 已提交
254 255 256
 *
 * @dev: the device structure.
 * @slots: free slots.
257
 * @cb: callback block.
O
Oren Weil 已提交
258 259 260 261
 * @cmpl_list: complete list.
 *
 * returns 0, OK; otherwise, error.
 */
262 263
static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots,
			struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list)
O
Oren Weil 已提交
264
{
265
	struct mei_msg_hdr mei_hdr;
266 267 268 269
	struct mei_cl *cl = cb->cl;
	size_t len = cb->request_buffer.size - cb->buf_idx;
	size_t msg_slots = mei_data2slots(len);

270 271 272
	mei_hdr.host_addr = cl->host_client_id;
	mei_hdr.me_addr = cl->me_client_id;
	mei_hdr.reserved = 0;
O
Oren Weil 已提交
273

274
	if (*slots >= msg_slots) {
275 276
		mei_hdr.length = len;
		mei_hdr.msg_complete = 1;
277
	/* Split the message only if we can write the whole host buffer */
278
	} else if (*slots == dev->hbuf_depth) {
279 280
		msg_slots = *slots;
		len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
281 282
		mei_hdr.length = len;
		mei_hdr.msg_complete = 0;
O
Oren Weil 已提交
283
	} else {
284 285
		/* wait for next time the host buffer is empty */
		return 0;
O
Oren Weil 已提交
286 287
	}

288 289
	dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n",
			cb->request_buffer.size, cb->buf_idx);
290
	dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr));
291 292

	*slots -=  msg_slots;
293
	if (mei_write_message(dev, &mei_hdr,
294
			cb->request_buffer.data + cb->buf_idx)) {
295 296 297 298 299 300 301 302 303
		cl->status = -ENODEV;
		list_move_tail(&cb->list, &cmpl_list->list);
		return -ENODEV;
	}

	if (mei_flow_ctrl_reduce(dev, cl))
		return -ENODEV;

	cl->status = 0;
304 305
	cb->buf_idx += mei_hdr.length;
	if (mei_hdr.msg_complete)
306 307
		list_move_tail(&cb->list, &dev->write_waiting_list.list);

O
Oren Weil 已提交
308 309 310 311 312 313 314 315 316 317 318 319 320
	return 0;
}

/**
 * mei_irq_thread_read_handler - bottom half read routine after ISR to
 * handle the read processing.
 *
 * @cmpl_list: An instance of our list structure
 * @dev: the device structure
 * @slots: slots to read.
 *
 * returns 0 on success, <0 on failure.
 */
321
static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list,
O
Oren Weil 已提交
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
		struct mei_device *dev,
		s32 *slots)
{
	struct mei_msg_hdr *mei_hdr;
	struct mei_cl *cl_pos = NULL;
	struct mei_cl *cl_next = NULL;
	int ret = 0;

	if (!dev->rd_msg_hdr) {
		dev->rd_msg_hdr = mei_mecbrw_read(dev);
		dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
		(*slots)--;
		dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
	}
	mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr;
337
	dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
O
Oren Weil 已提交
338 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 366 367 368 369 370 371 372 373 374 375

	if (mei_hdr->reserved || !dev->rd_msg_hdr) {
		dev_dbg(&dev->pdev->dev, "corrupted message header.\n");
		ret = -EBADMSG;
		goto end;
	}

	if (mei_hdr->host_addr || mei_hdr->me_addr) {
		list_for_each_entry_safe(cl_pos, cl_next,
					&dev->file_list, link) {
			dev_dbg(&dev->pdev->dev,
					"list_for_each_entry_safe read host"
					" client = %d, ME client = %d\n",
					cl_pos->host_client_id,
					cl_pos->me_client_id);
			if (cl_pos->host_client_id == mei_hdr->host_addr &&
			    cl_pos->me_client_id == mei_hdr->me_addr)
				break;
		}

		if (&cl_pos->link == &dev->file_list) {
			dev_dbg(&dev->pdev->dev, "corrupted message header\n");
			ret = -EBADMSG;
			goto end;
		}
	}
	if (((*slots) * sizeof(u32)) < mei_hdr->length) {
		dev_dbg(&dev->pdev->dev,
				"we can't read the message slots =%08x.\n",
				*slots);
		/* we can't read the message */
		ret = -ERANGE;
		goto end;
	}

	/* decide where to read the message too */
	if (!mei_hdr->host_addr) {
		dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n");
376
		mei_hbm_dispatch(dev, mei_hdr);
O
Oren Weil 已提交
377 378 379 380 381
		dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n");
	} else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
		   (MEI_FILE_CONNECTED == dev->iamthif_cl.state) &&
		   (dev->iamthif_state == MEI_IAMTHIF_READING)) {
		dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
382 383

		dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
384 385

		ret = mei_amthif_irq_read_message(cmpl_list, dev, mei_hdr);
O
Oren Weil 已提交
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
		if (ret)
			goto end;
	} else {
		dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n");
		ret = mei_irq_thread_read_client_message(cmpl_list,
							 dev, mei_hdr);
		if (ret)
			goto end;

	}

	/* reset the number of slots and header */
	*slots = mei_count_full_read_slots(dev);
	dev->rd_msg_hdr = 0;

	if (*slots == -EOVERFLOW) {
		/* overflow - reset */
		dev_dbg(&dev->pdev->dev, "resetting due to slots overflow.\n");
		/* set the event since message has been read */
		ret = -ERANGE;
		goto end;
	}
end:
	return ret;
}


/**
 * mei_irq_thread_write_handler - bottom half write routine after
 * ISR to handle the write processing.
 *
 * @dev: the device structure
418
 * @cmpl_list: An instance of our list structure
O
Oren Weil 已提交
419 420 421
 *
 * returns 0 on success, <0 on failure.
 */
422 423
static int mei_irq_thread_write_handler(struct mei_device *dev,
				struct mei_cl_cb *cmpl_list)
O
Oren Weil 已提交
424 425 426
{

	struct mei_cl *cl;
427
	struct mei_cl_cb *pos = NULL, *next = NULL;
428
	struct mei_cl_cb *list;
429
	s32 slots;
O
Oren Weil 已提交
430 431
	int ret;

432
	if (!mei_hbuf_is_empty(dev)) {
O
Oren Weil 已提交
433 434 435
		dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
		return 0;
	}
436 437
	slots = mei_hbuf_empty_slots(dev);
	if (slots <= 0)
438 439
		return -EMSGSIZE;

O
Oren Weil 已提交
440 441 442 443
	/* complete all waiting for write CB */
	dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");

	list = &dev->write_waiting_list;
444
	list_for_each_entry_safe(pos, next, &list->list, list) {
445
		cl = pos->cl;
446 447 448 449
		if (cl == NULL)
			continue;

		cl->status = 0;
450
		list_del(&pos->list);
451
		if (MEI_WRITING == cl->writing_state &&
452 453
		    pos->fop_type == MEI_FOP_WRITE &&
		    cl != &dev->iamthif_cl) {
454
			dev_dbg(&dev->pdev->dev, "MEI WRITE COMPLETE\n");
455
			cl->writing_state = MEI_WRITE_COMPLETE;
456
			list_add_tail(&pos->list, &cmpl_list->list);
457 458 459 460
		}
		if (cl == &dev->iamthif_cl) {
			dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n");
			if (dev->iamthif_flow_control_pending) {
461
				ret = mei_amthif_irq_read(dev, &slots);
462 463
				if (ret)
					return ret;
O
Oren Weil 已提交
464 465 466 467
			}
		}
	}

468 469
	if (dev->wd_state == MEI_WD_STOPPING) {
		dev->wd_state = MEI_WD_IDLE;
O
Oren Weil 已提交
470 471 472
		wake_up_interruptible(&dev->wait_stop_wd);
	}

473 474
	if (dev->wr_ext_msg.hdr.length) {
		mei_write_message(dev, &dev->wr_ext_msg.hdr,
475
				dev->wr_ext_msg.data);
476
		slots -= mei_data2slots(dev->wr_ext_msg.hdr.length);
477
		dev->wr_ext_msg.hdr.length = 0;
O
Oren Weil 已提交
478
	}
479
	if (dev->dev_state == MEI_DEV_ENABLED) {
O
Oren Weil 已提交
480
		if (dev->wd_pending &&
481
		    mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
O
Oren Weil 已提交
482 483
			if (mei_wd_send(dev))
				dev_dbg(&dev->pdev->dev, "wd send failed.\n");
484 485
			else if (mei_flow_ctrl_reduce(dev, &dev->wd_cl))
				return -ENODEV;
O
Oren Weil 已提交
486

487
			dev->wd_pending = false;
O
Oren Weil 已提交
488

489
			if (dev->wd_state == MEI_WD_RUNNING)
490
				slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
491
			else
492
				slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE);
O
Oren Weil 已提交
493 494 495 496
		}
	}

	/* complete control write list CB */
497
	dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
498
	list_for_each_entry_safe(pos, next, &dev->ctrl_wr_list.list, list) {
499
		cl = pos->cl;
500
		if (!cl) {
501
			list_del(&pos->list);
502 503
			return -ENODEV;
		}
504 505
		switch (pos->fop_type) {
		case MEI_FOP_CLOSE:
506
			/* send disconnect message */
507 508
			ret = _mei_irq_thread_close(dev, &slots, pos,
						cl, cmpl_list);
509 510
			if (ret)
				return ret;
O
Oren Weil 已提交
511

512
			break;
513
		case MEI_FOP_READ:
514
			/* send flow control message */
515 516
			ret = _mei_irq_thread_read(dev, &slots, pos,
						cl, cmpl_list);
517 518
			if (ret)
				return ret;
O
Oren Weil 已提交
519

520
			break;
521
		case MEI_FOP_IOCTL:
522
			/* connect message */
523
			if (mei_other_client_is_connecting(dev, cl))
524
				continue;
525 526
			ret = _mei_irq_thread_ioctl(dev, &slots, pos,
						cl, cmpl_list);
527 528
			if (ret)
				return ret;
O
Oren Weil 已提交
529

530
			break;
O
Oren Weil 已提交
531

532 533
		default:
			BUG();
O
Oren Weil 已提交
534
		}
535

O
Oren Weil 已提交
536 537
	}
	/* complete  write list CB */
538
	dev_dbg(&dev->pdev->dev, "complete write list cb.\n");
539
	list_for_each_entry_safe(pos, next, &dev->write_list.list, list) {
540
		cl = pos->cl;
541 542
		if (cl == NULL)
			continue;
543 544 545 546 547 548
		if (mei_flow_ctrl_creds(dev, cl) <= 0) {
			dev_dbg(&dev->pdev->dev,
				"No flow control credentials for client %d, not sending.\n",
				cl->host_client_id);
			continue;
		}
549

550
		if (cl == &dev->iamthif_cl)
551
			ret = mei_amthif_irq_write_complete(dev, &slots,
552
							pos, cmpl_list);
553 554 555 556 557
		else
			ret = mei_irq_thread_write_complete(dev, &slots, pos,
						cmpl_list);
		if (ret)
			return ret;
558

O
Oren Weil 已提交
559 560 561 562 563 564 565 566 567 568 569 570 571
	}
	return 0;
}



/**
 * mei_timer - timer function.
 *
 * @work: pointer to the work_struct structure
 *
 * NOTE: This function is called by timer interrupt work
 */
572
void mei_timer(struct work_struct *work)
O
Oren Weil 已提交
573 574 575 576 577 578 579 580
{
	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,
581
					struct mei_device, timer_work.work);
O
Oren Weil 已提交
582 583 584


	mutex_lock(&dev->device_lock);
585 586
	if (dev->dev_state != MEI_DEV_ENABLED) {
		if (dev->dev_state == MEI_DEV_INIT_CLIENTS) {
O
Oren Weil 已提交
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
			if (dev->init_clients_timer) {
				if (--dev->init_clients_timer == 0) {
					dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
						dev->init_clients_state);
					mei_reset(dev, 1);
				}
			}
		}
		goto out;
	}
	/*** 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) {
				dev_dbg(&dev->pdev->dev, "HECI reset due to connect/disconnect timeout.\n");
				mei_reset(dev, 1);
				goto out;
			}
		}
	}

	if (dev->iamthif_stall_timer) {
		if (--dev->iamthif_stall_timer == 0) {
610
			dev_dbg(&dev->pdev->dev, "resetting because of hang to amthi.\n");
O
Oren Weil 已提交
611 612 613
			mei_reset(dev, 1);
			dev->iamthif_msg_buf_size = 0;
			dev->iamthif_msg_buf_index = 0;
614 615
			dev->iamthif_canceled = false;
			dev->iamthif_ioctl = true;
O
Oren Weil 已提交
616 617 618
			dev->iamthif_state = MEI_IAMTHIF_IDLE;
			dev->iamthif_timer = 0;

619 620
			mei_io_cb_free(dev->iamthif_current_cb);
			dev->iamthif_current_cb = NULL;
O
Oren Weil 已提交
621 622

			dev->iamthif_file_object = NULL;
623
			mei_amthif_run_next_cmd(dev);
O
Oren Weil 已提交
624 625 626 627 628 629
		}
	}

	if (dev->iamthif_timer) {

		timeout = dev->iamthif_timer +
630
			mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
O
Oren Weil 已提交
631 632 633 634 635 636 637 638 639 640 641 642 643

		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");

644 645
			list_for_each_entry_safe(cb_pos, cb_next,
				&dev->amthif_rd_complete_list.list, list) {
O
Oren Weil 已提交
646

647
				cl_pos = cb_pos->file_object->private_data;
O
Oren Weil 已提交
648

649 650
				/* Finding the AMTHI entry. */
				if (cl_pos == &dev->iamthif_cl)
651
					list_del(&cb_pos->list);
O
Oren Weil 已提交
652
			}
653 654
			mei_io_cb_free(dev->iamthif_current_cb);
			dev->iamthif_current_cb = NULL;
O
Oren Weil 已提交
655 656 657 658

			dev->iamthif_file_object->private_data = NULL;
			dev->iamthif_file_object = NULL;
			dev->iamthif_timer = 0;
659
			mei_amthif_run_next_cmd(dev);
O
Oren Weil 已提交
660 661 662 663

		}
	}
out:
664 665
	schedule_delayed_work(&dev->timer_work, 2 * HZ);
	mutex_unlock(&dev->device_lock);
O
Oren Weil 已提交
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
}

/**
 *  mei_interrupt_thread_handler - function called after ISR to handle the interrupt
 * processing.
 *
 * @irq: The irq number
 * @dev_id: pointer to the device structure
 *
 * returns irqreturn_t
 *
 */
irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
{
	struct mei_device *dev = (struct mei_device *) dev_id;
681
	struct mei_cl_cb complete_list;
O
Oren Weil 已提交
682 683 684 685 686 687 688 689 690 691
	struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
	struct mei_cl *cl;
	s32 slots;
	int rets;
	bool  bus_message_received;


	dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
	/* initialize our complete list */
	mutex_lock(&dev->device_lock);
692
	mei_io_list_init(&complete_list);
O
Oren Weil 已提交
693
	dev->host_hw_state = mei_hcsr_read(dev);
694 695

	/* Ack the interrupt here
696
	 * In case of MSI we don't go through the quick handler */
697
	if (pci_dev_msi_enabled(dev->pdev))
698
		mei_clear_interrupts(dev);
699

O
Oren Weil 已提交
700 701 702 703
	dev->me_hw_state = mei_mecsr_read(dev);

	/* check if ME wants a reset */
	if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
704 705
	    dev->dev_state != MEI_DEV_RESETING &&
	    dev->dev_state != MEI_DEV_INITIALIZING) {
O
Oren Weil 已提交
706 707 708 709 710 711 712 713 714 715 716 717
		dev_dbg(&dev->pdev->dev, "FW not ready.\n");
		mei_reset(dev, 1);
		mutex_unlock(&dev->device_lock);
		return IRQ_HANDLED;
	}

	/*  check if we need to start the dev */
	if ((dev->host_hw_state & H_RDY) == 0) {
		if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) {
			dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
			dev->host_hw_state |= (H_IE | H_IG | H_RDY);
			mei_hcsr_set(dev);
718
			dev->dev_state = MEI_DEV_INIT_CLIENTS;
O
Oren Weil 已提交
719 720 721 722
			dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
			/* link is established
			 * start sending messages.
			 */
723
			mei_hbm_start_req(dev);
O
Oren Weil 已提交
724 725 726 727 728 729 730 731
			mutex_unlock(&dev->device_lock);
			return IRQ_HANDLED;
		} else {
			dev_dbg(&dev->pdev->dev, "FW not ready.\n");
			mutex_unlock(&dev->device_lock);
			return IRQ_HANDLED;
		}
	}
732
	/* check slots available for reading */
O
Oren Weil 已提交
733
	slots = mei_count_full_read_slots(dev);
734 735 736 737 738
	while (slots > 0) {
		/* we have urgent data to send so break the read */
		if (dev->wr_ext_msg.hdr.length)
			break;
		dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots);
O
Oren Weil 已提交
739 740 741 742 743
		dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n");
		rets = mei_irq_thread_read_handler(&complete_list, dev, &slots);
		if (rets)
			goto end;
	}
744
	rets = mei_irq_thread_write_handler(dev, &complete_list);
O
Oren Weil 已提交
745 746 747
end:
	dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
	dev->host_hw_state = mei_hcsr_read(dev);
748
	dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev);
O
Oren Weil 已提交
749 750 751 752 753 754 755 756 757 758 759 760

	bus_message_received = false;
	if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
		dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
		bus_message_received = true;
	}
	mutex_unlock(&dev->device_lock);
	if (bus_message_received) {
		dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
		wake_up_interruptible(&dev->wait_recvd_msg);
		bus_message_received = false;
	}
761
	if (list_empty(&complete_list.list))
O
Oren Weil 已提交
762 763 764
		return IRQ_HANDLED;


765
	list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) {
766
		cl = cb_pos->cl;
767
		list_del(&cb_pos->list);
O
Oren Weil 已提交
768 769 770 771 772 773
		if (cl) {
			if (cl != &dev->iamthif_cl) {
				dev_dbg(&dev->pdev->dev, "completing call back.\n");
				_mei_cmpl(cl, cb_pos);
				cb_pos = NULL;
			} else if (cl == &dev->iamthif_cl) {
774
				mei_amthif_complete(dev, cb_pos);
O
Oren Weil 已提交
775 776 777 778 779
			}
		}
	}
	return IRQ_HANDLED;
}