mei: introduce mei_data2slots wrapper
[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
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{
60 if (cb_pos->major_file_operations == MEI_WRITE) {
61 mei_free_cb_private(cb_pos);
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
67 } else if (cb_pos->major_file_operations == MEI_READ &&
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
76/**
77 * _mei_cmpl_iamthif - processes completed iamthif operation.
78 *
79 * @dev: the device structure.
80 * @cb_pos: callback block.
81 */
82static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos)
83{
84 if (dev->iamthif_canceled != 1) {
85 dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
86 dev->iamthif_stall_timer = 0;
87 memcpy(cb_pos->response_buffer.data,
88 dev->iamthif_msg_buf,
89 dev->iamthif_msg_buf_index);
90 list_add_tail(&cb_pos->cb_list,
91 &dev->amthi_read_complete_list.mei_cb.cb_list);
92 dev_dbg(&dev->pdev->dev, "amthi read completed.\n");
93 dev->iamthif_timer = jiffies;
94 dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
95 dev->iamthif_timer);
96 } else {
c95efb74 97 mei_run_next_iamthif_cmd(dev);
fb7d879f
OW
98 }
99
100 dev_dbg(&dev->pdev->dev, "completing amthi call back.\n");
101 wake_up_interruptible(&dev->iamthif_cl.wait);
102}
103
104
105/**
106 * mei_irq_thread_read_amthi_message - bottom half read routine after ISR to
107 * handle the read amthi message data processing.
108 *
109 * @complete_list: An instance of our list structure
110 * @dev: the device structure
111 * @mei_hdr: header of amthi message
112 *
113 * returns 0 on success, <0 on failure.
114 */
115static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list,
116 struct mei_device *dev,
117 struct mei_msg_hdr *mei_hdr)
118{
119 struct mei_cl *cl;
120 struct mei_cl_cb *cb;
121 unsigned char *buffer;
122
123 BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id);
124 BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING);
125
edf1eed4 126 buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index;
fb7d879f
OW
127 BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length);
128
129 mei_read_slots(dev, buffer, mei_hdr->length);
130
131 dev->iamthif_msg_buf_index += mei_hdr->length;
132
133 if (!mei_hdr->msg_complete)
134 return 0;
135
136 dev_dbg(&dev->pdev->dev,
137 "amthi_message_buffer_index =%d\n",
138 mei_hdr->length);
139
140 dev_dbg(&dev->pdev->dev, "completed amthi read.\n ");
141 if (!dev->iamthif_current_cb)
142 return -ENODEV;
143
144 cb = dev->iamthif_current_cb;
145 dev->iamthif_current_cb = NULL;
146
147 cl = (struct mei_cl *)cb->file_private;
148 if (!cl)
149 return -ENODEV;
150
151 dev->iamthif_stall_timer = 0;
152 cb->information = dev->iamthif_msg_buf_index;
153 cb->read_time = jiffies;
154 if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) {
155 /* found the iamthif cb */
156 dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n ");
157 dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n ");
158 list_add_tail(&cb->cb_list,
159 &complete_list->mei_cb.cb_list);
160 }
161 return 0;
162}
163
164/**
165 * _mei_irq_thread_state_ok - checks if mei header matches file private data
166 *
167 * @cl: private data of the file object
168 * @mei_hdr: header of mei client message
169 *
170 * returns !=0 if matches, 0 if no match.
171 */
172static int _mei_irq_thread_state_ok(struct mei_cl *cl,
173 struct mei_msg_hdr *mei_hdr)
174{
175 return (cl->host_client_id == mei_hdr->host_addr &&
176 cl->me_client_id == mei_hdr->me_addr &&
177 cl->state == MEI_FILE_CONNECTED &&
178 MEI_READ_COMPLETE != cl->reading_state);
179}
180
181/**
182 * mei_irq_thread_read_client_message - bottom half read routine after ISR to
183 * handle the read mei client message data processing.
184 *
185 * @complete_list: An instance of our list structure
186 * @dev: the device structure
187 * @mei_hdr: header of mei client message
188 *
189 * returns 0 on success, <0 on failure.
190 */
191static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list,
192 struct mei_device *dev,
193 struct mei_msg_hdr *mei_hdr)
194{
195 struct mei_cl *cl;
196 struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
479bc59d 197 unsigned char *buffer = NULL;
fb7d879f
OW
198
199 dev_dbg(&dev->pdev->dev, "start client msg\n");
c8372094 200 if (list_empty(&dev->read_list.mei_cb.cb_list))
fb7d879f
OW
201 goto quit;
202
203 list_for_each_entry_safe(cb_pos, cb_next,
204 &dev->read_list.mei_cb.cb_list, cb_list) {
205 cl = (struct mei_cl *)cb_pos->file_private;
206 if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
207 cl->reading_state = MEI_READING;
edf1eed4 208 buffer = cb_pos->response_buffer.data + cb_pos->information;
fb7d879f
OW
209
210 if (cb_pos->response_buffer.size <
211 mei_hdr->length + cb_pos->information) {
212 dev_dbg(&dev->pdev->dev, "message overflow.\n");
213 list_del(&cb_pos->cb_list);
214 return -ENOMEM;
215 }
216 if (buffer)
217 mei_read_slots(dev, buffer, mei_hdr->length);
218
219 cb_pos->information += mei_hdr->length;
220 if (mei_hdr->msg_complete) {
221 cl->status = 0;
222 list_del(&cb_pos->cb_list);
223 dev_dbg(&dev->pdev->dev,
224 "completed read host client = %d,"
225 "ME client = %d, "
226 "data length = %lu\n",
227 cl->host_client_id,
228 cl->me_client_id,
229 cb_pos->information);
230
231 *(cb_pos->response_buffer.data +
232 cb_pos->information) = '\0';
233 dev_dbg(&dev->pdev->dev, "cb_pos->res_buffer - %s\n",
234 cb_pos->response_buffer.data);
235 list_add_tail(&cb_pos->cb_list,
236 &complete_list->mei_cb.cb_list);
237 }
238
239 break;
240 }
241
242 }
243
244quit:
245 dev_dbg(&dev->pdev->dev, "message read\n");
246 if (!buffer) {
edf1eed4 247 mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
fb7d879f
OW
248 dev_dbg(&dev->pdev->dev, "discarding message, header =%08x.\n",
249 *(u32 *) dev->rd_msg_buf);
250 }
251
252 return 0;
253}
254
255/**
256 * _mei_irq_thread_iamthif_read - prepares to read iamthif data.
257 *
258 * @dev: the device structure.
259 * @slots: free slots.
260 *
261 * returns 0, OK; otherwise, error.
262 */
263static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots)
264{
265
1ccb7b62 266 if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr)
fb7d879f 267 + sizeof(struct hbm_flow_control))) {
fb7d879f
OW
268 return -EMSGSIZE;
269 }
7bdf72d3 270 *slots -= mei_data2slots(sizeof(struct hbm_flow_control));
1ccb7b62
TW
271 if (mei_send_flow_control(dev, &dev->iamthif_cl)) {
272 dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
273 return -EIO;
274 }
275
276 dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
277 dev->iamthif_state = MEI_IAMTHIF_READING;
278 dev->iamthif_flow_control_pending = false;
279 dev->iamthif_msg_buf_index = 0;
280 dev->iamthif_msg_buf_size = 0;
281 dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
726917f0 282 dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev);
1ccb7b62 283 return 0;
fb7d879f
OW
284}
285
286/**
287 * _mei_irq_thread_close - processes close related operation.
288 *
289 * @dev: the device structure.
290 * @slots: free slots.
291 * @cb_pos: callback block.
292 * @cl: private data of the file object.
293 * @cmpl_list: complete list.
294 *
295 * returns 0, OK; otherwise, error.
296 */
297static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots,
298 struct mei_cl_cb *cb_pos,
299 struct mei_cl *cl,
300 struct mei_io_list *cmpl_list)
301{
302 if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
303 sizeof(struct hbm_client_disconnect_request))) {
7bdf72d3 304 *slots -= mei_data2slots(sizeof(struct hbm_client_disconnect_request));
fb7d879f 305
1ccb7b62 306 if (mei_disconnect(dev, cl)) {
fb7d879f
OW
307 cl->status = 0;
308 cb_pos->information = 0;
309 list_move_tail(&cb_pos->cb_list,
310 &cmpl_list->mei_cb.cb_list);
311 return -EMSGSIZE;
312 } else {
313 cl->state = MEI_FILE_DISCONNECTING;
314 cl->status = 0;
315 cb_pos->information = 0;
316 list_move_tail(&cb_pos->cb_list,
317 &dev->ctrl_rd_list.mei_cb.cb_list);
318 cl->timer_count = MEI_CONNECT_TIMEOUT;
319 }
320 } else {
321 /* return the cancel routine */
322 return -EBADMSG;
323 }
324
325 return 0;
326}
327
328/**
329 * is_treat_specially_client - checks if the message belongs
330 * to the file private data.
331 *
332 * @cl: private data of the file object
333 * @rs: connect response bus message
334 *
335 */
336static bool is_treat_specially_client(struct mei_cl *cl,
337 struct hbm_client_connect_response *rs)
338{
339
340 if (cl->host_client_id == rs->host_addr &&
341 cl->me_client_id == rs->me_addr) {
342 if (!rs->status) {
343 cl->state = MEI_FILE_CONNECTED;
344 cl->status = 0;
345
346 } else {
347 cl->state = MEI_FILE_DISCONNECTED;
348 cl->status = -ENODEV;
349 }
350 cl->timer_count = 0;
351
352 return true;
353 }
354 return false;
355}
356
357/**
358 * mei_client_connect_response - connects to response irq routine
359 *
360 * @dev: the device structure
361 * @rs: connect response bus message
362 */
363static void mei_client_connect_response(struct mei_device *dev,
364 struct hbm_client_connect_response *rs)
365{
366
367 struct mei_cl *cl;
368 struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
369
370 dev_dbg(&dev->pdev->dev,
371 "connect_response:\n"
372 "ME Client = %d\n"
373 "Host Client = %d\n"
374 "Status = %d\n",
375 rs->me_addr,
376 rs->host_addr,
377 rs->status);
378
379 /* if WD or iamthif client treat specially */
380
381 if (is_treat_specially_client(&(dev->wd_cl), rs)) {
fb7d879f 382 dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
70cd5337 383 mei_watchdog_register(dev);
9ce178e5 384
70cd5337 385 /* next step in the state maching */
c95efb74 386 mei_host_init_iamthif(dev);
fb7d879f
OW
387 return;
388 }
389
390 if (is_treat_specially_client(&(dev->iamthif_cl), rs)) {
391 dev->iamthif_state = MEI_IAMTHIF_IDLE;
392 return;
393 }
b7cd2d9f
TW
394 list_for_each_entry_safe(cb_pos, cb_next,
395 &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) {
396
397 cl = (struct mei_cl *)cb_pos->file_private;
398 if (!cl) {
399 list_del(&cb_pos->cb_list);
400 return;
401 }
402 if (MEI_IOCTL == cb_pos->major_file_operations) {
403 if (is_treat_specially_client(cl, rs)) {
fb7d879f 404 list_del(&cb_pos->cb_list);
b7cd2d9f
TW
405 cl->status = 0;
406 cl->timer_count = 0;
407 break;
fb7d879f
OW
408 }
409 }
410 }
411}
412
413/**
414 * mei_client_disconnect_response - disconnects from response irq routine
415 *
416 * @dev: the device structure
417 * @rs: disconnect response bus message
418 */
419static void mei_client_disconnect_response(struct mei_device *dev,
420 struct hbm_client_connect_response *rs)
421{
422 struct mei_cl *cl;
423 struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
424
425 dev_dbg(&dev->pdev->dev,
426 "disconnect_response:\n"
427 "ME Client = %d\n"
428 "Host Client = %d\n"
429 "Status = %d\n",
430 rs->me_addr,
431 rs->host_addr,
432 rs->status);
433
b7cd2d9f
TW
434 list_for_each_entry_safe(cb_pos, cb_next,
435 &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) {
436 cl = (struct mei_cl *)cb_pos->file_private;
fb7d879f 437
b7cd2d9f
TW
438 if (!cl) {
439 list_del(&cb_pos->cb_list);
440 return;
441 }
fb7d879f 442
b7cd2d9f
TW
443 dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
444 if (cl->host_client_id == rs->host_addr &&
445 cl->me_client_id == rs->me_addr) {
fb7d879f 446
b7cd2d9f
TW
447 list_del(&cb_pos->cb_list);
448 if (!rs->status)
449 cl->state = MEI_FILE_DISCONNECTED;
fb7d879f 450
b7cd2d9f
TW
451 cl->status = 0;
452 cl->timer_count = 0;
453 break;
fb7d879f
OW
454 }
455 }
456}
457
458/**
459 * same_flow_addr - tells if they have the same address.
460 *
461 * @file: private data of the file object.
462 * @flow: flow control.
463 *
464 * returns !=0, same; 0,not.
465 */
466static int same_flow_addr(struct mei_cl *cl, struct hbm_flow_control *flow)
467{
468 return (cl->host_client_id == flow->host_addr &&
469 cl->me_client_id == flow->me_addr);
470}
471
472/**
473 * add_single_flow_creds - adds single buffer credentials.
474 *
475 * @file: private data ot the file object.
476 * @flow: flow control.
477 */
478static void add_single_flow_creds(struct mei_device *dev,
479 struct hbm_flow_control *flow)
480{
481 struct mei_me_client *client;
482 int i;
483
cf9673da 484 for (i = 0; i < dev->me_clients_num; i++) {
fb7d879f
OW
485 client = &dev->me_clients[i];
486 if (client && flow->me_addr == client->client_id) {
487 if (client->props.single_recv_buf) {
488 client->mei_flow_ctrl_creds++;
489 dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
490 flow->me_addr);
491 dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
492 client->mei_flow_ctrl_creds);
493 } else {
494 BUG(); /* error in flow control */
495 }
496 }
497 }
498}
499
500/**
501 * mei_client_flow_control_response - flow control response irq routine
502 *
503 * @dev: the device structure
504 * @flow_control: flow control response bus message
505 */
506static void mei_client_flow_control_response(struct mei_device *dev,
507 struct hbm_flow_control *flow_control)
508{
509 struct mei_cl *cl_pos = NULL;
510 struct mei_cl *cl_next = NULL;
511
512 if (!flow_control->host_addr) {
513 /* single receive buffer */
514 add_single_flow_creds(dev, flow_control);
515 } else {
516 /* normal connection */
517 list_for_each_entry_safe(cl_pos, cl_next,
518 &dev->file_list, link) {
519 dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in file_list\n");
520
521 dev_dbg(&dev->pdev->dev, "cl of host client %d ME client %d.\n",
522 cl_pos->host_client_id,
523 cl_pos->me_client_id);
524 dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
525 flow_control->host_addr,
526 flow_control->me_addr);
527 if (same_flow_addr(cl_pos, flow_control)) {
528 dev_dbg(&dev->pdev->dev, "recv ctrl msg for host %d ME %d.\n",
529 flow_control->host_addr,
530 flow_control->me_addr);
531 cl_pos->mei_flow_ctrl_creds++;
532 dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
533 cl_pos->mei_flow_ctrl_creds);
534 break;
535 }
536 }
537 }
538}
539
540/**
541 * same_disconn_addr - tells if they have the same address
542 *
543 * @file: private data of the file object.
544 * @disconn: disconnection request.
545 *
546 * returns !=0, same; 0,not.
547 */
548static int same_disconn_addr(struct mei_cl *cl,
549 struct hbm_client_disconnect_request *disconn)
550{
551 return (cl->host_client_id == disconn->host_addr &&
552 cl->me_client_id == disconn->me_addr);
553}
554
555/**
556 * mei_client_disconnect_request - disconnects from request irq routine
557 *
558 * @dev: the device structure.
559 * @disconnect_req: disconnect request bus message.
560 */
561static void mei_client_disconnect_request(struct mei_device *dev,
562 struct hbm_client_disconnect_request *disconnect_req)
563{
564 struct mei_msg_hdr *mei_hdr;
565 struct hbm_client_connect_response *disconnect_res;
566 struct mei_cl *cl_pos = NULL;
567 struct mei_cl *cl_next = NULL;
568
569 list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
570 if (same_disconn_addr(cl_pos, disconnect_req)) {
571 dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
572 disconnect_req->host_addr,
573 disconnect_req->me_addr);
574 cl_pos->state = MEI_FILE_DISCONNECTED;
575 cl_pos->timer_count = 0;
d242a0af 576 if (cl_pos == &dev->wd_cl)
eb9af0ac 577 dev->wd_pending = false;
d242a0af 578 else if (cl_pos == &dev->iamthif_cl)
fb7d879f
OW
579 dev->iamthif_timer = 0;
580
581 /* prepare disconnect response */
582 mei_hdr =
583 (struct mei_msg_hdr *) &dev->ext_msg_buf[0];
584 mei_hdr->host_addr = 0;
585 mei_hdr->me_addr = 0;
586 mei_hdr->length =
587 sizeof(struct hbm_client_connect_response);
588 mei_hdr->msg_complete = 1;
589 mei_hdr->reserved = 0;
590
591 disconnect_res =
592 (struct hbm_client_connect_response *)
593 &dev->ext_msg_buf[1];
594 disconnect_res->host_addr = cl_pos->host_client_id;
595 disconnect_res->me_addr = cl_pos->me_client_id;
1ca7e782 596 disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD;
fb7d879f
OW
597 disconnect_res->status = 0;
598 dev->extra_write_index = 2;
599 break;
600 }
601 }
602}
603
604
605/**
606 * mei_irq_thread_read_bus_message - bottom half read routine after ISR to
607 * handle the read bus message cmd processing.
608 *
609 * @dev: the device structure
610 * @mei_hdr: header of bus message
611 */
612static void mei_irq_thread_read_bus_message(struct mei_device *dev,
613 struct mei_msg_hdr *mei_hdr)
614{
615 struct mei_bus_message *mei_msg;
616 struct hbm_host_version_response *version_res;
617 struct hbm_client_connect_response *connect_res;
618 struct hbm_client_connect_response *disconnect_res;
619 struct hbm_flow_control *flow_control;
620 struct hbm_props_response *props_res;
621 struct hbm_host_enum_response *enum_res;
622 struct hbm_client_disconnect_request *disconnect_req;
623 struct hbm_host_stop_request *host_stop_req;
abc51b6d 624 int res;
fb7d879f 625
fb7d879f
OW
626
627 /* read the message to our buffer */
fb7d879f 628 BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf));
edf1eed4
TW
629 mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
630 mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
fb7d879f 631
1ca7e782 632 switch (mei_msg->hbm_cmd) {
fb7d879f
OW
633 case HOST_START_RES_CMD:
634 version_res = (struct hbm_host_version_response *) mei_msg;
635 if (version_res->host_version_supported) {
636 dev->version.major_version = HBM_MAJOR_VERSION;
637 dev->version.minor_version = HBM_MINOR_VERSION;
638 if (dev->mei_state == MEI_INIT_CLIENTS &&
639 dev->init_clients_state == MEI_START_MESSAGE) {
640 dev->init_clients_timer = 0;
c95efb74 641 mei_host_enum_clients_message(dev);
fb7d879f 642 } else {
eb9af0ac 643 dev->recvd_msg = false;
fb7d879f
OW
644 dev_dbg(&dev->pdev->dev, "IMEI reset due to received host start response bus message.\n");
645 mei_reset(dev, 1);
646 return;
647 }
648 } else {
649 dev->version = version_res->me_max_version;
650 /* send stop message */
97d5cb09 651 mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
fb7d879f
OW
652 mei_hdr->host_addr = 0;
653 mei_hdr->me_addr = 0;
654 mei_hdr->length = sizeof(struct hbm_host_stop_request);
655 mei_hdr->msg_complete = 1;
656 mei_hdr->reserved = 0;
657
658 host_stop_req = (struct hbm_host_stop_request *)
659 &dev->wr_msg_buf[1];
660
661 memset(host_stop_req,
662 0,
663 sizeof(struct hbm_host_stop_request));
1ca7e782 664 host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
fb7d879f
OW
665 host_stop_req->reason = DRIVER_STOP_REQUEST;
666 mei_write_message(dev, mei_hdr,
667 (unsigned char *) (host_stop_req),
668 mei_hdr->length);
669 dev_dbg(&dev->pdev->dev, "version mismatch.\n");
670 return;
671 }
672
eb9af0ac 673 dev->recvd_msg = true;
fb7d879f
OW
674 dev_dbg(&dev->pdev->dev, "host start response message received.\n");
675 break;
676
677 case CLIENT_CONNECT_RES_CMD:
678 connect_res =
679 (struct hbm_client_connect_response *) mei_msg;
680 mei_client_connect_response(dev, connect_res);
681 dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
682 wake_up(&dev->wait_recvd_msg);
683 break;
684
685 case CLIENT_DISCONNECT_RES_CMD:
686 disconnect_res =
687 (struct hbm_client_connect_response *) mei_msg;
441ab50f 688 mei_client_disconnect_response(dev, disconnect_res);
fb7d879f
OW
689 dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
690 wake_up(&dev->wait_recvd_msg);
691 break;
692
693 case MEI_FLOW_CONTROL_CMD:
694 flow_control = (struct hbm_flow_control *) mei_msg;
695 mei_client_flow_control_response(dev, flow_control);
696 dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
697 break;
698
699 case HOST_CLIENT_PROPERTIES_RES_CMD:
700 props_res = (struct hbm_props_response *)mei_msg;
701 if (props_res->status || !dev->me_clients) {
702 dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
703 mei_reset(dev, 1);
704 return;
705 }
441ab50f 706 if (dev->me_clients[dev->me_client_presentation_num]
fb7d879f
OW
707 .client_id == props_res->address) {
708
709 dev->me_clients[dev->me_client_presentation_num].props
710 = props_res->client_properties;
711
712 if (dev->mei_state == MEI_INIT_CLIENTS &&
713 dev->init_clients_state ==
714 MEI_CLIENT_PROPERTIES_MESSAGE) {
715 dev->me_client_index++;
716 dev->me_client_presentation_num++;
abc51b6d 717
5f9092f3 718 /** Send Client Properties request **/
abc51b6d
OW
719 res = mei_host_client_properties(dev);
720 if (res < 0) {
721 dev_dbg(&dev->pdev->dev, "mei_host_client_properties() failed");
722 return;
723 } else if (!res) {
724 /*
725 * No more clients to send to.
726 * Clear Map for indicating now ME clients
727 * with associated host client
728 */
729 bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
730 dev->open_handle_count = 0;
731
732 /*
733 * Reserving the first three client IDs
734 * Client Id 0 - Reserved for MEI Bus Message communications
735 * Client Id 1 - Reserved for Watchdog
736 * Client ID 2 - Reserved for AMTHI
737 */
738 bitmap_set(dev->host_clients_map, 0, 3);
739 dev->mei_state = MEI_ENABLED;
740
741 /* if wd initialization fails, initialization the AMTHI client,
742 * otherwise the AMTHI client will be initialized after the WD client connect response
743 * will be received
744 */
745 if (mei_wd_host_init(dev))
746 mei_host_init_iamthif(dev);
747 }
748
fb7d879f
OW
749 } else {
750 dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message");
751 mei_reset(dev, 1);
752 return;
753 }
754 } else {
755 dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message for wrong client ID\n");
756 mei_reset(dev, 1);
757 return;
758 }
759 break;
760
761 case HOST_ENUM_RES_CMD:
762 enum_res = (struct hbm_host_enum_response *) mei_msg;
763 memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
764 if (dev->mei_state == MEI_INIT_CLIENTS &&
765 dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
766 dev->init_clients_timer = 0;
767 dev->me_client_presentation_num = 0;
768 dev->me_client_index = 0;
c95efb74 769 mei_allocate_me_clients_storage(dev);
fb7d879f
OW
770 dev->init_clients_state =
771 MEI_CLIENT_PROPERTIES_MESSAGE;
c95efb74 772 mei_host_client_properties(dev);
fb7d879f
OW
773 } else {
774 dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
775 mei_reset(dev, 1);
776 return;
777 }
778 break;
779
780 case HOST_STOP_RES_CMD:
781 dev->mei_state = MEI_DISABLED;
782 dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
783 mei_reset(dev, 1);
784 break;
785
786 case CLIENT_DISCONNECT_REQ_CMD:
787 /* search for client */
788 disconnect_req =
789 (struct hbm_client_disconnect_request *) mei_msg;
790 mei_client_disconnect_request(dev, disconnect_req);
791 break;
792
793 case ME_STOP_REQ_CMD:
794 /* prepare stop request */
795 mei_hdr = (struct mei_msg_hdr *) &dev->ext_msg_buf[0];
796 mei_hdr->host_addr = 0;
797 mei_hdr->me_addr = 0;
798 mei_hdr->length = sizeof(struct hbm_host_stop_request);
799 mei_hdr->msg_complete = 1;
800 mei_hdr->reserved = 0;
801 host_stop_req =
802 (struct hbm_host_stop_request *) &dev->ext_msg_buf[1];
803 memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request));
1ca7e782 804 host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD;
fb7d879f
OW
805 host_stop_req->reason = DRIVER_STOP_REQUEST;
806 host_stop_req->reserved[0] = 0;
807 host_stop_req->reserved[1] = 0;
808 dev->extra_write_index = 2;
809 break;
810
811 default:
812 BUG();
813 break;
814
815 }
816}
817
818
819/**
820 * _mei_hb_read - processes read related operation.
821 *
822 * @dev: the device structure.
823 * @slots: free slots.
824 * @cb_pos: callback block.
825 * @cl: private data of the file object.
826 * @cmpl_list: complete list.
827 *
828 * returns 0, OK; otherwise, error.
829 */
830static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots,
831 struct mei_cl_cb *cb_pos,
832 struct mei_cl *cl,
833 struct mei_io_list *cmpl_list)
834{
835 if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
836 sizeof(struct hbm_flow_control))) {
fb7d879f
OW
837 /* return the cancel routine */
838 list_del(&cb_pos->cb_list);
839 return -EBADMSG;
840 }
841
7bdf72d3
TW
842 *slots -= mei_data2slots(sizeof(struct hbm_flow_control));
843
1ccb7b62
TW
844 if (mei_send_flow_control(dev, cl)) {
845 cl->status = -ENODEV;
846 cb_pos->information = 0;
847 list_move_tail(&cb_pos->cb_list, &cmpl_list->mei_cb.cb_list);
848 return -ENODEV;
849 }
850 list_move_tail(&cb_pos->cb_list, &dev->read_list.mei_cb.cb_list);
851
fb7d879f
OW
852 return 0;
853}
854
855
856/**
857 * _mei_irq_thread_ioctl - processes ioctl related operation.
858 *
859 * @dev: the device structure.
860 * @slots: free slots.
861 * @cb_pos: callback block.
862 * @cl: private data of the file object.
863 * @cmpl_list: complete list.
864 *
865 * returns 0, OK; otherwise, error.
866 */
867static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots,
868 struct mei_cl_cb *cb_pos,
869 struct mei_cl *cl,
870 struct mei_io_list *cmpl_list)
871{
872 if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
873 sizeof(struct hbm_client_connect_request))) {
874 cl->state = MEI_FILE_CONNECTING;
7bdf72d3 875 *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request));
1ccb7b62 876 if (mei_connect(dev, cl)) {
fb7d879f
OW
877 cl->status = -ENODEV;
878 cb_pos->information = 0;
879 list_del(&cb_pos->cb_list);
880 return -ENODEV;
881 } else {
882 list_move_tail(&cb_pos->cb_list,
883 &dev->ctrl_rd_list.mei_cb.cb_list);
884 cl->timer_count = MEI_CONNECT_TIMEOUT;
885 }
886 } else {
887 /* return the cancel routine */
888 list_del(&cb_pos->cb_list);
889 return -EBADMSG;
890 }
891
892 return 0;
893}
894
895/**
896 * _mei_irq_thread_cmpl - processes completed and no-iamthif operation.
897 *
898 * @dev: the device structure.
899 * @slots: free slots.
900 * @cb_pos: callback block.
901 * @cl: private data of the file object.
902 * @cmpl_list: complete list.
903 *
904 * returns 0, OK; otherwise, error.
905 */
906static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots,
907 struct mei_cl_cb *cb_pos,
908 struct mei_cl *cl,
909 struct mei_io_list *cmpl_list)
910{
911 struct mei_msg_hdr *mei_hdr;
912
913 if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
914 (cb_pos->request_buffer.size -
915 cb_pos->information))) {
916 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
917 mei_hdr->host_addr = cl->host_client_id;
918 mei_hdr->me_addr = cl->me_client_id;
919 mei_hdr->length = cb_pos->request_buffer.size -
920 cb_pos->information;
921 mei_hdr->msg_complete = 1;
922 mei_hdr->reserved = 0;
923 dev_dbg(&dev->pdev->dev, "cb_pos->request_buffer.size =%d"
924 "mei_hdr->msg_complete = %d\n",
925 cb_pos->request_buffer.size,
926 mei_hdr->msg_complete);
927 dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n",
928 cb_pos->information);
929 dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n",
930 mei_hdr->length);
7bdf72d3 931 *slots -= mei_data2slots(mei_hdr->length);
1ccb7b62 932 if (mei_write_message(dev, mei_hdr,
fb7d879f
OW
933 (unsigned char *)
934 (cb_pos->request_buffer.data +
935 cb_pos->information),
936 mei_hdr->length)) {
937 cl->status = -ENODEV;
938 list_move_tail(&cb_pos->cb_list,
939 &cmpl_list->mei_cb.cb_list);
940 return -ENODEV;
941 } else {
942 if (mei_flow_ctrl_reduce(dev, cl))
943 return -ENODEV;
944 cl->status = 0;
945 cb_pos->information += mei_hdr->length;
946 list_move_tail(&cb_pos->cb_list,
947 &dev->write_waiting_list.mei_cb.cb_list);
948 }
24aadc80 949 } else if (*slots == dev->hbuf_depth) {
fb7d879f
OW
950 /* buffer is still empty */
951 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
952 mei_hdr->host_addr = cl->host_client_id;
953 mei_hdr->me_addr = cl->me_client_id;
954 mei_hdr->length =
955 (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
956 mei_hdr->msg_complete = 0;
957 mei_hdr->reserved = 0;
7bdf72d3 958 *slots -= mei_data2slots(mei_hdr->length);
1ccb7b62 959 if (mei_write_message(dev, mei_hdr,
fb7d879f
OW
960 (unsigned char *)
961 (cb_pos->request_buffer.data +
962 cb_pos->information),
963 mei_hdr->length)) {
964 cl->status = -ENODEV;
965 list_move_tail(&cb_pos->cb_list,
966 &cmpl_list->mei_cb.cb_list);
967 return -ENODEV;
968 } else {
969 cb_pos->information += mei_hdr->length;
970 dev_dbg(&dev->pdev->dev,
971 "cb_pos->request_buffer.size =%d"
972 " mei_hdr->msg_complete = %d\n",
973 cb_pos->request_buffer.size,
974 mei_hdr->msg_complete);
975 dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n",
976 cb_pos->information);
977 dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n",
978 mei_hdr->length);
979 }
980 return -EMSGSIZE;
981 } else {
982 return -EBADMSG;
983 }
984
985 return 0;
986}
987
988/**
989 * _mei_irq_thread_cmpl_iamthif - processes completed iamthif operation.
990 *
991 * @dev: the device structure.
992 * @slots: free slots.
993 * @cb_pos: callback block.
994 * @cl: private data of the file object.
995 * @cmpl_list: complete list.
996 *
997 * returns 0, OK; otherwise, error.
998 */
999static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots,
1000 struct mei_cl_cb *cb_pos,
1001 struct mei_cl *cl,
1002 struct mei_io_list *cmpl_list)
1003{
1004 struct mei_msg_hdr *mei_hdr;
1005
1006 if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
1007 dev->iamthif_msg_buf_size -
1008 dev->iamthif_msg_buf_index)) {
1009 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
1010 mei_hdr->host_addr = cl->host_client_id;
1011 mei_hdr->me_addr = cl->me_client_id;
1012 mei_hdr->length = dev->iamthif_msg_buf_size -
1013 dev->iamthif_msg_buf_index;
1014 mei_hdr->msg_complete = 1;
1015 mei_hdr->reserved = 0;
1016
7bdf72d3 1017 *slots -= mei_data2slots(mei_hdr->length);
fb7d879f 1018
1ccb7b62 1019 if (mei_write_message(dev, mei_hdr,
fb7d879f
OW
1020 (dev->iamthif_msg_buf +
1021 dev->iamthif_msg_buf_index),
1022 mei_hdr->length)) {
1023 dev->iamthif_state = MEI_IAMTHIF_IDLE;
1024 cl->status = -ENODEV;
1025 list_del(&cb_pos->cb_list);
1026 return -ENODEV;
1027 } else {
1028 if (mei_flow_ctrl_reduce(dev, cl))
1029 return -ENODEV;
1030 dev->iamthif_msg_buf_index += mei_hdr->length;
1031 cb_pos->information = dev->iamthif_msg_buf_index;
1032 cl->status = 0;
1033 dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
eb9af0ac 1034 dev->iamthif_flow_control_pending = true;
fb7d879f
OW
1035 /* save iamthif cb sent to amthi client */
1036 dev->iamthif_current_cb = cb_pos;
1037 list_move_tail(&cb_pos->cb_list,
1038 &dev->write_waiting_list.mei_cb.cb_list);
1039
1040 }
24aadc80
TW
1041 } else if (*slots == dev->hbuf_depth) {
1042 /* buffer is still empty */
fb7d879f
OW
1043 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
1044 mei_hdr->host_addr = cl->host_client_id;
1045 mei_hdr->me_addr = cl->me_client_id;
1046 mei_hdr->length =
1047 (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
1048 mei_hdr->msg_complete = 0;
1049 mei_hdr->reserved = 0;
1050
7bdf72d3 1051 *slots -= mei_data2slots(mei_hdr->length);
fb7d879f 1052
1ccb7b62 1053 if (mei_write_message(dev, mei_hdr,
fb7d879f
OW
1054 (dev->iamthif_msg_buf +
1055 dev->iamthif_msg_buf_index),
1056 mei_hdr->length)) {
1057 cl->status = -ENODEV;
1058 list_del(&cb_pos->cb_list);
1059 } else {
1060 dev->iamthif_msg_buf_index += mei_hdr->length;
1061 }
1062 return -EMSGSIZE;
1063 } else {
1064 return -EBADMSG;
1065 }
1066
1067 return 0;
1068}
1069
1070/**
1071 * mei_irq_thread_read_handler - bottom half read routine after ISR to
1072 * handle the read processing.
1073 *
1074 * @cmpl_list: An instance of our list structure
1075 * @dev: the device structure
1076 * @slots: slots to read.
1077 *
1078 * returns 0 on success, <0 on failure.
1079 */
1080static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list,
1081 struct mei_device *dev,
1082 s32 *slots)
1083{
1084 struct mei_msg_hdr *mei_hdr;
1085 struct mei_cl *cl_pos = NULL;
1086 struct mei_cl *cl_next = NULL;
1087 int ret = 0;
1088
1089 if (!dev->rd_msg_hdr) {
1090 dev->rd_msg_hdr = mei_mecbrw_read(dev);
1091 dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
1092 (*slots)--;
1093 dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
1094 }
1095 mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr;
1096 dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length);
1097
1098 if (mei_hdr->reserved || !dev->rd_msg_hdr) {
1099 dev_dbg(&dev->pdev->dev, "corrupted message header.\n");
1100 ret = -EBADMSG;
1101 goto end;
1102 }
1103
1104 if (mei_hdr->host_addr || mei_hdr->me_addr) {
1105 list_for_each_entry_safe(cl_pos, cl_next,
1106 &dev->file_list, link) {
1107 dev_dbg(&dev->pdev->dev,
1108 "list_for_each_entry_safe read host"
1109 " client = %d, ME client = %d\n",
1110 cl_pos->host_client_id,
1111 cl_pos->me_client_id);
1112 if (cl_pos->host_client_id == mei_hdr->host_addr &&
1113 cl_pos->me_client_id == mei_hdr->me_addr)
1114 break;
1115 }
1116
1117 if (&cl_pos->link == &dev->file_list) {
1118 dev_dbg(&dev->pdev->dev, "corrupted message header\n");
1119 ret = -EBADMSG;
1120 goto end;
1121 }
1122 }
1123 if (((*slots) * sizeof(u32)) < mei_hdr->length) {
1124 dev_dbg(&dev->pdev->dev,
1125 "we can't read the message slots =%08x.\n",
1126 *slots);
1127 /* we can't read the message */
1128 ret = -ERANGE;
1129 goto end;
1130 }
1131
1132 /* decide where to read the message too */
1133 if (!mei_hdr->host_addr) {
1134 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n");
1135 mei_irq_thread_read_bus_message(dev, mei_hdr);
1136 dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n");
1137 } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
1138 (MEI_FILE_CONNECTED == dev->iamthif_cl.state) &&
1139 (dev->iamthif_state == MEI_IAMTHIF_READING)) {
1140 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
1141 dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n",
1142 mei_hdr->length);
1143 ret = mei_irq_thread_read_amthi_message(cmpl_list,
1144 dev, mei_hdr);
1145 if (ret)
1146 goto end;
1147
1148 } else {
1149 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n");
1150 ret = mei_irq_thread_read_client_message(cmpl_list,
1151 dev, mei_hdr);
1152 if (ret)
1153 goto end;
1154
1155 }
1156
1157 /* reset the number of slots and header */
1158 *slots = mei_count_full_read_slots(dev);
1159 dev->rd_msg_hdr = 0;
1160
1161 if (*slots == -EOVERFLOW) {
1162 /* overflow - reset */
1163 dev_dbg(&dev->pdev->dev, "resetting due to slots overflow.\n");
1164 /* set the event since message has been read */
1165 ret = -ERANGE;
1166 goto end;
1167 }
1168end:
1169 return ret;
1170}
1171
1172
1173/**
1174 * mei_irq_thread_write_handler - bottom half write routine after
1175 * ISR to handle the write processing.
1176 *
1177 * @cmpl_list: An instance of our list structure
1178 * @dev: the device structure
1179 * @slots: slots to write.
1180 *
1181 * returns 0 on success, <0 on failure.
1182 */
1183static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
1184 struct mei_device *dev,
1185 s32 *slots)
1186{
1187
1188 struct mei_cl *cl;
b7cd2d9f 1189 struct mei_cl_cb *pos = NULL, *next = NULL;
fb7d879f
OW
1190 struct mei_io_list *list;
1191 int ret;
1192
726917f0 1193 if (!mei_hbuf_is_empty(dev)) {
fb7d879f
OW
1194 dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
1195 return 0;
1196 }
726917f0 1197 *slots = mei_hbuf_empty_slots(dev);
7d5e0e59
TW
1198 if (*slots <= 0)
1199 return -EMSGSIZE;
1200
fb7d879f
OW
1201 /* complete all waiting for write CB */
1202 dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");
1203
1204 list = &dev->write_waiting_list;
b7cd2d9f
TW
1205 list_for_each_entry_safe(pos, next,
1206 &list->mei_cb.cb_list, cb_list) {
1207 cl = (struct mei_cl *)pos->file_private;
1208 if (cl == NULL)
1209 continue;
1210
1211 cl->status = 0;
1212 list_del(&pos->cb_list);
1213 if (MEI_WRITING == cl->writing_state &&
1214 (pos->major_file_operations == MEI_WRITE) &&
1215 (cl != &dev->iamthif_cl)) {
1216 dev_dbg(&dev->pdev->dev,
1217 "MEI WRITE COMPLETE\n");
1218 cl->writing_state = MEI_WRITE_COMPLETE;
1219 list_add_tail(&pos->cb_list,
1220 &cmpl_list->mei_cb.cb_list);
1221 }
1222 if (cl == &dev->iamthif_cl) {
1223 dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n");
1224 if (dev->iamthif_flow_control_pending) {
1225 ret = _mei_irq_thread_iamthif_read(
1226 dev, slots);
1227 if (ret)
1228 return ret;
fb7d879f 1229 }
fb7d879f
OW
1230 }
1231 }
1232
1233 if (dev->stop && !dev->wd_pending) {
eb9af0ac 1234 dev->wd_stopped = true;
fb7d879f
OW
1235 wake_up_interruptible(&dev->wait_stop_wd);
1236 return 0;
1237 }
1238
1239 if (dev->extra_write_index) {
1240 dev_dbg(&dev->pdev->dev, "extra_write_index =%d.\n",
1241 dev->extra_write_index);
1242 mei_write_message(dev,
1243 (struct mei_msg_hdr *) &dev->ext_msg_buf[0],
1244 (unsigned char *) &dev->ext_msg_buf[1],
1245 (dev->extra_write_index - 1) * sizeof(u32));
1246 *slots -= dev->extra_write_index;
1247 dev->extra_write_index = 0;
1248 }
1249 if (dev->mei_state == MEI_ENABLED) {
1250 if (dev->wd_pending &&
1251 mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
1252 if (mei_wd_send(dev))
1253 dev_dbg(&dev->pdev->dev, "wd send failed.\n");
1254 else
1255 if (mei_flow_ctrl_reduce(dev, &dev->wd_cl))
1256 return -ENODEV;
1257
eb9af0ac 1258 dev->wd_pending = false;
fb7d879f 1259
d242a0af 1260 if (dev->wd_timeout)
7bdf72d3 1261 *slots -= mei_data2slots(MEI_START_WD_DATA_SIZE);
d242a0af 1262 else
7bdf72d3 1263 *slots -= mei_data2slots(MEI_START_WD_DATA_SIZE);
fb7d879f
OW
1264 }
1265 }
1266 if (dev->stop)
dc91e2f1 1267 return -ENODEV;
fb7d879f
OW
1268
1269 /* complete control write list CB */
c8372094 1270 dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
b7cd2d9f 1271 list_for_each_entry_safe(pos, next,
fb7d879f 1272 &dev->ctrl_wr_list.mei_cb.cb_list, cb_list) {
b7cd2d9f 1273 cl = (struct mei_cl *) pos->file_private;
c8372094 1274 if (!cl) {
b7cd2d9f 1275 list_del(&pos->cb_list);
c8372094
TW
1276 return -ENODEV;
1277 }
b7cd2d9f 1278 switch (pos->major_file_operations) {
c8372094
TW
1279 case MEI_CLOSE:
1280 /* send disconnect message */
b7cd2d9f 1281 ret = _mei_irq_thread_close(dev, slots, pos, cl, cmpl_list);
c8372094
TW
1282 if (ret)
1283 return ret;
fb7d879f 1284
c8372094
TW
1285 break;
1286 case MEI_READ:
1287 /* send flow control message */
b7cd2d9f 1288 ret = _mei_irq_thread_read(dev, slots, pos, cl, cmpl_list);
c8372094
TW
1289 if (ret)
1290 return ret;
fb7d879f 1291
c8372094
TW
1292 break;
1293 case MEI_IOCTL:
1294 /* connect message */
e8cd29d8 1295 if (mei_other_client_is_connecting(dev, cl))
c8372094 1296 continue;
b7cd2d9f 1297 ret = _mei_irq_thread_ioctl(dev, slots, pos, cl, cmpl_list);
c8372094
TW
1298 if (ret)
1299 return ret;
fb7d879f 1300
c8372094 1301 break;
fb7d879f 1302
c8372094
TW
1303 default:
1304 BUG();
fb7d879f 1305 }
c8372094 1306
fb7d879f
OW
1307 }
1308 /* complete write list CB */
b7cd2d9f
TW
1309 dev_dbg(&dev->pdev->dev, "complete write list cb.\n");
1310 list_for_each_entry_safe(pos, next,
1311 &dev->write_list.mei_cb.cb_list, cb_list) {
1312 cl = (struct mei_cl *)pos->file_private;
1313 if (cl == NULL)
1314 continue;
1315
1316 if (cl != &dev->iamthif_cl) {
d2041158 1317 if (mei_flow_ctrl_creds(dev, cl) <= 0) {
b7cd2d9f
TW
1318 dev_dbg(&dev->pdev->dev,
1319 "No flow control"
1320 " credentials for client"
1321 " %d, not sending.\n",
1322 cl->host_client_id);
1323 continue;
1324 }
1325 ret = _mei_irq_thread_cmpl(dev, slots,
1326 pos,
1327 cl, cmpl_list);
1328 if (ret)
1329 return ret;
fb7d879f 1330
b7cd2d9f
TW
1331 } else if (cl == &dev->iamthif_cl) {
1332 /* IAMTHIF IOCTL */
1333 dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n");
d2041158 1334 if (mei_flow_ctrl_creds(dev, cl) <= 0) {
b7cd2d9f
TW
1335 dev_dbg(&dev->pdev->dev,
1336 "No flow control"
1337 " credentials for amthi"
1338 " client %d.\n",
1339 cl->host_client_id);
1340 continue;
fb7d879f 1341 }
b7cd2d9f
TW
1342 ret = _mei_irq_thread_cmpl_iamthif(dev,
1343 slots,
1344 pos,
1345 cl,
1346 cmpl_list);
1347 if (ret)
1348 return ret;
fb7d879f
OW
1349
1350 }
b7cd2d9f 1351
fb7d879f
OW
1352 }
1353 return 0;
1354}
1355
1356
1357
1358/**
1359 * mei_timer - timer function.
1360 *
1361 * @work: pointer to the work_struct structure
1362 *
1363 * NOTE: This function is called by timer interrupt work
1364 */
a61c6530 1365void mei_timer(struct work_struct *work)
fb7d879f
OW
1366{
1367 unsigned long timeout;
1368 struct mei_cl *cl_pos = NULL;
1369 struct mei_cl *cl_next = NULL;
1370 struct list_head *amthi_complete_list = NULL;
1371 struct mei_cl_cb *cb_pos = NULL;
1372 struct mei_cl_cb *cb_next = NULL;
1373
1374 struct mei_device *dev = container_of(work,
a61c6530 1375 struct mei_device, timer_work.work);
fb7d879f
OW
1376
1377
1378 mutex_lock(&dev->device_lock);
1379 if (dev->mei_state != MEI_ENABLED) {
1380 if (dev->mei_state == MEI_INIT_CLIENTS) {
1381 if (dev->init_clients_timer) {
1382 if (--dev->init_clients_timer == 0) {
1383 dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
1384 dev->init_clients_state);
1385 mei_reset(dev, 1);
1386 }
1387 }
1388 }
1389 goto out;
1390 }
1391 /*** connect/disconnect timeouts ***/
1392 list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
1393 if (cl_pos->timer_count) {
1394 if (--cl_pos->timer_count == 0) {
1395 dev_dbg(&dev->pdev->dev, "HECI reset due to connect/disconnect timeout.\n");
1396 mei_reset(dev, 1);
1397 goto out;
1398 }
1399 }
1400 }
1401
fb7d879f
OW
1402 if (dev->iamthif_stall_timer) {
1403 if (--dev->iamthif_stall_timer == 0) {
32de21f7 1404 dev_dbg(&dev->pdev->dev, "resetting because of hang to amthi.\n");
fb7d879f
OW
1405 mei_reset(dev, 1);
1406 dev->iamthif_msg_buf_size = 0;
1407 dev->iamthif_msg_buf_index = 0;
eb9af0ac
TW
1408 dev->iamthif_canceled = false;
1409 dev->iamthif_ioctl = true;
fb7d879f
OW
1410 dev->iamthif_state = MEI_IAMTHIF_IDLE;
1411 dev->iamthif_timer = 0;
1412
1413 if (dev->iamthif_current_cb)
1414 mei_free_cb_private(dev->iamthif_current_cb);
1415
1416 dev->iamthif_file_object = NULL;
1417 dev->iamthif_current_cb = NULL;
c95efb74 1418 mei_run_next_iamthif_cmd(dev);
fb7d879f
OW
1419 }
1420 }
1421
1422 if (dev->iamthif_timer) {
1423
1424 timeout = dev->iamthif_timer +
1425 msecs_to_jiffies(IAMTHIF_READ_TIMER);
1426
1427 dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
1428 dev->iamthif_timer);
1429 dev_dbg(&dev->pdev->dev, "timeout = %ld\n", timeout);
1430 dev_dbg(&dev->pdev->dev, "jiffies = %ld\n", jiffies);
1431 if (time_after(jiffies, timeout)) {
1432 /*
1433 * User didn't read the AMTHI data on time (15sec)
1434 * freeing AMTHI for other requests
1435 */
1436
1437 dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n");
1438
1439 amthi_complete_list = &dev->amthi_read_complete_list.
1440 mei_cb.cb_list;
1441
b7cd2d9f 1442 list_for_each_entry_safe(cb_pos, cb_next, amthi_complete_list, cb_list) {
fb7d879f 1443
b7cd2d9f 1444 cl_pos = cb_pos->file_object->private_data;
fb7d879f 1445
b7cd2d9f
TW
1446 /* Finding the AMTHI entry. */
1447 if (cl_pos == &dev->iamthif_cl)
1448 list_del(&cb_pos->cb_list);
fb7d879f
OW
1449 }
1450 if (dev->iamthif_current_cb)
1451 mei_free_cb_private(dev->iamthif_current_cb);
1452
1453 dev->iamthif_file_object->private_data = NULL;
1454 dev->iamthif_file_object = NULL;
1455 dev->iamthif_current_cb = NULL;
1456 dev->iamthif_timer = 0;
c95efb74 1457 mei_run_next_iamthif_cmd(dev);
fb7d879f
OW
1458
1459 }
1460 }
1461out:
441ab50f
TW
1462 schedule_delayed_work(&dev->timer_work, 2 * HZ);
1463 mutex_unlock(&dev->device_lock);
fb7d879f
OW
1464}
1465
1466/**
1467 * mei_interrupt_thread_handler - function called after ISR to handle the interrupt
1468 * processing.
1469 *
1470 * @irq: The irq number
1471 * @dev_id: pointer to the device structure
1472 *
1473 * returns irqreturn_t
1474 *
1475 */
1476irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
1477{
1478 struct mei_device *dev = (struct mei_device *) dev_id;
1479 struct mei_io_list complete_list;
1480 struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
1481 struct mei_cl *cl;
1482 s32 slots;
1483 int rets;
1484 bool bus_message_received;
1485
1486
1487 dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
1488 /* initialize our complete list */
1489 mutex_lock(&dev->device_lock);
0288c7c9 1490 mei_io_list_init(&complete_list);
fb7d879f 1491 dev->host_hw_state = mei_hcsr_read(dev);
4f61a7ad
TW
1492
1493 /* Ack the interrupt here
5f9092f3 1494 * In case of MSI we don't go through the quick handler */
4f61a7ad
TW
1495 if (pci_dev_msi_enabled(dev->pdev))
1496 mei_reg_write(dev, H_CSR, dev->host_hw_state);
1497
fb7d879f
OW
1498 dev->me_hw_state = mei_mecsr_read(dev);
1499
1500 /* check if ME wants a reset */
1501 if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
1502 dev->mei_state != MEI_RESETING &&
1503 dev->mei_state != MEI_INITIALIZING) {
1504 dev_dbg(&dev->pdev->dev, "FW not ready.\n");
1505 mei_reset(dev, 1);
1506 mutex_unlock(&dev->device_lock);
1507 return IRQ_HANDLED;
1508 }
1509
1510 /* check if we need to start the dev */
1511 if ((dev->host_hw_state & H_RDY) == 0) {
1512 if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) {
1513 dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
1514 dev->host_hw_state |= (H_IE | H_IG | H_RDY);
1515 mei_hcsr_set(dev);
1516 dev->mei_state = MEI_INIT_CLIENTS;
1517 dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
1518 /* link is established
1519 * start sending messages.
1520 */
c95efb74 1521 mei_host_start_message(dev);
fb7d879f
OW
1522 mutex_unlock(&dev->device_lock);
1523 return IRQ_HANDLED;
1524 } else {
1525 dev_dbg(&dev->pdev->dev, "FW not ready.\n");
1526 mutex_unlock(&dev->device_lock);
1527 return IRQ_HANDLED;
1528 }
1529 }
5f9092f3 1530 /* check slots available for reading */
fb7d879f
OW
1531 slots = mei_count_full_read_slots(dev);
1532 dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n",
1533 slots, dev->extra_write_index);
1534 while (slots > 0 && !dev->extra_write_index) {
1535 dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n",
1536 slots, dev->extra_write_index);
1537 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n");
1538 rets = mei_irq_thread_read_handler(&complete_list, dev, &slots);
1539 if (rets)
1540 goto end;
1541 }
1542 rets = mei_irq_thread_write_handler(&complete_list, dev, &slots);
1543end:
1544 dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
1545 dev->host_hw_state = mei_hcsr_read(dev);
726917f0 1546 dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev);
fb7d879f
OW
1547
1548 bus_message_received = false;
1549 if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
1550 dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
1551 bus_message_received = true;
1552 }
1553 mutex_unlock(&dev->device_lock);
1554 if (bus_message_received) {
1555 dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
1556 wake_up_interruptible(&dev->wait_recvd_msg);
1557 bus_message_received = false;
1558 }
c8372094 1559 if (list_empty(&complete_list.mei_cb.cb_list))
fb7d879f
OW
1560 return IRQ_HANDLED;
1561
1562
1563 list_for_each_entry_safe(cb_pos, cb_next,
1564 &complete_list.mei_cb.cb_list, cb_list) {
1565 cl = (struct mei_cl *)cb_pos->file_private;
1566 list_del(&cb_pos->cb_list);
1567 if (cl) {
1568 if (cl != &dev->iamthif_cl) {
1569 dev_dbg(&dev->pdev->dev, "completing call back.\n");
1570 _mei_cmpl(cl, cb_pos);
1571 cb_pos = NULL;
1572 } else if (cl == &dev->iamthif_cl) {
1573 _mei_cmpl_iamthif(dev, cb_pos);
1574 }
1575 }
1576 }
1577 return IRQ_HANDLED;
1578}
This page took 0.312827 seconds and 5 git commands to generate.