]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/misc/mei/interrupt.c
mei: extract device dependent constants into hw-me.h
[mirror_ubuntu-artful-kernel.git] / drivers / misc / mei / interrupt.c
CommitLineData
fb7d879f
OW
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
733ba91c 4 * Copyright (c) 2003-2012, Intel Corporation.
fb7d879f
OW
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
17
18#include <linux/pci.h>
19#include <linux/kthread.h>
20#include <linux/interrupt.h>
21#include <linux/fs.h>
22#include <linux/jiffies.h>
23
24#include "mei_dev.h"
4f3afe1d 25#include <linux/mei.h>
fb7d879f
OW
26#include "hw.h"
27#include "interface.h"
28
29
30/**
31 * mei_interrupt_quick_handler - The ISR of the MEI device
32 *
33 * @irq: The irq number
34 * @dev_id: pointer to the device structure
35 *
36 * returns irqreturn_t
37 */
38irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id)
39{
40 struct mei_device *dev = (struct mei_device *) dev_id;
41 u32 csr_reg = mei_hcsr_read(dev);
42
43 if ((csr_reg & H_IS) != H_IS)
44 return IRQ_NONE;
45
46 /* clear H_IS bit in H_CSR */
47 mei_reg_write(dev, H_CSR, csr_reg);
48
49 return IRQ_WAKE_THREAD;
50}
51
52/**
53 * _mei_cmpl - processes completed operation.
54 *
55 * @cl: private data of the file object.
56 * @cb_pos: callback block.
57 */
58static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
59{
4b8960b4 60 if (cb_pos->fop_type == MEI_FOP_WRITE) {
601a1efa 61 mei_io_cb_free(cb_pos);
fb7d879f
OW
62 cb_pos = NULL;
63 cl->writing_state = MEI_WRITE_COMPLETE;
64 if (waitqueue_active(&cl->tx_wait))
65 wake_up_interruptible(&cl->tx_wait);
66
4b8960b4 67 } else if (cb_pos->fop_type == MEI_FOP_READ &&
fb7d879f
OW
68 MEI_READING == cl->reading_state) {
69 cl->reading_state = MEI_READ_COMPLETE;
70 if (waitqueue_active(&cl->rx_wait))
71 wake_up_interruptible(&cl->rx_wait);
72
73 }
74}
75
fb7d879f
OW
76/**
77 * _mei_irq_thread_state_ok - checks if mei header matches file private data
78 *
79 * @cl: private data of the file object
80 * @mei_hdr: header of mei client message
81 *
82 * returns !=0 if matches, 0 if no match.
83 */
84static int _mei_irq_thread_state_ok(struct mei_cl *cl,
85 struct mei_msg_hdr *mei_hdr)
86{
87 return (cl->host_client_id == mei_hdr->host_addr &&
88 cl->me_client_id == mei_hdr->me_addr &&
89 cl->state == MEI_FILE_CONNECTED &&
90 MEI_READ_COMPLETE != cl->reading_state);
91}
92
93/**
94 * mei_irq_thread_read_client_message - bottom half read routine after ISR to
95 * handle the read mei client message data processing.
96 *
97 * @complete_list: An instance of our list structure
98 * @dev: the device structure
99 * @mei_hdr: header of mei client message
100 *
101 * returns 0 on success, <0 on failure.
102 */
fb601adb 103static int mei_irq_thread_read_client_message(struct mei_cl_cb *complete_list,
fb7d879f
OW
104 struct mei_device *dev,
105 struct mei_msg_hdr *mei_hdr)
106{
107 struct mei_cl *cl;
108 struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
479bc59d 109 unsigned char *buffer = NULL;
fb7d879f
OW
110
111 dev_dbg(&dev->pdev->dev, "start client msg\n");
fb601adb 112 if (list_empty(&dev->read_list.list))
fb7d879f
OW
113 goto quit;
114
fb601adb 115 list_for_each_entry_safe(cb_pos, cb_next, &dev->read_list.list, list) {
db3ed431 116 cl = cb_pos->cl;
fb7d879f
OW
117 if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
118 cl->reading_state = MEI_READING;
ebb108ef 119 buffer = cb_pos->response_buffer.data + cb_pos->buf_idx;
fb7d879f
OW
120
121 if (cb_pos->response_buffer.size <
ebb108ef 122 mei_hdr->length + cb_pos->buf_idx) {
fb7d879f 123 dev_dbg(&dev->pdev->dev, "message overflow.\n");
fb601adb 124 list_del(&cb_pos->list);
fb7d879f
OW
125 return -ENOMEM;
126 }
127 if (buffer)
128 mei_read_slots(dev, buffer, mei_hdr->length);
129
ebb108ef 130 cb_pos->buf_idx += mei_hdr->length;
fb7d879f
OW
131 if (mei_hdr->msg_complete) {
132 cl->status = 0;
fb601adb 133 list_del(&cb_pos->list);
fb7d879f 134 dev_dbg(&dev->pdev->dev,
a4136b49 135 "completed read H cl = %d, ME cl = %d, length = %lu\n",
fb7d879f
OW
136 cl->host_client_id,
137 cl->me_client_id,
ebb108ef
TW
138 cb_pos->buf_idx);
139
fb601adb
TW
140 list_add_tail(&cb_pos->list,
141 &complete_list->list);
fb7d879f
OW
142 }
143
144 break;
145 }
146
147 }
148
149quit:
150 dev_dbg(&dev->pdev->dev, "message read\n");
151 if (!buffer) {
edf1eed4 152 mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
15d4acc5
TW
153 dev_dbg(&dev->pdev->dev, "discarding message " MEI_HDR_FMT "\n",
154 MEI_HDR_PRM(mei_hdr));
fb7d879f
OW
155 }
156
157 return 0;
158}
159
fb7d879f
OW
160/**
161 * _mei_irq_thread_close - processes close related operation.
162 *
163 * @dev: the device structure.
164 * @slots: free slots.
165 * @cb_pos: callback block.
166 * @cl: private data of the file object.
167 * @cmpl_list: complete list.
168 *
169 * returns 0, OK; otherwise, error.
170 */
171static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots,
172 struct mei_cl_cb *cb_pos,
173 struct mei_cl *cl,
fb601adb 174 struct mei_cl_cb *cmpl_list)
fb7d879f 175{
b45f3ccf 176 if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) +
aeba4a06 177 sizeof(struct hbm_client_connect_request)))
b45f3ccf 178 return -EBADMSG;
fb7d879f 179
aeba4a06 180 *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request));
b45f3ccf
TW
181
182 if (mei_disconnect(dev, cl)) {
183 cl->status = 0;
ebb108ef 184 cb_pos->buf_idx = 0;
fb601adb 185 list_move_tail(&cb_pos->list, &cmpl_list->list);
b45f3ccf 186 return -EMSGSIZE;
fb7d879f 187 } else {
b45f3ccf
TW
188 cl->state = MEI_FILE_DISCONNECTING;
189 cl->status = 0;
ebb108ef 190 cb_pos->buf_idx = 0;
fb601adb 191 list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list);
b45f3ccf 192 cl->timer_count = MEI_CONNECT_TIMEOUT;
fb7d879f
OW
193 }
194
195 return 0;
196}
197
198/**
199 * is_treat_specially_client - checks if the message belongs
200 * to the file private data.
201 *
202 * @cl: private data of the file object
203 * @rs: connect response bus message
204 *
205 */
206static bool is_treat_specially_client(struct mei_cl *cl,
207 struct hbm_client_connect_response *rs)
208{
209
210 if (cl->host_client_id == rs->host_addr &&
211 cl->me_client_id == rs->me_addr) {
212 if (!rs->status) {
213 cl->state = MEI_FILE_CONNECTED;
214 cl->status = 0;
215
216 } else {
217 cl->state = MEI_FILE_DISCONNECTED;
218 cl->status = -ENODEV;
219 }
220 cl->timer_count = 0;
221
222 return true;
223 }
224 return false;
225}
226
227/**
228 * mei_client_connect_response - connects to response irq routine
229 *
230 * @dev: the device structure
231 * @rs: connect response bus message
232 */
233static void mei_client_connect_response(struct mei_device *dev,
234 struct hbm_client_connect_response *rs)
235{
236
237 struct mei_cl *cl;
fb601adb 238 struct mei_cl_cb *pos = NULL, *next = NULL;
fb7d879f
OW
239
240 dev_dbg(&dev->pdev->dev,
241 "connect_response:\n"
242 "ME Client = %d\n"
243 "Host Client = %d\n"
244 "Status = %d\n",
245 rs->me_addr,
246 rs->host_addr,
247 rs->status);
248
249 /* if WD or iamthif client treat specially */
250
251 if (is_treat_specially_client(&(dev->wd_cl), rs)) {
fb7d879f 252 dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
70cd5337 253 mei_watchdog_register(dev);
9ce178e5 254
fb7d879f
OW
255 return;
256 }
257
258 if (is_treat_specially_client(&(dev->iamthif_cl), rs)) {
259 dev->iamthif_state = MEI_IAMTHIF_IDLE;
260 return;
261 }
fb601adb 262 list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
b7cd2d9f 263
db3ed431 264 cl = pos->cl;
b7cd2d9f 265 if (!cl) {
fb601adb 266 list_del(&pos->list);
b7cd2d9f
TW
267 return;
268 }
4b8960b4 269 if (pos->fop_type == MEI_FOP_IOCTL) {
b7cd2d9f 270 if (is_treat_specially_client(cl, rs)) {
fb601adb 271 list_del(&pos->list);
b7cd2d9f
TW
272 cl->status = 0;
273 cl->timer_count = 0;
274 break;
fb7d879f
OW
275 }
276 }
277 }
278}
279
280/**
281 * mei_client_disconnect_response - disconnects from response irq routine
282 *
283 * @dev: the device structure
284 * @rs: disconnect response bus message
285 */
286static void mei_client_disconnect_response(struct mei_device *dev,
287 struct hbm_client_connect_response *rs)
288{
289 struct mei_cl *cl;
fb601adb 290 struct mei_cl_cb *pos = NULL, *next = NULL;
fb7d879f
OW
291
292 dev_dbg(&dev->pdev->dev,
293 "disconnect_response:\n"
294 "ME Client = %d\n"
295 "Host Client = %d\n"
296 "Status = %d\n",
297 rs->me_addr,
298 rs->host_addr,
299 rs->status);
300
fb601adb 301 list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
db3ed431 302 cl = pos->cl;
fb7d879f 303
b7cd2d9f 304 if (!cl) {
fb601adb 305 list_del(&pos->list);
b7cd2d9f
TW
306 return;
307 }
fb7d879f 308
b7cd2d9f
TW
309 dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
310 if (cl->host_client_id == rs->host_addr &&
311 cl->me_client_id == rs->me_addr) {
fb7d879f 312
fb601adb 313 list_del(&pos->list);
b7cd2d9f
TW
314 if (!rs->status)
315 cl->state = MEI_FILE_DISCONNECTED;
fb7d879f 316
b7cd2d9f
TW
317 cl->status = 0;
318 cl->timer_count = 0;
319 break;
fb7d879f
OW
320 }
321 }
322}
323
324/**
325 * same_flow_addr - tells if they have the same address.
326 *
327 * @file: private data of the file object.
328 * @flow: flow control.
329 *
330 * returns !=0, same; 0,not.
331 */
332static int same_flow_addr(struct mei_cl *cl, struct hbm_flow_control *flow)
333{
334 return (cl->host_client_id == flow->host_addr &&
335 cl->me_client_id == flow->me_addr);
336}
337
338/**
339 * add_single_flow_creds - adds single buffer credentials.
340 *
341 * @file: private data ot the file object.
342 * @flow: flow control.
343 */
344static void add_single_flow_creds(struct mei_device *dev,
345 struct hbm_flow_control *flow)
346{
347 struct mei_me_client *client;
348 int i;
349
cf9673da 350 for (i = 0; i < dev->me_clients_num; i++) {
fb7d879f
OW
351 client = &dev->me_clients[i];
352 if (client && flow->me_addr == client->client_id) {
353 if (client->props.single_recv_buf) {
354 client->mei_flow_ctrl_creds++;
355 dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
356 flow->me_addr);
357 dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
358 client->mei_flow_ctrl_creds);
359 } else {
360 BUG(); /* error in flow control */
361 }
362 }
363 }
364}
365
366/**
367 * mei_client_flow_control_response - flow control response irq routine
368 *
369 * @dev: the device structure
370 * @flow_control: flow control response bus message
371 */
372static void mei_client_flow_control_response(struct mei_device *dev,
373 struct hbm_flow_control *flow_control)
374{
375 struct mei_cl *cl_pos = NULL;
376 struct mei_cl *cl_next = NULL;
377
378 if (!flow_control->host_addr) {
379 /* single receive buffer */
380 add_single_flow_creds(dev, flow_control);
381 } else {
382 /* normal connection */
383 list_for_each_entry_safe(cl_pos, cl_next,
384 &dev->file_list, link) {
385 dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in file_list\n");
386
387 dev_dbg(&dev->pdev->dev, "cl of host client %d ME client %d.\n",
388 cl_pos->host_client_id,
389 cl_pos->me_client_id);
390 dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
391 flow_control->host_addr,
392 flow_control->me_addr);
393 if (same_flow_addr(cl_pos, flow_control)) {
394 dev_dbg(&dev->pdev->dev, "recv ctrl msg for host %d ME %d.\n",
395 flow_control->host_addr,
396 flow_control->me_addr);
397 cl_pos->mei_flow_ctrl_creds++;
398 dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
399 cl_pos->mei_flow_ctrl_creds);
400 break;
401 }
402 }
403 }
404}
405
406/**
407 * same_disconn_addr - tells if they have the same address
408 *
409 * @file: private data of the file object.
410 * @disconn: disconnection request.
411 *
412 * returns !=0, same; 0,not.
413 */
414static int same_disconn_addr(struct mei_cl *cl,
aeba4a06 415 struct hbm_client_connect_request *req)
fb7d879f 416{
aeba4a06
TW
417 return (cl->host_client_id == req->host_addr &&
418 cl->me_client_id == req->me_addr);
fb7d879f
OW
419}
420
421/**
422 * mei_client_disconnect_request - disconnects from request irq routine
423 *
424 * @dev: the device structure.
425 * @disconnect_req: disconnect request bus message.
426 */
427static void mei_client_disconnect_request(struct mei_device *dev,
aeba4a06 428 struct hbm_client_connect_request *disconnect_req)
fb7d879f 429{
fb7d879f 430 struct hbm_client_connect_response *disconnect_res;
5bd64714
TW
431 struct mei_cl *pos, *next;
432 const size_t len = sizeof(struct hbm_client_connect_response);
fb7d879f 433
5bd64714
TW
434 list_for_each_entry_safe(pos, next, &dev->file_list, link) {
435 if (same_disconn_addr(pos, disconnect_req)) {
fb7d879f
OW
436 dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
437 disconnect_req->host_addr,
438 disconnect_req->me_addr);
5bd64714
TW
439 pos->state = MEI_FILE_DISCONNECTED;
440 pos->timer_count = 0;
441 if (pos == &dev->wd_cl)
eb9af0ac 442 dev->wd_pending = false;
5bd64714 443 else if (pos == &dev->iamthif_cl)
fb7d879f
OW
444 dev->iamthif_timer = 0;
445
446 /* prepare disconnect response */
5fb54fb4 447 (void)mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len);
fb7d879f
OW
448 disconnect_res =
449 (struct hbm_client_connect_response *)
5fb54fb4 450 &dev->wr_ext_msg.data;
1ca7e782 451 disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD;
5bd64714
TW
452 disconnect_res->host_addr = pos->host_client_id;
453 disconnect_res->me_addr = pos->me_client_id;
fb7d879f 454 disconnect_res->status = 0;
fb7d879f
OW
455 break;
456 }
457 }
458}
459
fb7d879f
OW
460/**
461 * mei_irq_thread_read_bus_message - bottom half read routine after ISR to
462 * handle the read bus message cmd processing.
463 *
464 * @dev: the device structure
465 * @mei_hdr: header of bus message
466 */
467static void mei_irq_thread_read_bus_message(struct mei_device *dev,
438763f3 468 struct mei_msg_hdr *hdr)
fb7d879f
OW
469{
470 struct mei_bus_message *mei_msg;
c1174c0e 471 struct mei_me_client *me_client;
fb7d879f
OW
472 struct hbm_host_version_response *version_res;
473 struct hbm_client_connect_response *connect_res;
474 struct hbm_client_connect_response *disconnect_res;
aeba4a06 475 struct hbm_client_connect_request *disconnect_req;
fb7d879f
OW
476 struct hbm_flow_control *flow_control;
477 struct hbm_props_response *props_res;
478 struct hbm_host_enum_response *enum_res;
5bd64714 479 struct hbm_host_stop_request *stop_req;
fb7d879f
OW
480
481 /* read the message to our buffer */
438763f3
TW
482 BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
483 mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
edf1eed4 484 mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
fb7d879f 485
1ca7e782 486 switch (mei_msg->hbm_cmd) {
fb7d879f
OW
487 case HOST_START_RES_CMD:
488 version_res = (struct hbm_host_version_response *) mei_msg;
489 if (version_res->host_version_supported) {
490 dev->version.major_version = HBM_MAJOR_VERSION;
491 dev->version.minor_version = HBM_MINOR_VERSION;
b210d750 492 if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
fb7d879f
OW
493 dev->init_clients_state == MEI_START_MESSAGE) {
494 dev->init_clients_timer = 0;
c95efb74 495 mei_host_enum_clients_message(dev);
fb7d879f 496 } else {
eb9af0ac 497 dev->recvd_msg = false;
fb7d879f
OW
498 dev_dbg(&dev->pdev->dev, "IMEI reset due to received host start response bus message.\n");
499 mei_reset(dev, 1);
500 return;
501 }
502 } else {
5bd64714
TW
503 u32 *buf = dev->wr_msg_buf;
504 const size_t len = sizeof(struct hbm_host_stop_request);
505
fb7d879f 506 dev->version = version_res->me_max_version;
5bd64714 507
fb7d879f 508 /* send stop message */
438763f3 509 hdr = mei_hbm_hdr(&buf[0], len);
5bd64714
TW
510 stop_req = (struct hbm_host_stop_request *)&buf[1];
511 memset(stop_req, 0, len);
512 stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
513 stop_req->reason = DRIVER_STOP_REQUEST;
514
438763f3 515 mei_write_message(dev, hdr, (unsigned char *)stop_req);
fb7d879f
OW
516 dev_dbg(&dev->pdev->dev, "version mismatch.\n");
517 return;
518 }
519
eb9af0ac 520 dev->recvd_msg = true;
fb7d879f
OW
521 dev_dbg(&dev->pdev->dev, "host start response message received.\n");
522 break;
523
524 case CLIENT_CONNECT_RES_CMD:
5bd64714 525 connect_res = (struct hbm_client_connect_response *) mei_msg;
fb7d879f
OW
526 mei_client_connect_response(dev, connect_res);
527 dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
528 wake_up(&dev->wait_recvd_msg);
529 break;
530
531 case CLIENT_DISCONNECT_RES_CMD:
5bd64714 532 disconnect_res = (struct hbm_client_connect_response *) mei_msg;
441ab50f 533 mei_client_disconnect_response(dev, disconnect_res);
fb7d879f
OW
534 dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
535 wake_up(&dev->wait_recvd_msg);
536 break;
537
538 case MEI_FLOW_CONTROL_CMD:
539 flow_control = (struct hbm_flow_control *) mei_msg;
540 mei_client_flow_control_response(dev, flow_control);
541 dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
542 break;
543
544 case HOST_CLIENT_PROPERTIES_RES_CMD:
545 props_res = (struct hbm_props_response *)mei_msg;
c1174c0e
SO
546 me_client = &dev->me_clients[dev->me_client_presentation_num];
547
fb7d879f
OW
548 if (props_res->status || !dev->me_clients) {
549 dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
550 mei_reset(dev, 1);
551 return;
552 }
fb7d879f 553
c1174c0e
SO
554 if (me_client->client_id != props_res->address) {
555 dev_err(&dev->pdev->dev,
556 "Host client properties reply mismatch\n");
557 mei_reset(dev, 1);
fb7d879f 558
c1174c0e
SO
559 return;
560 }
abc51b6d 561
c1174c0e
SO
562 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
563 dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) {
564 dev_err(&dev->pdev->dev,
565 "Unexpected client properties reply\n");
fb7d879f 566 mei_reset(dev, 1);
c1174c0e 567
fb7d879f
OW
568 return;
569 }
c1174c0e
SO
570
571 me_client->props = props_res->client_properties;
572 dev->me_client_index++;
573 dev->me_client_presentation_num++;
574
575 mei_host_client_enumerate(dev);
576
fb7d879f
OW
577 break;
578
579 case HOST_ENUM_RES_CMD:
580 enum_res = (struct hbm_host_enum_response *) mei_msg;
581 memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
b210d750 582 if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
fb7d879f
OW
583 dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
584 dev->init_clients_timer = 0;
585 dev->me_client_presentation_num = 0;
586 dev->me_client_index = 0;
c95efb74 587 mei_allocate_me_clients_storage(dev);
fb7d879f
OW
588 dev->init_clients_state =
589 MEI_CLIENT_PROPERTIES_MESSAGE;
c1174c0e
SO
590
591 mei_host_client_enumerate(dev);
fb7d879f
OW
592 } else {
593 dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
594 mei_reset(dev, 1);
595 return;
596 }
597 break;
598
599 case HOST_STOP_RES_CMD:
b210d750 600 dev->dev_state = MEI_DEV_DISABLED;
fb7d879f
OW
601 dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
602 mei_reset(dev, 1);
603 break;
604
605 case CLIENT_DISCONNECT_REQ_CMD:
606 /* search for client */
aeba4a06 607 disconnect_req = (struct hbm_client_connect_request *)mei_msg;
fb7d879f
OW
608 mei_client_disconnect_request(dev, disconnect_req);
609 break;
610
611 case ME_STOP_REQ_CMD:
5bd64714
TW
612 {
613 /* prepare stop request: sent in next interrupt event */
614
5bd64714
TW
615 const size_t len = sizeof(struct hbm_host_stop_request);
616
438763f3 617 hdr = mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len);
5fb54fb4 618 stop_req = (struct hbm_host_stop_request *)&dev->wr_ext_msg.data;
5bd64714
TW
619 memset(stop_req, 0, len);
620 stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
621 stop_req->reason = DRIVER_STOP_REQUEST;
fb7d879f 622 break;
5bd64714 623 }
fb7d879f
OW
624 default:
625 BUG();
626 break;
627
628 }
629}
630
631
632/**
633 * _mei_hb_read - processes read related operation.
634 *
635 * @dev: the device structure.
636 * @slots: free slots.
637 * @cb_pos: callback block.
638 * @cl: private data of the file object.
639 * @cmpl_list: complete list.
640 *
641 * returns 0, OK; otherwise, error.
642 */
643static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots,
644 struct mei_cl_cb *cb_pos,
645 struct mei_cl *cl,
fb601adb 646 struct mei_cl_cb *cmpl_list)
fb7d879f 647{
1e69d64a 648 if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) +
fb7d879f 649 sizeof(struct hbm_flow_control))) {
fb7d879f 650 /* return the cancel routine */
fb601adb 651 list_del(&cb_pos->list);
fb7d879f
OW
652 return -EBADMSG;
653 }
654
7bdf72d3
TW
655 *slots -= mei_data2slots(sizeof(struct hbm_flow_control));
656
1ccb7b62
TW
657 if (mei_send_flow_control(dev, cl)) {
658 cl->status = -ENODEV;
ebb108ef 659 cb_pos->buf_idx = 0;
fb601adb 660 list_move_tail(&cb_pos->list, &cmpl_list->list);
1ccb7b62
TW
661 return -ENODEV;
662 }
fb601adb 663 list_move_tail(&cb_pos->list, &dev->read_list.list);
1ccb7b62 664
fb7d879f
OW
665 return 0;
666}
667
668
669/**
670 * _mei_irq_thread_ioctl - processes ioctl related operation.
671 *
672 * @dev: the device structure.
673 * @slots: free slots.
674 * @cb_pos: callback block.
675 * @cl: private data of the file object.
676 * @cmpl_list: complete list.
677 *
678 * returns 0, OK; otherwise, error.
679 */
680static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots,
681 struct mei_cl_cb *cb_pos,
682 struct mei_cl *cl,
fb601adb 683 struct mei_cl_cb *cmpl_list)
fb7d879f 684{
b45f3ccf 685 if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) +
fb7d879f 686 sizeof(struct hbm_client_connect_request))) {
fb7d879f 687 /* return the cancel routine */
fb601adb 688 list_del(&cb_pos->list);
fb7d879f
OW
689 return -EBADMSG;
690 }
691
b45f3ccf
TW
692 cl->state = MEI_FILE_CONNECTING;
693 *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request));
694 if (mei_connect(dev, cl)) {
695 cl->status = -ENODEV;
ebb108ef 696 cb_pos->buf_idx = 0;
fb601adb 697 list_del(&cb_pos->list);
b45f3ccf
TW
698 return -ENODEV;
699 } else {
fb601adb 700 list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list);
b45f3ccf
TW
701 cl->timer_count = MEI_CONNECT_TIMEOUT;
702 }
fb7d879f
OW
703 return 0;
704}
705
706/**
ea3b5fb7 707 * mei_irq_thread_write_complete - write messages to device.
fb7d879f
OW
708 *
709 * @dev: the device structure.
710 * @slots: free slots.
ea3b5fb7 711 * @cb: callback block.
fb7d879f
OW
712 * @cmpl_list: complete list.
713 *
714 * returns 0, OK; otherwise, error.
715 */
ea3b5fb7
TW
716static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots,
717 struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list)
fb7d879f
OW
718{
719 struct mei_msg_hdr *mei_hdr;
ea3b5fb7
TW
720 struct mei_cl *cl = cb->cl;
721 size_t len = cb->request_buffer.size - cb->buf_idx;
722 size_t msg_slots = mei_data2slots(len);
723
724 mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
725 mei_hdr->host_addr = cl->host_client_id;
726 mei_hdr->me_addr = cl->me_client_id;
727 mei_hdr->reserved = 0;
fb7d879f 728
ea3b5fb7
TW
729 if (*slots >= msg_slots) {
730 mei_hdr->length = len;
fb7d879f 731 mei_hdr->msg_complete = 1;
ea3b5fb7 732 /* Split the message only if we can write the whole host buffer */
24aadc80 733 } else if (*slots == dev->hbuf_depth) {
ea3b5fb7
TW
734 msg_slots = *slots;
735 len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
736 mei_hdr->length = len;
fb7d879f 737 mei_hdr->msg_complete = 0;
fb7d879f 738 } else {
ea3b5fb7
TW
739 /* wait for next time the host buffer is empty */
740 return 0;
fb7d879f
OW
741 }
742
ea3b5fb7
TW
743 dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n",
744 cb->request_buffer.size, cb->buf_idx);
15d4acc5 745 dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
ea3b5fb7
TW
746
747 *slots -= msg_slots;
748 if (mei_write_message(dev, mei_hdr,
438763f3 749 cb->request_buffer.data + cb->buf_idx)) {
ea3b5fb7
TW
750 cl->status = -ENODEV;
751 list_move_tail(&cb->list, &cmpl_list->list);
752 return -ENODEV;
753 }
754
755 if (mei_flow_ctrl_reduce(dev, cl))
756 return -ENODEV;
757
758 cl->status = 0;
759 cb->buf_idx += mei_hdr->length;
760 if (mei_hdr->msg_complete)
761 list_move_tail(&cb->list, &dev->write_waiting_list.list);
762
fb7d879f
OW
763 return 0;
764}
765
fb7d879f
OW
766/**
767 * mei_irq_thread_read_handler - bottom half read routine after ISR to
768 * handle the read processing.
769 *
770 * @cmpl_list: An instance of our list structure
771 * @dev: the device structure
772 * @slots: slots to read.
773 *
774 * returns 0 on success, <0 on failure.
775 */
fb601adb 776static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list,
fb7d879f
OW
777 struct mei_device *dev,
778 s32 *slots)
779{
780 struct mei_msg_hdr *mei_hdr;
781 struct mei_cl *cl_pos = NULL;
782 struct mei_cl *cl_next = NULL;
783 int ret = 0;
784
785 if (!dev->rd_msg_hdr) {
786 dev->rd_msg_hdr = mei_mecbrw_read(dev);
787 dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
788 (*slots)--;
789 dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
790 }
791 mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr;
15d4acc5 792 dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
fb7d879f
OW
793
794 if (mei_hdr->reserved || !dev->rd_msg_hdr) {
795 dev_dbg(&dev->pdev->dev, "corrupted message header.\n");
796 ret = -EBADMSG;
797 goto end;
798 }
799
800 if (mei_hdr->host_addr || mei_hdr->me_addr) {
801 list_for_each_entry_safe(cl_pos, cl_next,
802 &dev->file_list, link) {
803 dev_dbg(&dev->pdev->dev,
804 "list_for_each_entry_safe read host"
805 " client = %d, ME client = %d\n",
806 cl_pos->host_client_id,
807 cl_pos->me_client_id);
808 if (cl_pos->host_client_id == mei_hdr->host_addr &&
809 cl_pos->me_client_id == mei_hdr->me_addr)
810 break;
811 }
812
813 if (&cl_pos->link == &dev->file_list) {
814 dev_dbg(&dev->pdev->dev, "corrupted message header\n");
815 ret = -EBADMSG;
816 goto end;
817 }
818 }
819 if (((*slots) * sizeof(u32)) < mei_hdr->length) {
820 dev_dbg(&dev->pdev->dev,
821 "we can't read the message slots =%08x.\n",
822 *slots);
823 /* we can't read the message */
824 ret = -ERANGE;
825 goto end;
826 }
827
828 /* decide where to read the message too */
829 if (!mei_hdr->host_addr) {
830 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n");
831 mei_irq_thread_read_bus_message(dev, mei_hdr);
832 dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n");
833 } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
834 (MEI_FILE_CONNECTED == dev->iamthif_cl.state) &&
835 (dev->iamthif_state == MEI_IAMTHIF_READING)) {
836 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
15d4acc5
TW
837
838 dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
19838fb8
TW
839
840 ret = mei_amthif_irq_read_message(cmpl_list, dev, mei_hdr);
fb7d879f
OW
841 if (ret)
842 goto end;
fb7d879f
OW
843 } else {
844 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n");
845 ret = mei_irq_thread_read_client_message(cmpl_list,
846 dev, mei_hdr);
847 if (ret)
848 goto end;
849
850 }
851
852 /* reset the number of slots and header */
853 *slots = mei_count_full_read_slots(dev);
854 dev->rd_msg_hdr = 0;
855
856 if (*slots == -EOVERFLOW) {
857 /* overflow - reset */
858 dev_dbg(&dev->pdev->dev, "resetting due to slots overflow.\n");
859 /* set the event since message has been read */
860 ret = -ERANGE;
861 goto end;
862 }
863end:
864 return ret;
865}
866
867
868/**
869 * mei_irq_thread_write_handler - bottom half write routine after
870 * ISR to handle the write processing.
871 *
fb7d879f 872 * @dev: the device structure
9a84d616 873 * @cmpl_list: An instance of our list structure
fb7d879f
OW
874 *
875 * returns 0 on success, <0 on failure.
876 */
9a84d616
TW
877static int mei_irq_thread_write_handler(struct mei_device *dev,
878 struct mei_cl_cb *cmpl_list)
fb7d879f
OW
879{
880
881 struct mei_cl *cl;
b7cd2d9f 882 struct mei_cl_cb *pos = NULL, *next = NULL;
fb601adb 883 struct mei_cl_cb *list;
9a84d616 884 s32 slots;
fb7d879f
OW
885 int ret;
886
726917f0 887 if (!mei_hbuf_is_empty(dev)) {
fb7d879f
OW
888 dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
889 return 0;
890 }
9a84d616
TW
891 slots = mei_hbuf_empty_slots(dev);
892 if (slots <= 0)
7d5e0e59
TW
893 return -EMSGSIZE;
894
fb7d879f
OW
895 /* complete all waiting for write CB */
896 dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");
897
898 list = &dev->write_waiting_list;
fb601adb 899 list_for_each_entry_safe(pos, next, &list->list, list) {
db3ed431 900 cl = pos->cl;
b7cd2d9f
TW
901 if (cl == NULL)
902 continue;
903
904 cl->status = 0;
fb601adb 905 list_del(&pos->list);
b7cd2d9f 906 if (MEI_WRITING == cl->writing_state &&
4b8960b4
TW
907 pos->fop_type == MEI_FOP_WRITE &&
908 cl != &dev->iamthif_cl) {
483136ea 909 dev_dbg(&dev->pdev->dev, "MEI WRITE COMPLETE\n");
b7cd2d9f 910 cl->writing_state = MEI_WRITE_COMPLETE;
fb601adb 911 list_add_tail(&pos->list, &cmpl_list->list);
b7cd2d9f
TW
912 }
913 if (cl == &dev->iamthif_cl) {
914 dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n");
915 if (dev->iamthif_flow_control_pending) {
9a84d616 916 ret = mei_amthif_irq_read(dev, &slots);
b7cd2d9f
TW
917 if (ret)
918 return ret;
fb7d879f 919 }
fb7d879f
OW
920 }
921 }
922
c216fdeb
TW
923 if (dev->wd_state == MEI_WD_STOPPING) {
924 dev->wd_state = MEI_WD_IDLE;
fb7d879f 925 wake_up_interruptible(&dev->wait_stop_wd);
fb7d879f
OW
926 }
927
5fb54fb4
TW
928 if (dev->wr_ext_msg.hdr.length) {
929 mei_write_message(dev, &dev->wr_ext_msg.hdr,
438763f3 930 dev->wr_ext_msg.data);
9a84d616 931 slots -= mei_data2slots(dev->wr_ext_msg.hdr.length);
5fb54fb4 932 dev->wr_ext_msg.hdr.length = 0;
fb7d879f 933 }
b210d750 934 if (dev->dev_state == MEI_DEV_ENABLED) {
fb7d879f 935 if (dev->wd_pending &&
483136ea 936 mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
fb7d879f
OW
937 if (mei_wd_send(dev))
938 dev_dbg(&dev->pdev->dev, "wd send failed.\n");
483136ea
TW
939 else if (mei_flow_ctrl_reduce(dev, &dev->wd_cl))
940 return -ENODEV;
fb7d879f 941
eb9af0ac 942 dev->wd_pending = false;
fb7d879f 943
c216fdeb 944 if (dev->wd_state == MEI_WD_RUNNING)
9a84d616 945 slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
d242a0af 946 else
9a84d616 947 slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE);
fb7d879f
OW
948 }
949 }
fb7d879f
OW
950
951 /* complete control write list CB */
c8372094 952 dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
fb601adb 953 list_for_each_entry_safe(pos, next, &dev->ctrl_wr_list.list, list) {
db3ed431 954 cl = pos->cl;
c8372094 955 if (!cl) {
fb601adb 956 list_del(&pos->list);
c8372094
TW
957 return -ENODEV;
958 }
4b8960b4
TW
959 switch (pos->fop_type) {
960 case MEI_FOP_CLOSE:
c8372094 961 /* send disconnect message */
9a84d616
TW
962 ret = _mei_irq_thread_close(dev, &slots, pos,
963 cl, cmpl_list);
c8372094
TW
964 if (ret)
965 return ret;
fb7d879f 966
c8372094 967 break;
4b8960b4 968 case MEI_FOP_READ:
c8372094 969 /* send flow control message */
9a84d616
TW
970 ret = _mei_irq_thread_read(dev, &slots, pos,
971 cl, cmpl_list);
c8372094
TW
972 if (ret)
973 return ret;
fb7d879f 974
c8372094 975 break;
4b8960b4 976 case MEI_FOP_IOCTL:
c8372094 977 /* connect message */
e8cd29d8 978 if (mei_other_client_is_connecting(dev, cl))
c8372094 979 continue;
9a84d616
TW
980 ret = _mei_irq_thread_ioctl(dev, &slots, pos,
981 cl, cmpl_list);
c8372094
TW
982 if (ret)
983 return ret;
fb7d879f 984
c8372094 985 break;
fb7d879f 986
c8372094
TW
987 default:
988 BUG();
fb7d879f 989 }
c8372094 990
fb7d879f
OW
991 }
992 /* complete write list CB */
b7cd2d9f 993 dev_dbg(&dev->pdev->dev, "complete write list cb.\n");
fb601adb 994 list_for_each_entry_safe(pos, next, &dev->write_list.list, list) {
db3ed431 995 cl = pos->cl;
b7cd2d9f
TW
996 if (cl == NULL)
997 continue;
be9d87a7
TW
998 if (mei_flow_ctrl_creds(dev, cl) <= 0) {
999 dev_dbg(&dev->pdev->dev,
1000 "No flow control credentials for client %d, not sending.\n",
1001 cl->host_client_id);
1002 continue;
1003 }
b7cd2d9f 1004
be9d87a7 1005 if (cl == &dev->iamthif_cl)
9a84d616 1006 ret = mei_amthif_irq_write_complete(dev, &slots,
24c656e5 1007 pos, cmpl_list);
be9d87a7
TW
1008 else
1009 ret = mei_irq_thread_write_complete(dev, &slots, pos,
1010 cmpl_list);
1011 if (ret)
1012 return ret;
b7cd2d9f 1013
fb7d879f
OW
1014 }
1015 return 0;
1016}
1017
1018
1019
1020/**
1021 * mei_timer - timer function.
1022 *
1023 * @work: pointer to the work_struct structure
1024 *
1025 * NOTE: This function is called by timer interrupt work
1026 */
a61c6530 1027void mei_timer(struct work_struct *work)
fb7d879f
OW
1028{
1029 unsigned long timeout;
1030 struct mei_cl *cl_pos = NULL;
1031 struct mei_cl *cl_next = NULL;
fb7d879f
OW
1032 struct mei_cl_cb *cb_pos = NULL;
1033 struct mei_cl_cb *cb_next = NULL;
1034
1035 struct mei_device *dev = container_of(work,
a61c6530 1036 struct mei_device, timer_work.work);
fb7d879f
OW
1037
1038
1039 mutex_lock(&dev->device_lock);
b210d750
TW
1040 if (dev->dev_state != MEI_DEV_ENABLED) {
1041 if (dev->dev_state == MEI_DEV_INIT_CLIENTS) {
fb7d879f
OW
1042 if (dev->init_clients_timer) {
1043 if (--dev->init_clients_timer == 0) {
1044 dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
1045 dev->init_clients_state);
1046 mei_reset(dev, 1);
1047 }
1048 }
1049 }
1050 goto out;
1051 }
1052 /*** connect/disconnect timeouts ***/
1053 list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
1054 if (cl_pos->timer_count) {
1055 if (--cl_pos->timer_count == 0) {
1056 dev_dbg(&dev->pdev->dev, "HECI reset due to connect/disconnect timeout.\n");
1057 mei_reset(dev, 1);
1058 goto out;
1059 }
1060 }
1061 }
1062
fb7d879f
OW
1063 if (dev->iamthif_stall_timer) {
1064 if (--dev->iamthif_stall_timer == 0) {
32de21f7 1065 dev_dbg(&dev->pdev->dev, "resetting because of hang to amthi.\n");
fb7d879f
OW
1066 mei_reset(dev, 1);
1067 dev->iamthif_msg_buf_size = 0;
1068 dev->iamthif_msg_buf_index = 0;
eb9af0ac
TW
1069 dev->iamthif_canceled = false;
1070 dev->iamthif_ioctl = true;
fb7d879f
OW
1071 dev->iamthif_state = MEI_IAMTHIF_IDLE;
1072 dev->iamthif_timer = 0;
1073
601a1efa
TW
1074 mei_io_cb_free(dev->iamthif_current_cb);
1075 dev->iamthif_current_cb = NULL;
fb7d879f
OW
1076
1077 dev->iamthif_file_object = NULL;
19838fb8 1078 mei_amthif_run_next_cmd(dev);
fb7d879f
OW
1079 }
1080 }
1081
1082 if (dev->iamthif_timer) {
1083
1084 timeout = dev->iamthif_timer +
3870c320 1085 mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
fb7d879f
OW
1086
1087 dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
1088 dev->iamthif_timer);
1089 dev_dbg(&dev->pdev->dev, "timeout = %ld\n", timeout);
1090 dev_dbg(&dev->pdev->dev, "jiffies = %ld\n", jiffies);
1091 if (time_after(jiffies, timeout)) {
1092 /*
1093 * User didn't read the AMTHI data on time (15sec)
1094 * freeing AMTHI for other requests
1095 */
1096
1097 dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n");
1098
e773efc4
TW
1099 list_for_each_entry_safe(cb_pos, cb_next,
1100 &dev->amthif_rd_complete_list.list, list) {
fb7d879f 1101
b7cd2d9f 1102 cl_pos = cb_pos->file_object->private_data;
fb7d879f 1103
b7cd2d9f
TW
1104 /* Finding the AMTHI entry. */
1105 if (cl_pos == &dev->iamthif_cl)
fb601adb 1106 list_del(&cb_pos->list);
fb7d879f 1107 }
601a1efa
TW
1108 mei_io_cb_free(dev->iamthif_current_cb);
1109 dev->iamthif_current_cb = NULL;
fb7d879f
OW
1110
1111 dev->iamthif_file_object->private_data = NULL;
1112 dev->iamthif_file_object = NULL;
fb7d879f 1113 dev->iamthif_timer = 0;
19838fb8 1114 mei_amthif_run_next_cmd(dev);
fb7d879f
OW
1115
1116 }
1117 }
1118out:
441ab50f
TW
1119 schedule_delayed_work(&dev->timer_work, 2 * HZ);
1120 mutex_unlock(&dev->device_lock);
fb7d879f
OW
1121}
1122
1123/**
1124 * mei_interrupt_thread_handler - function called after ISR to handle the interrupt
1125 * processing.
1126 *
1127 * @irq: The irq number
1128 * @dev_id: pointer to the device structure
1129 *
1130 * returns irqreturn_t
1131 *
1132 */
1133irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
1134{
1135 struct mei_device *dev = (struct mei_device *) dev_id;
fb601adb 1136 struct mei_cl_cb complete_list;
fb7d879f
OW
1137 struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
1138 struct mei_cl *cl;
1139 s32 slots;
1140 int rets;
1141 bool bus_message_received;
1142
1143
1144 dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
1145 /* initialize our complete list */
1146 mutex_lock(&dev->device_lock);
0288c7c9 1147 mei_io_list_init(&complete_list);
fb7d879f 1148 dev->host_hw_state = mei_hcsr_read(dev);
4f61a7ad
TW
1149
1150 /* Ack the interrupt here
5f9092f3 1151 * In case of MSI we don't go through the quick handler */
4f61a7ad
TW
1152 if (pci_dev_msi_enabled(dev->pdev))
1153 mei_reg_write(dev, H_CSR, dev->host_hw_state);
1154
fb7d879f
OW
1155 dev->me_hw_state = mei_mecsr_read(dev);
1156
1157 /* check if ME wants a reset */
1158 if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
b210d750
TW
1159 dev->dev_state != MEI_DEV_RESETING &&
1160 dev->dev_state != MEI_DEV_INITIALIZING) {
fb7d879f
OW
1161 dev_dbg(&dev->pdev->dev, "FW not ready.\n");
1162 mei_reset(dev, 1);
1163 mutex_unlock(&dev->device_lock);
1164 return IRQ_HANDLED;
1165 }
1166
1167 /* check if we need to start the dev */
1168 if ((dev->host_hw_state & H_RDY) == 0) {
1169 if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) {
1170 dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
1171 dev->host_hw_state |= (H_IE | H_IG | H_RDY);
1172 mei_hcsr_set(dev);
b210d750 1173 dev->dev_state = MEI_DEV_INIT_CLIENTS;
fb7d879f
OW
1174 dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
1175 /* link is established
1176 * start sending messages.
1177 */
c95efb74 1178 mei_host_start_message(dev);
fb7d879f
OW
1179 mutex_unlock(&dev->device_lock);
1180 return IRQ_HANDLED;
1181 } else {
1182 dev_dbg(&dev->pdev->dev, "FW not ready.\n");
1183 mutex_unlock(&dev->device_lock);
1184 return IRQ_HANDLED;
1185 }
1186 }
5f9092f3 1187 /* check slots available for reading */
fb7d879f 1188 slots = mei_count_full_read_slots(dev);
5fb54fb4
TW
1189 while (slots > 0) {
1190 /* we have urgent data to send so break the read */
1191 if (dev->wr_ext_msg.hdr.length)
1192 break;
1193 dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots);
fb7d879f
OW
1194 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n");
1195 rets = mei_irq_thread_read_handler(&complete_list, dev, &slots);
1196 if (rets)
1197 goto end;
1198 }
9a84d616 1199 rets = mei_irq_thread_write_handler(dev, &complete_list);
fb7d879f
OW
1200end:
1201 dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
1202 dev->host_hw_state = mei_hcsr_read(dev);
726917f0 1203 dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev);
fb7d879f
OW
1204
1205 bus_message_received = false;
1206 if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
1207 dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
1208 bus_message_received = true;
1209 }
1210 mutex_unlock(&dev->device_lock);
1211 if (bus_message_received) {
1212 dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
1213 wake_up_interruptible(&dev->wait_recvd_msg);
1214 bus_message_received = false;
1215 }
fb601adb 1216 if (list_empty(&complete_list.list))
fb7d879f
OW
1217 return IRQ_HANDLED;
1218
1219
fb601adb 1220 list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) {
db3ed431 1221 cl = cb_pos->cl;
fb601adb 1222 list_del(&cb_pos->list);
fb7d879f
OW
1223 if (cl) {
1224 if (cl != &dev->iamthif_cl) {
1225 dev_dbg(&dev->pdev->dev, "completing call back.\n");
1226 _mei_cmpl(cl, cb_pos);
1227 cb_pos = NULL;
1228 } else if (cl == &dev->iamthif_cl) {
19838fb8 1229 mei_amthif_complete(dev, cb_pos);
fb7d879f
OW
1230 }
1231 }
1232 }
1233 return IRQ_HANDLED;
1234}