mei: revamp hbm state machine
[deliverable/linux.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
40e0b67b 18#include <linux/export.h>
fb7d879f
OW
19#include <linux/pci.h>
20#include <linux/kthread.h>
21#include <linux/interrupt.h>
22#include <linux/fs.h>
23#include <linux/jiffies.h>
24
4f3afe1d 25#include <linux/mei.h>
47a73801
TW
26
27#include "mei_dev.h"
0edb23fc 28#include "hbm.h"
9dc64d6a 29#include "hw-me.h"
90e0b5f1 30#include "client.h"
fb7d879f
OW
31
32
fb7d879f 33/**
4c6e22b8 34 * mei_cl_complete_handler - processes completed operation for a client
fb7d879f
OW
35 *
36 * @cl: private data of the file object.
4c6e22b8 37 * @cb: callback block.
fb7d879f 38 */
4c6e22b8 39static void mei_cl_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb)
fb7d879f 40{
4c6e22b8
TW
41 if (cb->fop_type == MEI_FOP_WRITE) {
42 mei_io_cb_free(cb);
43 cb = NULL;
fb7d879f
OW
44 cl->writing_state = MEI_WRITE_COMPLETE;
45 if (waitqueue_active(&cl->tx_wait))
46 wake_up_interruptible(&cl->tx_wait);
47
4c6e22b8 48 } else if (cb->fop_type == MEI_FOP_READ &&
fb7d879f
OW
49 MEI_READING == cl->reading_state) {
50 cl->reading_state = MEI_READ_COMPLETE;
51 if (waitqueue_active(&cl->rx_wait))
52 wake_up_interruptible(&cl->rx_wait);
cf3baefb
SO
53 else
54 mei_cl_bus_rx_event(cl);
fb7d879f
OW
55
56 }
57}
58
4c6e22b8
TW
59/**
60 * mei_irq_compl_handler - dispatch complete handelers
61 * for the completed callbacks
62 *
63 * @dev - mei device
64 * @compl_list - list of completed cbs
65 */
66void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list)
67{
68 struct mei_cl_cb *cb, *next;
69 struct mei_cl *cl;
70
71 list_for_each_entry_safe(cb, next, &compl_list->list, list) {
72 cl = cb->cl;
73 list_del(&cb->list);
74 if (!cl)
75 continue;
76
77 dev_dbg(&dev->pdev->dev, "completing call back.\n");
78 if (cl == &dev->iamthif_cl)
79 mei_amthif_complete(dev, cb);
80 else
81 mei_cl_complete_handler(cl, cb);
82 }
83}
40e0b67b 84EXPORT_SYMBOL_GPL(mei_irq_compl_handler);
fb7d879f
OW
85/**
86 * _mei_irq_thread_state_ok - checks if mei header matches file private data
87 *
88 * @cl: private data of the file object
89 * @mei_hdr: header of mei client message
90 *
91 * returns !=0 if matches, 0 if no match.
92 */
93static int _mei_irq_thread_state_ok(struct mei_cl *cl,
94 struct mei_msg_hdr *mei_hdr)
95{
96 return (cl->host_client_id == mei_hdr->host_addr &&
97 cl->me_client_id == mei_hdr->me_addr &&
98 cl->state == MEI_FILE_CONNECTED &&
99 MEI_READ_COMPLETE != cl->reading_state);
100}
101
102/**
103 * mei_irq_thread_read_client_message - bottom half read routine after ISR to
104 * handle the read mei client message data processing.
105 *
106 * @complete_list: An instance of our list structure
107 * @dev: the device structure
108 * @mei_hdr: header of mei client message
109 *
110 * returns 0 on success, <0 on failure.
111 */
fb601adb 112static int mei_irq_thread_read_client_message(struct mei_cl_cb *complete_list,
fb7d879f
OW
113 struct mei_device *dev,
114 struct mei_msg_hdr *mei_hdr)
115{
116 struct mei_cl *cl;
117 struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
479bc59d 118 unsigned char *buffer = NULL;
fb7d879f
OW
119
120 dev_dbg(&dev->pdev->dev, "start client msg\n");
fb601adb 121 if (list_empty(&dev->read_list.list))
fb7d879f
OW
122 goto quit;
123
fb601adb 124 list_for_each_entry_safe(cb_pos, cb_next, &dev->read_list.list, list) {
db3ed431 125 cl = cb_pos->cl;
fb7d879f
OW
126 if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
127 cl->reading_state = MEI_READING;
ebb108ef 128 buffer = cb_pos->response_buffer.data + cb_pos->buf_idx;
fb7d879f
OW
129
130 if (cb_pos->response_buffer.size <
ebb108ef 131 mei_hdr->length + cb_pos->buf_idx) {
fb7d879f 132 dev_dbg(&dev->pdev->dev, "message overflow.\n");
fb601adb 133 list_del(&cb_pos->list);
fb7d879f
OW
134 return -ENOMEM;
135 }
136 if (buffer)
137 mei_read_slots(dev, buffer, mei_hdr->length);
138
ebb108ef 139 cb_pos->buf_idx += mei_hdr->length;
fb7d879f
OW
140 if (mei_hdr->msg_complete) {
141 cl->status = 0;
fb601adb 142 list_del(&cb_pos->list);
fb7d879f 143 dev_dbg(&dev->pdev->dev,
a4136b49 144 "completed read H cl = %d, ME cl = %d, length = %lu\n",
fb7d879f
OW
145 cl->host_client_id,
146 cl->me_client_id,
ebb108ef
TW
147 cb_pos->buf_idx);
148
fb601adb
TW
149 list_add_tail(&cb_pos->list,
150 &complete_list->list);
fb7d879f
OW
151 }
152
153 break;
154 }
155
156 }
157
158quit:
159 dev_dbg(&dev->pdev->dev, "message read\n");
160 if (!buffer) {
edf1eed4 161 mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
15d4acc5
TW
162 dev_dbg(&dev->pdev->dev, "discarding message " MEI_HDR_FMT "\n",
163 MEI_HDR_PRM(mei_hdr));
fb7d879f
OW
164 }
165
166 return 0;
167}
168
fb7d879f
OW
169/**
170 * _mei_irq_thread_close - processes close related operation.
171 *
172 * @dev: the device structure.
173 * @slots: free slots.
174 * @cb_pos: callback block.
175 * @cl: private data of the file object.
176 * @cmpl_list: complete list.
177 *
178 * returns 0, OK; otherwise, error.
179 */
180static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots,
181 struct mei_cl_cb *cb_pos,
182 struct mei_cl *cl,
fb601adb 183 struct mei_cl_cb *cmpl_list)
fb7d879f 184{
c8c8d080
TW
185 u32 msg_slots =
186 mei_data2slots(sizeof(struct hbm_client_connect_request));
fb7d879f 187
c8c8d080
TW
188 if (*slots < msg_slots)
189 return -EMSGSIZE;
190
191 *slots -= msg_slots;
b45f3ccf 192
8120e720 193 if (mei_hbm_cl_disconnect_req(dev, cl)) {
b45f3ccf 194 cl->status = 0;
ebb108ef 195 cb_pos->buf_idx = 0;
fb601adb 196 list_move_tail(&cb_pos->list, &cmpl_list->list);
c8c8d080 197 return -EIO;
fb7d879f
OW
198 }
199
c8c8d080
TW
200 cl->state = MEI_FILE_DISCONNECTING;
201 cl->status = 0;
202 cb_pos->buf_idx = 0;
203 list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list);
204 cl->timer_count = MEI_CONNECT_TIMEOUT;
205
fb7d879f
OW
206 return 0;
207}
208
fb7d879f
OW
209
210/**
211 * _mei_hb_read - processes read related operation.
212 *
213 * @dev: the device structure.
214 * @slots: free slots.
215 * @cb_pos: callback block.
216 * @cl: private data of the file object.
217 * @cmpl_list: complete list.
218 *
219 * returns 0, OK; otherwise, error.
220 */
221static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots,
222 struct mei_cl_cb *cb_pos,
223 struct mei_cl *cl,
fb601adb 224 struct mei_cl_cb *cmpl_list)
fb7d879f 225{
c8c8d080
TW
226 u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
227
228 if (*slots < msg_slots) {
fb7d879f 229 /* return the cancel routine */
fb601adb 230 list_del(&cb_pos->list);
c8c8d080 231 return -EMSGSIZE;
fb7d879f
OW
232 }
233
c8c8d080 234 *slots -= msg_slots;
7bdf72d3 235
8120e720 236 if (mei_hbm_cl_flow_control_req(dev, cl)) {
1ccb7b62 237 cl->status = -ENODEV;
ebb108ef 238 cb_pos->buf_idx = 0;
fb601adb 239 list_move_tail(&cb_pos->list, &cmpl_list->list);
1ccb7b62
TW
240 return -ENODEV;
241 }
fb601adb 242 list_move_tail(&cb_pos->list, &dev->read_list.list);
1ccb7b62 243
fb7d879f
OW
244 return 0;
245}
246
247
248/**
249 * _mei_irq_thread_ioctl - processes ioctl related operation.
250 *
251 * @dev: the device structure.
252 * @slots: free slots.
253 * @cb_pos: callback block.
254 * @cl: private data of the file object.
255 * @cmpl_list: complete list.
256 *
257 * returns 0, OK; otherwise, error.
258 */
259static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots,
260 struct mei_cl_cb *cb_pos,
261 struct mei_cl *cl,
fb601adb 262 struct mei_cl_cb *cmpl_list)
fb7d879f 263{
c8c8d080
TW
264 u32 msg_slots =
265 mei_data2slots(sizeof(struct hbm_client_connect_request));
266
267 if (*slots < msg_slots) {
fb7d879f 268 /* return the cancel routine */
fb601adb 269 list_del(&cb_pos->list);
c8c8d080 270 return -EMSGSIZE;
fb7d879f
OW
271 }
272
c8c8d080
TW
273 *slots -= msg_slots;
274
b45f3ccf 275 cl->state = MEI_FILE_CONNECTING;
c8c8d080 276
8120e720 277 if (mei_hbm_cl_connect_req(dev, cl)) {
b45f3ccf 278 cl->status = -ENODEV;
ebb108ef 279 cb_pos->buf_idx = 0;
fb601adb 280 list_del(&cb_pos->list);
b45f3ccf
TW
281 return -ENODEV;
282 } else {
fb601adb 283 list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list);
b45f3ccf
TW
284 cl->timer_count = MEI_CONNECT_TIMEOUT;
285 }
fb7d879f
OW
286 return 0;
287}
288
289/**
ea3b5fb7 290 * mei_irq_thread_write_complete - write messages to device.
fb7d879f
OW
291 *
292 * @dev: the device structure.
293 * @slots: free slots.
ea3b5fb7 294 * @cb: callback block.
fb7d879f
OW
295 * @cmpl_list: complete list.
296 *
297 * returns 0, OK; otherwise, error.
298 */
ea3b5fb7
TW
299static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots,
300 struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list)
fb7d879f 301{
e46f1874 302 struct mei_msg_hdr mei_hdr;
ea3b5fb7
TW
303 struct mei_cl *cl = cb->cl;
304 size_t len = cb->request_buffer.size - cb->buf_idx;
c8c8d080 305 u32 msg_slots = mei_data2slots(len);
ea3b5fb7 306
e46f1874
TW
307 mei_hdr.host_addr = cl->host_client_id;
308 mei_hdr.me_addr = cl->me_client_id;
309 mei_hdr.reserved = 0;
fb7d879f 310
ea3b5fb7 311 if (*slots >= msg_slots) {
e46f1874
TW
312 mei_hdr.length = len;
313 mei_hdr.msg_complete = 1;
ea3b5fb7 314 /* Split the message only if we can write the whole host buffer */
24aadc80 315 } else if (*slots == dev->hbuf_depth) {
ea3b5fb7
TW
316 msg_slots = *slots;
317 len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
e46f1874
TW
318 mei_hdr.length = len;
319 mei_hdr.msg_complete = 0;
fb7d879f 320 } else {
ea3b5fb7
TW
321 /* wait for next time the host buffer is empty */
322 return 0;
fb7d879f
OW
323 }
324
ea3b5fb7
TW
325 dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n",
326 cb->request_buffer.size, cb->buf_idx);
e46f1874 327 dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr));
ea3b5fb7
TW
328
329 *slots -= msg_slots;
e46f1874 330 if (mei_write_message(dev, &mei_hdr,
438763f3 331 cb->request_buffer.data + cb->buf_idx)) {
ea3b5fb7
TW
332 cl->status = -ENODEV;
333 list_move_tail(&cb->list, &cmpl_list->list);
334 return -ENODEV;
335 }
336
90e0b5f1 337 if (mei_cl_flow_ctrl_reduce(cl))
ea3b5fb7
TW
338 return -ENODEV;
339
340 cl->status = 0;
e46f1874
TW
341 cb->buf_idx += mei_hdr.length;
342 if (mei_hdr.msg_complete)
ea3b5fb7
TW
343 list_move_tail(&cb->list, &dev->write_waiting_list.list);
344
fb7d879f
OW
345 return 0;
346}
347
fb7d879f
OW
348/**
349 * mei_irq_thread_read_handler - bottom half read routine after ISR to
350 * handle the read processing.
351 *
fb7d879f 352 * @dev: the device structure
06ecd645 353 * @cmpl_list: An instance of our list structure
fb7d879f
OW
354 * @slots: slots to read.
355 *
356 * returns 0 on success, <0 on failure.
357 */
06ecd645
TW
358int mei_irq_read_handler(struct mei_device *dev,
359 struct mei_cl_cb *cmpl_list, s32 *slots)
fb7d879f
OW
360{
361 struct mei_msg_hdr *mei_hdr;
362 struct mei_cl *cl_pos = NULL;
363 struct mei_cl *cl_next = NULL;
364 int ret = 0;
365
366 if (!dev->rd_msg_hdr) {
827eef51 367 dev->rd_msg_hdr = mei_read_hdr(dev);
fb7d879f
OW
368 dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
369 (*slots)--;
370 dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
371 }
372 mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr;
15d4acc5 373 dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
fb7d879f
OW
374
375 if (mei_hdr->reserved || !dev->rd_msg_hdr) {
376 dev_dbg(&dev->pdev->dev, "corrupted message header.\n");
377 ret = -EBADMSG;
378 goto end;
379 }
380
381 if (mei_hdr->host_addr || mei_hdr->me_addr) {
382 list_for_each_entry_safe(cl_pos, cl_next,
383 &dev->file_list, link) {
384 dev_dbg(&dev->pdev->dev,
385 "list_for_each_entry_safe read host"
386 " client = %d, ME client = %d\n",
387 cl_pos->host_client_id,
388 cl_pos->me_client_id);
389 if (cl_pos->host_client_id == mei_hdr->host_addr &&
390 cl_pos->me_client_id == mei_hdr->me_addr)
391 break;
392 }
393
394 if (&cl_pos->link == &dev->file_list) {
395 dev_dbg(&dev->pdev->dev, "corrupted message header\n");
396 ret = -EBADMSG;
397 goto end;
398 }
399 }
400 if (((*slots) * sizeof(u32)) < mei_hdr->length) {
401 dev_dbg(&dev->pdev->dev,
402 "we can't read the message slots =%08x.\n",
403 *slots);
404 /* we can't read the message */
405 ret = -ERANGE;
406 goto end;
407 }
408
409 /* decide where to read the message too */
410 if (!mei_hdr->host_addr) {
411 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n");
bb1b0133 412 mei_hbm_dispatch(dev, mei_hdr);
fb7d879f
OW
413 dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n");
414 } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
415 (MEI_FILE_CONNECTED == dev->iamthif_cl.state) &&
416 (dev->iamthif_state == MEI_IAMTHIF_READING)) {
417 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
15d4acc5
TW
418
419 dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
19838fb8
TW
420
421 ret = mei_amthif_irq_read_message(cmpl_list, dev, mei_hdr);
fb7d879f
OW
422 if (ret)
423 goto end;
fb7d879f
OW
424 } else {
425 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n");
426 ret = mei_irq_thread_read_client_message(cmpl_list,
427 dev, mei_hdr);
428 if (ret)
429 goto end;
430
431 }
432
433 /* reset the number of slots and header */
434 *slots = mei_count_full_read_slots(dev);
435 dev->rd_msg_hdr = 0;
436
437 if (*slots == -EOVERFLOW) {
438 /* overflow - reset */
439 dev_dbg(&dev->pdev->dev, "resetting due to slots overflow.\n");
440 /* set the event since message has been read */
441 ret = -ERANGE;
442 goto end;
443 }
444end:
445 return ret;
446}
40e0b67b 447EXPORT_SYMBOL_GPL(mei_irq_read_handler);
fb7d879f
OW
448
449
450/**
06ecd645
TW
451 * mei_irq_write_handler - dispatch write requests
452 * after irq received
fb7d879f 453 *
fb7d879f 454 * @dev: the device structure
9a84d616 455 * @cmpl_list: An instance of our list structure
fb7d879f
OW
456 *
457 * returns 0 on success, <0 on failure.
458 */
c8c8d080 459int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
fb7d879f
OW
460{
461
462 struct mei_cl *cl;
b7cd2d9f 463 struct mei_cl_cb *pos = NULL, *next = NULL;
fb601adb 464 struct mei_cl_cb *list;
9a84d616 465 s32 slots;
fb7d879f
OW
466 int ret;
467
827eef51 468 if (!mei_hbuf_is_ready(dev)) {
fb7d879f
OW
469 dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
470 return 0;
471 }
9a84d616
TW
472 slots = mei_hbuf_empty_slots(dev);
473 if (slots <= 0)
7d5e0e59
TW
474 return -EMSGSIZE;
475
fb7d879f
OW
476 /* complete all waiting for write CB */
477 dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");
478
479 list = &dev->write_waiting_list;
fb601adb 480 list_for_each_entry_safe(pos, next, &list->list, list) {
db3ed431 481 cl = pos->cl;
b7cd2d9f
TW
482 if (cl == NULL)
483 continue;
484
485 cl->status = 0;
fb601adb 486 list_del(&pos->list);
b7cd2d9f 487 if (MEI_WRITING == cl->writing_state &&
4b8960b4
TW
488 pos->fop_type == MEI_FOP_WRITE &&
489 cl != &dev->iamthif_cl) {
483136ea 490 dev_dbg(&dev->pdev->dev, "MEI WRITE COMPLETE\n");
b7cd2d9f 491 cl->writing_state = MEI_WRITE_COMPLETE;
fb601adb 492 list_add_tail(&pos->list, &cmpl_list->list);
b7cd2d9f
TW
493 }
494 if (cl == &dev->iamthif_cl) {
495 dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n");
496 if (dev->iamthif_flow_control_pending) {
9a84d616 497 ret = mei_amthif_irq_read(dev, &slots);
b7cd2d9f
TW
498 if (ret)
499 return ret;
fb7d879f 500 }
fb7d879f
OW
501 }
502 }
503
c216fdeb
TW
504 if (dev->wd_state == MEI_WD_STOPPING) {
505 dev->wd_state = MEI_WD_IDLE;
fb7d879f 506 wake_up_interruptible(&dev->wait_stop_wd);
fb7d879f
OW
507 }
508
5fb54fb4
TW
509 if (dev->wr_ext_msg.hdr.length) {
510 mei_write_message(dev, &dev->wr_ext_msg.hdr,
438763f3 511 dev->wr_ext_msg.data);
9a84d616 512 slots -= mei_data2slots(dev->wr_ext_msg.hdr.length);
5fb54fb4 513 dev->wr_ext_msg.hdr.length = 0;
fb7d879f 514 }
b210d750 515 if (dev->dev_state == MEI_DEV_ENABLED) {
fb7d879f 516 if (dev->wd_pending &&
90e0b5f1 517 mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
fb7d879f
OW
518 if (mei_wd_send(dev))
519 dev_dbg(&dev->pdev->dev, "wd send failed.\n");
90e0b5f1 520 else if (mei_cl_flow_ctrl_reduce(&dev->wd_cl))
483136ea 521 return -ENODEV;
fb7d879f 522
eb9af0ac 523 dev->wd_pending = false;
fb7d879f 524
c216fdeb 525 if (dev->wd_state == MEI_WD_RUNNING)
9a84d616 526 slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
d242a0af 527 else
9a84d616 528 slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE);
fb7d879f
OW
529 }
530 }
fb7d879f
OW
531
532 /* complete control write list CB */
c8372094 533 dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
fb601adb 534 list_for_each_entry_safe(pos, next, &dev->ctrl_wr_list.list, list) {
db3ed431 535 cl = pos->cl;
c8372094 536 if (!cl) {
fb601adb 537 list_del(&pos->list);
c8372094
TW
538 return -ENODEV;
539 }
4b8960b4
TW
540 switch (pos->fop_type) {
541 case MEI_FOP_CLOSE:
c8372094 542 /* send disconnect message */
9a84d616
TW
543 ret = _mei_irq_thread_close(dev, &slots, pos,
544 cl, cmpl_list);
c8372094
TW
545 if (ret)
546 return ret;
fb7d879f 547
c8372094 548 break;
4b8960b4 549 case MEI_FOP_READ:
c8372094 550 /* send flow control message */
9a84d616
TW
551 ret = _mei_irq_thread_read(dev, &slots, pos,
552 cl, cmpl_list);
c8372094
TW
553 if (ret)
554 return ret;
fb7d879f 555
c8372094 556 break;
4b8960b4 557 case MEI_FOP_IOCTL:
c8372094 558 /* connect message */
90e0b5f1 559 if (mei_cl_is_other_connecting(cl))
c8372094 560 continue;
9a84d616
TW
561 ret = _mei_irq_thread_ioctl(dev, &slots, pos,
562 cl, cmpl_list);
c8372094
TW
563 if (ret)
564 return ret;
fb7d879f 565
c8372094 566 break;
fb7d879f 567
c8372094
TW
568 default:
569 BUG();
fb7d879f 570 }
c8372094 571
fb7d879f
OW
572 }
573 /* complete write list CB */
b7cd2d9f 574 dev_dbg(&dev->pdev->dev, "complete write list cb.\n");
fb601adb 575 list_for_each_entry_safe(pos, next, &dev->write_list.list, list) {
db3ed431 576 cl = pos->cl;
b7cd2d9f
TW
577 if (cl == NULL)
578 continue;
90e0b5f1 579 if (mei_cl_flow_ctrl_creds(cl) <= 0) {
be9d87a7
TW
580 dev_dbg(&dev->pdev->dev,
581 "No flow control credentials for client %d, not sending.\n",
582 cl->host_client_id);
583 continue;
584 }
b7cd2d9f 585
be9d87a7 586 if (cl == &dev->iamthif_cl)
9a84d616 587 ret = mei_amthif_irq_write_complete(dev, &slots,
24c656e5 588 pos, cmpl_list);
be9d87a7
TW
589 else
590 ret = mei_irq_thread_write_complete(dev, &slots, pos,
591 cmpl_list);
592 if (ret)
593 return ret;
b7cd2d9f 594
fb7d879f
OW
595 }
596 return 0;
597}
40e0b67b 598EXPORT_SYMBOL_GPL(mei_irq_write_handler);
fb7d879f
OW
599
600
601
602/**
603 * mei_timer - timer function.
604 *
605 * @work: pointer to the work_struct structure
606 *
607 * NOTE: This function is called by timer interrupt work
608 */
a61c6530 609void mei_timer(struct work_struct *work)
fb7d879f
OW
610{
611 unsigned long timeout;
612 struct mei_cl *cl_pos = NULL;
613 struct mei_cl *cl_next = NULL;
fb7d879f
OW
614 struct mei_cl_cb *cb_pos = NULL;
615 struct mei_cl_cb *cb_next = NULL;
616
617 struct mei_device *dev = container_of(work,
a61c6530 618 struct mei_device, timer_work.work);
fb7d879f
OW
619
620
621 mutex_lock(&dev->device_lock);
b210d750
TW
622 if (dev->dev_state != MEI_DEV_ENABLED) {
623 if (dev->dev_state == MEI_DEV_INIT_CLIENTS) {
fb7d879f
OW
624 if (dev->init_clients_timer) {
625 if (--dev->init_clients_timer == 0) {
9b0d5efc
TW
626 dev_err(&dev->pdev->dev, "reset: init clients timeout hbm_state = %d.\n",
627 dev->hbm_state);
fb7d879f
OW
628 mei_reset(dev, 1);
629 }
630 }
631 }
632 goto out;
633 }
634 /*** connect/disconnect timeouts ***/
635 list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
636 if (cl_pos->timer_count) {
637 if (--cl_pos->timer_count == 0) {
d6c36a47 638 dev_err(&dev->pdev->dev, "reset: connect/disconnect timeout.\n");
fb7d879f
OW
639 mei_reset(dev, 1);
640 goto out;
641 }
642 }
643 }
644
fb7d879f
OW
645 if (dev->iamthif_stall_timer) {
646 if (--dev->iamthif_stall_timer == 0) {
d6c36a47 647 dev_err(&dev->pdev->dev, "reset: amthif hanged.\n");
fb7d879f
OW
648 mei_reset(dev, 1);
649 dev->iamthif_msg_buf_size = 0;
650 dev->iamthif_msg_buf_index = 0;
eb9af0ac
TW
651 dev->iamthif_canceled = false;
652 dev->iamthif_ioctl = true;
fb7d879f
OW
653 dev->iamthif_state = MEI_IAMTHIF_IDLE;
654 dev->iamthif_timer = 0;
655
601a1efa
TW
656 mei_io_cb_free(dev->iamthif_current_cb);
657 dev->iamthif_current_cb = NULL;
fb7d879f
OW
658
659 dev->iamthif_file_object = NULL;
19838fb8 660 mei_amthif_run_next_cmd(dev);
fb7d879f
OW
661 }
662 }
663
664 if (dev->iamthif_timer) {
665
666 timeout = dev->iamthif_timer +
3870c320 667 mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
fb7d879f
OW
668
669 dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
670 dev->iamthif_timer);
671 dev_dbg(&dev->pdev->dev, "timeout = %ld\n", timeout);
672 dev_dbg(&dev->pdev->dev, "jiffies = %ld\n", jiffies);
673 if (time_after(jiffies, timeout)) {
674 /*
675 * User didn't read the AMTHI data on time (15sec)
676 * freeing AMTHI for other requests
677 */
678
679 dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n");
680
e773efc4
TW
681 list_for_each_entry_safe(cb_pos, cb_next,
682 &dev->amthif_rd_complete_list.list, list) {
fb7d879f 683
b7cd2d9f 684 cl_pos = cb_pos->file_object->private_data;
fb7d879f 685
b7cd2d9f
TW
686 /* Finding the AMTHI entry. */
687 if (cl_pos == &dev->iamthif_cl)
fb601adb 688 list_del(&cb_pos->list);
fb7d879f 689 }
601a1efa
TW
690 mei_io_cb_free(dev->iamthif_current_cb);
691 dev->iamthif_current_cb = NULL;
fb7d879f
OW
692
693 dev->iamthif_file_object->private_data = NULL;
694 dev->iamthif_file_object = NULL;
fb7d879f 695 dev->iamthif_timer = 0;
19838fb8 696 mei_amthif_run_next_cmd(dev);
fb7d879f
OW
697
698 }
699 }
700out:
441ab50f
TW
701 schedule_delayed_work(&dev->timer_work, 2 * HZ);
702 mutex_unlock(&dev->device_lock);
fb7d879f
OW
703}
704
This page took 0.328336 seconds and 5 git commands to generate.