diff options
Diffstat (limited to 'drivers/misc/mei/interrupt.c')
-rw-r--r-- | drivers/misc/mei/interrupt.c | 656 |
1 files changed, 43 insertions, 613 deletions
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 04fa2134615e..3535b2676c97 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c | |||
@@ -21,41 +21,21 @@ | |||
21 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
22 | #include <linux/jiffies.h> | 22 | #include <linux/jiffies.h> |
23 | 23 | ||
24 | #include "mei_dev.h" | ||
25 | #include <linux/mei.h> | 24 | #include <linux/mei.h> |
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 | */ | ||
38 | irqreturn_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 | 25 | ||
46 | /* clear H_IS bit in H_CSR */ | 26 | #include "mei_dev.h" |
47 | mei_reg_write(dev, H_CSR, csr_reg); | 27 | #include "hbm.h" |
28 | #include "hw-me.h" | ||
29 | #include "client.h" | ||
48 | 30 | ||
49 | return IRQ_WAKE_THREAD; | ||
50 | } | ||
51 | 31 | ||
52 | /** | 32 | /** |
53 | * _mei_cmpl - processes completed operation. | 33 | * mei_complete_handler - processes completed operation. |
54 | * | 34 | * |
55 | * @cl: private data of the file object. | 35 | * @cl: private data of the file object. |
56 | * @cb_pos: callback block. | 36 | * @cb_pos: callback block. |
57 | */ | 37 | */ |
58 | static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos) | 38 | void mei_irq_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb_pos) |
59 | { | 39 | { |
60 | if (cb_pos->fop_type == MEI_FOP_WRITE) { | 40 | if (cb_pos->fop_type == MEI_FOP_WRITE) { |
61 | mei_io_cb_free(cb_pos); | 41 | mei_io_cb_free(cb_pos); |
@@ -150,8 +130,8 @@ quit: | |||
150 | dev_dbg(&dev->pdev->dev, "message read\n"); | 130 | dev_dbg(&dev->pdev->dev, "message read\n"); |
151 | if (!buffer) { | 131 | if (!buffer) { |
152 | mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length); | 132 | mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length); |
153 | dev_dbg(&dev->pdev->dev, "discarding message, header =%08x.\n", | 133 | dev_dbg(&dev->pdev->dev, "discarding message " MEI_HDR_FMT "\n", |
154 | *(u32 *) dev->rd_msg_buf); | 134 | MEI_HDR_PRM(mei_hdr)); |
155 | } | 135 | } |
156 | 136 | ||
157 | return 0; | 137 | return 0; |
@@ -179,7 +159,7 @@ static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, | |||
179 | 159 | ||
180 | *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); | 160 | *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); |
181 | 161 | ||
182 | if (mei_disconnect(dev, cl)) { | 162 | if (mei_hbm_cl_disconnect_req(dev, cl)) { |
183 | cl->status = 0; | 163 | cl->status = 0; |
184 | cb_pos->buf_idx = 0; | 164 | cb_pos->buf_idx = 0; |
185 | list_move_tail(&cb_pos->list, &cmpl_list->list); | 165 | list_move_tail(&cb_pos->list, &cmpl_list->list); |
@@ -195,440 +175,6 @@ static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, | |||
195 | return 0; | 175 | return 0; |
196 | } | 176 | } |
197 | 177 | ||
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 | */ | ||
206 | static 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 | */ | ||
233 | static void mei_client_connect_response(struct mei_device *dev, | ||
234 | struct hbm_client_connect_response *rs) | ||
235 | { | ||
236 | |||
237 | struct mei_cl *cl; | ||
238 | struct mei_cl_cb *pos = NULL, *next = NULL; | ||
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)) { | ||
252 | dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n"); | ||
253 | mei_watchdog_register(dev); | ||
254 | |||
255 | return; | ||
256 | } | ||
257 | |||
258 | if (is_treat_specially_client(&(dev->iamthif_cl), rs)) { | ||
259 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | ||
260 | return; | ||
261 | } | ||
262 | list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { | ||
263 | |||
264 | cl = pos->cl; | ||
265 | if (!cl) { | ||
266 | list_del(&pos->list); | ||
267 | return; | ||
268 | } | ||
269 | if (pos->fop_type == MEI_FOP_IOCTL) { | ||
270 | if (is_treat_specially_client(cl, rs)) { | ||
271 | list_del(&pos->list); | ||
272 | cl->status = 0; | ||
273 | cl->timer_count = 0; | ||
274 | break; | ||
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 | */ | ||
286 | static void mei_client_disconnect_response(struct mei_device *dev, | ||
287 | struct hbm_client_connect_response *rs) | ||
288 | { | ||
289 | struct mei_cl *cl; | ||
290 | struct mei_cl_cb *pos = NULL, *next = NULL; | ||
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 | |||
301 | list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { | ||
302 | cl = pos->cl; | ||
303 | |||
304 | if (!cl) { | ||
305 | list_del(&pos->list); | ||
306 | return; | ||
307 | } | ||
308 | |||
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) { | ||
312 | |||
313 | list_del(&pos->list); | ||
314 | if (!rs->status) | ||
315 | cl->state = MEI_FILE_DISCONNECTED; | ||
316 | |||
317 | cl->status = 0; | ||
318 | cl->timer_count = 0; | ||
319 | break; | ||
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 | */ | ||
332 | static 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 | */ | ||
344 | static 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 | |||
350 | for (i = 0; i < dev->me_clients_num; i++) { | ||
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 | */ | ||
372 | static 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 | */ | ||
414 | static int same_disconn_addr(struct mei_cl *cl, | ||
415 | struct hbm_client_connect_request *req) | ||
416 | { | ||
417 | return (cl->host_client_id == req->host_addr && | ||
418 | cl->me_client_id == req->me_addr); | ||
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 | */ | ||
427 | static void mei_client_disconnect_request(struct mei_device *dev, | ||
428 | struct hbm_client_connect_request *disconnect_req) | ||
429 | { | ||
430 | struct hbm_client_connect_response *disconnect_res; | ||
431 | struct mei_cl *pos, *next; | ||
432 | const size_t len = sizeof(struct hbm_client_connect_response); | ||
433 | |||
434 | list_for_each_entry_safe(pos, next, &dev->file_list, link) { | ||
435 | if (same_disconn_addr(pos, disconnect_req)) { | ||
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); | ||
439 | pos->state = MEI_FILE_DISCONNECTED; | ||
440 | pos->timer_count = 0; | ||
441 | if (pos == &dev->wd_cl) | ||
442 | dev->wd_pending = false; | ||
443 | else if (pos == &dev->iamthif_cl) | ||
444 | dev->iamthif_timer = 0; | ||
445 | |||
446 | /* prepare disconnect response */ | ||
447 | (void)mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len); | ||
448 | disconnect_res = | ||
449 | (struct hbm_client_connect_response *) | ||
450 | &dev->wr_ext_msg.data; | ||
451 | disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD; | ||
452 | disconnect_res->host_addr = pos->host_client_id; | ||
453 | disconnect_res->me_addr = pos->me_client_id; | ||
454 | disconnect_res->status = 0; | ||
455 | break; | ||
456 | } | ||
457 | } | ||
458 | } | ||
459 | |||
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 | */ | ||
467 | static void mei_irq_thread_read_bus_message(struct mei_device *dev, | ||
468 | struct mei_msg_hdr *mei_hdr) | ||
469 | { | ||
470 | struct mei_bus_message *mei_msg; | ||
471 | struct mei_me_client *me_client; | ||
472 | struct hbm_host_version_response *version_res; | ||
473 | struct hbm_client_connect_response *connect_res; | ||
474 | struct hbm_client_connect_response *disconnect_res; | ||
475 | struct hbm_client_connect_request *disconnect_req; | ||
476 | struct hbm_flow_control *flow_control; | ||
477 | struct hbm_props_response *props_res; | ||
478 | struct hbm_host_enum_response *enum_res; | ||
479 | struct hbm_host_stop_request *stop_req; | ||
480 | |||
481 | /* read the message to our buffer */ | ||
482 | BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf)); | ||
483 | mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length); | ||
484 | mei_msg = (struct mei_bus_message *)dev->rd_msg_buf; | ||
485 | |||
486 | switch (mei_msg->hbm_cmd) { | ||
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; | ||
492 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && | ||
493 | dev->init_clients_state == MEI_START_MESSAGE) { | ||
494 | dev->init_clients_timer = 0; | ||
495 | mei_host_enum_clients_message(dev); | ||
496 | } else { | ||
497 | dev->recvd_msg = false; | ||
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 { | ||
503 | u32 *buf = dev->wr_msg_buf; | ||
504 | const size_t len = sizeof(struct hbm_host_stop_request); | ||
505 | |||
506 | dev->version = version_res->me_max_version; | ||
507 | |||
508 | /* send stop message */ | ||
509 | mei_hdr = mei_hbm_hdr(&buf[0], len); | ||
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 | |||
515 | mei_write_message(dev, mei_hdr, | ||
516 | (unsigned char *)stop_req, len); | ||
517 | dev_dbg(&dev->pdev->dev, "version mismatch.\n"); | ||
518 | return; | ||
519 | } | ||
520 | |||
521 | dev->recvd_msg = true; | ||
522 | dev_dbg(&dev->pdev->dev, "host start response message received.\n"); | ||
523 | break; | ||
524 | |||
525 | case CLIENT_CONNECT_RES_CMD: | ||
526 | connect_res = (struct hbm_client_connect_response *) mei_msg; | ||
527 | mei_client_connect_response(dev, connect_res); | ||
528 | dev_dbg(&dev->pdev->dev, "client connect response message received.\n"); | ||
529 | wake_up(&dev->wait_recvd_msg); | ||
530 | break; | ||
531 | |||
532 | case CLIENT_DISCONNECT_RES_CMD: | ||
533 | disconnect_res = (struct hbm_client_connect_response *) mei_msg; | ||
534 | mei_client_disconnect_response(dev, disconnect_res); | ||
535 | dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n"); | ||
536 | wake_up(&dev->wait_recvd_msg); | ||
537 | break; | ||
538 | |||
539 | case MEI_FLOW_CONTROL_CMD: | ||
540 | flow_control = (struct hbm_flow_control *) mei_msg; | ||
541 | mei_client_flow_control_response(dev, flow_control); | ||
542 | dev_dbg(&dev->pdev->dev, "client flow control response message received.\n"); | ||
543 | break; | ||
544 | |||
545 | case HOST_CLIENT_PROPERTIES_RES_CMD: | ||
546 | props_res = (struct hbm_props_response *)mei_msg; | ||
547 | me_client = &dev->me_clients[dev->me_client_presentation_num]; | ||
548 | |||
549 | if (props_res->status || !dev->me_clients) { | ||
550 | dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n"); | ||
551 | mei_reset(dev, 1); | ||
552 | return; | ||
553 | } | ||
554 | |||
555 | if (me_client->client_id != props_res->address) { | ||
556 | dev_err(&dev->pdev->dev, | ||
557 | "Host client properties reply mismatch\n"); | ||
558 | mei_reset(dev, 1); | ||
559 | |||
560 | return; | ||
561 | } | ||
562 | |||
563 | if (dev->dev_state != MEI_DEV_INIT_CLIENTS || | ||
564 | dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) { | ||
565 | dev_err(&dev->pdev->dev, | ||
566 | "Unexpected client properties reply\n"); | ||
567 | mei_reset(dev, 1); | ||
568 | |||
569 | return; | ||
570 | } | ||
571 | |||
572 | me_client->props = props_res->client_properties; | ||
573 | dev->me_client_index++; | ||
574 | dev->me_client_presentation_num++; | ||
575 | |||
576 | mei_host_client_enumerate(dev); | ||
577 | |||
578 | break; | ||
579 | |||
580 | case HOST_ENUM_RES_CMD: | ||
581 | enum_res = (struct hbm_host_enum_response *) mei_msg; | ||
582 | memcpy(dev->me_clients_map, enum_res->valid_addresses, 32); | ||
583 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && | ||
584 | dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) { | ||
585 | dev->init_clients_timer = 0; | ||
586 | dev->me_client_presentation_num = 0; | ||
587 | dev->me_client_index = 0; | ||
588 | mei_allocate_me_clients_storage(dev); | ||
589 | dev->init_clients_state = | ||
590 | MEI_CLIENT_PROPERTIES_MESSAGE; | ||
591 | |||
592 | mei_host_client_enumerate(dev); | ||
593 | } else { | ||
594 | dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n"); | ||
595 | mei_reset(dev, 1); | ||
596 | return; | ||
597 | } | ||
598 | break; | ||
599 | |||
600 | case HOST_STOP_RES_CMD: | ||
601 | dev->dev_state = MEI_DEV_DISABLED; | ||
602 | dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n"); | ||
603 | mei_reset(dev, 1); | ||
604 | break; | ||
605 | |||
606 | case CLIENT_DISCONNECT_REQ_CMD: | ||
607 | /* search for client */ | ||
608 | disconnect_req = (struct hbm_client_connect_request *)mei_msg; | ||
609 | mei_client_disconnect_request(dev, disconnect_req); | ||
610 | break; | ||
611 | |||
612 | case ME_STOP_REQ_CMD: | ||
613 | { | ||
614 | /* prepare stop request: sent in next interrupt event */ | ||
615 | |||
616 | const size_t len = sizeof(struct hbm_host_stop_request); | ||
617 | |||
618 | mei_hdr = mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len); | ||
619 | stop_req = (struct hbm_host_stop_request *)&dev->wr_ext_msg.data; | ||
620 | memset(stop_req, 0, len); | ||
621 | stop_req->hbm_cmd = HOST_STOP_REQ_CMD; | ||
622 | stop_req->reason = DRIVER_STOP_REQUEST; | ||
623 | break; | ||
624 | } | ||
625 | default: | ||
626 | BUG(); | ||
627 | break; | ||
628 | |||
629 | } | ||
630 | } | ||
631 | |||
632 | 178 | ||
633 | /** | 179 | /** |
634 | * _mei_hb_read - processes read related operation. | 180 | * _mei_hb_read - processes read related operation. |
@@ -655,7 +201,7 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, | |||
655 | 201 | ||
656 | *slots -= mei_data2slots(sizeof(struct hbm_flow_control)); | 202 | *slots -= mei_data2slots(sizeof(struct hbm_flow_control)); |
657 | 203 | ||
658 | if (mei_send_flow_control(dev, cl)) { | 204 | if (mei_hbm_cl_flow_control_req(dev, cl)) { |
659 | cl->status = -ENODEV; | 205 | cl->status = -ENODEV; |
660 | cb_pos->buf_idx = 0; | 206 | cb_pos->buf_idx = 0; |
661 | list_move_tail(&cb_pos->list, &cmpl_list->list); | 207 | list_move_tail(&cb_pos->list, &cmpl_list->list); |
@@ -691,8 +237,8 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, | |||
691 | } | 237 | } |
692 | 238 | ||
693 | cl->state = MEI_FILE_CONNECTING; | 239 | cl->state = MEI_FILE_CONNECTING; |
694 | *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); | 240 | *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); |
695 | if (mei_connect(dev, cl)) { | 241 | if (mei_hbm_cl_connect_req(dev, cl)) { |
696 | cl->status = -ENODEV; | 242 | cl->status = -ENODEV; |
697 | cb_pos->buf_idx = 0; | 243 | cb_pos->buf_idx = 0; |
698 | list_del(&cb_pos->list); | 244 | list_del(&cb_pos->list); |
@@ -717,25 +263,24 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, | |||
717 | static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots, | 263 | static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots, |
718 | struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list) | 264 | struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list) |
719 | { | 265 | { |
720 | struct mei_msg_hdr *mei_hdr; | 266 | struct mei_msg_hdr mei_hdr; |
721 | struct mei_cl *cl = cb->cl; | 267 | struct mei_cl *cl = cb->cl; |
722 | size_t len = cb->request_buffer.size - cb->buf_idx; | 268 | size_t len = cb->request_buffer.size - cb->buf_idx; |
723 | size_t msg_slots = mei_data2slots(len); | 269 | size_t msg_slots = mei_data2slots(len); |
724 | 270 | ||
725 | mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; | 271 | mei_hdr.host_addr = cl->host_client_id; |
726 | mei_hdr->host_addr = cl->host_client_id; | 272 | mei_hdr.me_addr = cl->me_client_id; |
727 | mei_hdr->me_addr = cl->me_client_id; | 273 | mei_hdr.reserved = 0; |
728 | mei_hdr->reserved = 0; | ||
729 | 274 | ||
730 | if (*slots >= msg_slots) { | 275 | if (*slots >= msg_slots) { |
731 | mei_hdr->length = len; | 276 | mei_hdr.length = len; |
732 | mei_hdr->msg_complete = 1; | 277 | mei_hdr.msg_complete = 1; |
733 | /* Split the message only if we can write the whole host buffer */ | 278 | /* Split the message only if we can write the whole host buffer */ |
734 | } else if (*slots == dev->hbuf_depth) { | 279 | } else if (*slots == dev->hbuf_depth) { |
735 | msg_slots = *slots; | 280 | msg_slots = *slots; |
736 | len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); | 281 | len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); |
737 | mei_hdr->length = len; | 282 | mei_hdr.length = len; |
738 | mei_hdr->msg_complete = 0; | 283 | mei_hdr.msg_complete = 0; |
739 | } else { | 284 | } else { |
740 | /* wait for next time the host buffer is empty */ | 285 | /* wait for next time the host buffer is empty */ |
741 | return 0; | 286 | return 0; |
@@ -743,23 +288,22 @@ static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots, | |||
743 | 288 | ||
744 | dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n", | 289 | dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n", |
745 | cb->request_buffer.size, cb->buf_idx); | 290 | cb->request_buffer.size, cb->buf_idx); |
746 | dev_dbg(&dev->pdev->dev, "msg: len = %d complete = %d\n", | 291 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr)); |
747 | mei_hdr->length, mei_hdr->msg_complete); | ||
748 | 292 | ||
749 | *slots -= msg_slots; | 293 | *slots -= msg_slots; |
750 | if (mei_write_message(dev, mei_hdr, | 294 | if (mei_write_message(dev, &mei_hdr, |
751 | cb->request_buffer.data + cb->buf_idx, len)) { | 295 | cb->request_buffer.data + cb->buf_idx)) { |
752 | cl->status = -ENODEV; | 296 | cl->status = -ENODEV; |
753 | list_move_tail(&cb->list, &cmpl_list->list); | 297 | list_move_tail(&cb->list, &cmpl_list->list); |
754 | return -ENODEV; | 298 | return -ENODEV; |
755 | } | 299 | } |
756 | 300 | ||
757 | if (mei_flow_ctrl_reduce(dev, cl)) | 301 | if (mei_cl_flow_ctrl_reduce(cl)) |
758 | return -ENODEV; | 302 | return -ENODEV; |
759 | 303 | ||
760 | cl->status = 0; | 304 | cl->status = 0; |
761 | cb->buf_idx += mei_hdr->length; | 305 | cb->buf_idx += mei_hdr.length; |
762 | if (mei_hdr->msg_complete) | 306 | if (mei_hdr.msg_complete) |
763 | list_move_tail(&cb->list, &dev->write_waiting_list.list); | 307 | list_move_tail(&cb->list, &dev->write_waiting_list.list); |
764 | 308 | ||
765 | return 0; | 309 | return 0; |
@@ -769,15 +313,14 @@ static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots, | |||
769 | * mei_irq_thread_read_handler - bottom half read routine after ISR to | 313 | * mei_irq_thread_read_handler - bottom half read routine after ISR to |
770 | * handle the read processing. | 314 | * handle the read processing. |
771 | * | 315 | * |
772 | * @cmpl_list: An instance of our list structure | ||
773 | * @dev: the device structure | 316 | * @dev: the device structure |
317 | * @cmpl_list: An instance of our list structure | ||
774 | * @slots: slots to read. | 318 | * @slots: slots to read. |
775 | * | 319 | * |
776 | * returns 0 on success, <0 on failure. | 320 | * returns 0 on success, <0 on failure. |
777 | */ | 321 | */ |
778 | static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list, | 322 | int mei_irq_read_handler(struct mei_device *dev, |
779 | struct mei_device *dev, | 323 | struct mei_cl_cb *cmpl_list, s32 *slots) |
780 | s32 *slots) | ||
781 | { | 324 | { |
782 | struct mei_msg_hdr *mei_hdr; | 325 | struct mei_msg_hdr *mei_hdr; |
783 | struct mei_cl *cl_pos = NULL; | 326 | struct mei_cl *cl_pos = NULL; |
@@ -785,13 +328,13 @@ static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list, | |||
785 | int ret = 0; | 328 | int ret = 0; |
786 | 329 | ||
787 | if (!dev->rd_msg_hdr) { | 330 | if (!dev->rd_msg_hdr) { |
788 | dev->rd_msg_hdr = mei_mecbrw_read(dev); | 331 | dev->rd_msg_hdr = mei_read_hdr(dev); |
789 | dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); | 332 | dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); |
790 | (*slots)--; | 333 | (*slots)--; |
791 | dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); | 334 | dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); |
792 | } | 335 | } |
793 | mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr; | 336 | mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr; |
794 | dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length); | 337 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); |
795 | 338 | ||
796 | if (mei_hdr->reserved || !dev->rd_msg_hdr) { | 339 | if (mei_hdr->reserved || !dev->rd_msg_hdr) { |
797 | dev_dbg(&dev->pdev->dev, "corrupted message header.\n"); | 340 | dev_dbg(&dev->pdev->dev, "corrupted message header.\n"); |
@@ -830,19 +373,18 @@ static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list, | |||
830 | /* decide where to read the message too */ | 373 | /* decide where to read the message too */ |
831 | if (!mei_hdr->host_addr) { | 374 | if (!mei_hdr->host_addr) { |
832 | dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n"); | 375 | dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n"); |
833 | mei_irq_thread_read_bus_message(dev, mei_hdr); | 376 | mei_hbm_dispatch(dev, mei_hdr); |
834 | dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n"); | 377 | dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n"); |
835 | } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && | 378 | } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && |
836 | (MEI_FILE_CONNECTED == dev->iamthif_cl.state) && | 379 | (MEI_FILE_CONNECTED == dev->iamthif_cl.state) && |
837 | (dev->iamthif_state == MEI_IAMTHIF_READING)) { | 380 | (dev->iamthif_state == MEI_IAMTHIF_READING)) { |
838 | dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n"); | 381 | dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n"); |
839 | dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", | 382 | |
840 | mei_hdr->length); | 383 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); |
841 | 384 | ||
842 | ret = mei_amthif_irq_read_message(cmpl_list, dev, mei_hdr); | 385 | ret = mei_amthif_irq_read_message(cmpl_list, dev, mei_hdr); |
843 | if (ret) | 386 | if (ret) |
844 | goto end; | 387 | goto end; |
845 | |||
846 | } else { | 388 | } else { |
847 | dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n"); | 389 | dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n"); |
848 | ret = mei_irq_thread_read_client_message(cmpl_list, | 390 | ret = mei_irq_thread_read_client_message(cmpl_list, |
@@ -869,15 +411,15 @@ end: | |||
869 | 411 | ||
870 | 412 | ||
871 | /** | 413 | /** |
872 | * mei_irq_thread_write_handler - bottom half write routine after | 414 | * mei_irq_write_handler - dispatch write requests |
873 | * ISR to handle the write processing. | 415 | * after irq received |
874 | * | 416 | * |
875 | * @dev: the device structure | 417 | * @dev: the device structure |
876 | * @cmpl_list: An instance of our list structure | 418 | * @cmpl_list: An instance of our list structure |
877 | * | 419 | * |
878 | * returns 0 on success, <0 on failure. | 420 | * returns 0 on success, <0 on failure. |
879 | */ | 421 | */ |
880 | static int mei_irq_thread_write_handler(struct mei_device *dev, | 422 | int mei_irq_write_handler(struct mei_device *dev, |
881 | struct mei_cl_cb *cmpl_list) | 423 | struct mei_cl_cb *cmpl_list) |
882 | { | 424 | { |
883 | 425 | ||
@@ -887,7 +429,7 @@ static int mei_irq_thread_write_handler(struct mei_device *dev, | |||
887 | s32 slots; | 429 | s32 slots; |
888 | int ret; | 430 | int ret; |
889 | 431 | ||
890 | if (!mei_hbuf_is_empty(dev)) { | 432 | if (!mei_hbuf_is_ready(dev)) { |
891 | dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n"); | 433 | dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n"); |
892 | return 0; | 434 | return 0; |
893 | } | 435 | } |
@@ -930,16 +472,16 @@ static int mei_irq_thread_write_handler(struct mei_device *dev, | |||
930 | 472 | ||
931 | if (dev->wr_ext_msg.hdr.length) { | 473 | if (dev->wr_ext_msg.hdr.length) { |
932 | mei_write_message(dev, &dev->wr_ext_msg.hdr, | 474 | mei_write_message(dev, &dev->wr_ext_msg.hdr, |
933 | dev->wr_ext_msg.data, dev->wr_ext_msg.hdr.length); | 475 | dev->wr_ext_msg.data); |
934 | slots -= mei_data2slots(dev->wr_ext_msg.hdr.length); | 476 | slots -= mei_data2slots(dev->wr_ext_msg.hdr.length); |
935 | dev->wr_ext_msg.hdr.length = 0; | 477 | dev->wr_ext_msg.hdr.length = 0; |
936 | } | 478 | } |
937 | if (dev->dev_state == MEI_DEV_ENABLED) { | 479 | if (dev->dev_state == MEI_DEV_ENABLED) { |
938 | if (dev->wd_pending && | 480 | if (dev->wd_pending && |
939 | mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) { | 481 | mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) { |
940 | if (mei_wd_send(dev)) | 482 | if (mei_wd_send(dev)) |
941 | dev_dbg(&dev->pdev->dev, "wd send failed.\n"); | 483 | dev_dbg(&dev->pdev->dev, "wd send failed.\n"); |
942 | else if (mei_flow_ctrl_reduce(dev, &dev->wd_cl)) | 484 | else if (mei_cl_flow_ctrl_reduce(&dev->wd_cl)) |
943 | return -ENODEV; | 485 | return -ENODEV; |
944 | 486 | ||
945 | dev->wd_pending = false; | 487 | dev->wd_pending = false; |
@@ -978,7 +520,7 @@ static int mei_irq_thread_write_handler(struct mei_device *dev, | |||
978 | break; | 520 | break; |
979 | case MEI_FOP_IOCTL: | 521 | case MEI_FOP_IOCTL: |
980 | /* connect message */ | 522 | /* connect message */ |
981 | if (mei_other_client_is_connecting(dev, cl)) | 523 | if (mei_cl_is_other_connecting(cl)) |
982 | continue; | 524 | continue; |
983 | ret = _mei_irq_thread_ioctl(dev, &slots, pos, | 525 | ret = _mei_irq_thread_ioctl(dev, &slots, pos, |
984 | cl, cmpl_list); | 526 | cl, cmpl_list); |
@@ -998,7 +540,7 @@ static int mei_irq_thread_write_handler(struct mei_device *dev, | |||
998 | cl = pos->cl; | 540 | cl = pos->cl; |
999 | if (cl == NULL) | 541 | if (cl == NULL) |
1000 | continue; | 542 | continue; |
1001 | if (mei_flow_ctrl_creds(dev, cl) <= 0) { | 543 | if (mei_cl_flow_ctrl_creds(cl) <= 0) { |
1002 | dev_dbg(&dev->pdev->dev, | 544 | dev_dbg(&dev->pdev->dev, |
1003 | "No flow control credentials for client %d, not sending.\n", | 545 | "No flow control credentials for client %d, not sending.\n", |
1004 | cl->host_client_id); | 546 | cl->host_client_id); |
@@ -1123,115 +665,3 @@ out: | |||
1123 | mutex_unlock(&dev->device_lock); | 665 | mutex_unlock(&dev->device_lock); |
1124 | } | 666 | } |
1125 | 667 | ||
1126 | /** | ||
1127 | * mei_interrupt_thread_handler - function called after ISR to handle the interrupt | ||
1128 | * processing. | ||
1129 | * | ||
1130 | * @irq: The irq number | ||
1131 | * @dev_id: pointer to the device structure | ||
1132 | * | ||
1133 | * returns irqreturn_t | ||
1134 | * | ||
1135 | */ | ||
1136 | irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) | ||
1137 | { | ||
1138 | struct mei_device *dev = (struct mei_device *) dev_id; | ||
1139 | struct mei_cl_cb complete_list; | ||
1140 | struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; | ||
1141 | struct mei_cl *cl; | ||
1142 | s32 slots; | ||
1143 | int rets; | ||
1144 | bool bus_message_received; | ||
1145 | |||
1146 | |||
1147 | dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n"); | ||
1148 | /* initialize our complete list */ | ||
1149 | mutex_lock(&dev->device_lock); | ||
1150 | mei_io_list_init(&complete_list); | ||
1151 | dev->host_hw_state = mei_hcsr_read(dev); | ||
1152 | |||
1153 | /* Ack the interrupt here | ||
1154 | * In case of MSI we don't go through the quick handler */ | ||
1155 | if (pci_dev_msi_enabled(dev->pdev)) | ||
1156 | mei_reg_write(dev, H_CSR, dev->host_hw_state); | ||
1157 | |||
1158 | dev->me_hw_state = mei_mecsr_read(dev); | ||
1159 | |||
1160 | /* check if ME wants a reset */ | ||
1161 | if ((dev->me_hw_state & ME_RDY_HRA) == 0 && | ||
1162 | dev->dev_state != MEI_DEV_RESETING && | ||
1163 | dev->dev_state != MEI_DEV_INITIALIZING) { | ||
1164 | dev_dbg(&dev->pdev->dev, "FW not ready.\n"); | ||
1165 | mei_reset(dev, 1); | ||
1166 | mutex_unlock(&dev->device_lock); | ||
1167 | return IRQ_HANDLED; | ||
1168 | } | ||
1169 | |||
1170 | /* check if we need to start the dev */ | ||
1171 | if ((dev->host_hw_state & H_RDY) == 0) { | ||
1172 | if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) { | ||
1173 | dev_dbg(&dev->pdev->dev, "we need to start the dev.\n"); | ||
1174 | dev->host_hw_state |= (H_IE | H_IG | H_RDY); | ||
1175 | mei_hcsr_set(dev); | ||
1176 | dev->dev_state = MEI_DEV_INIT_CLIENTS; | ||
1177 | dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n"); | ||
1178 | /* link is established | ||
1179 | * start sending messages. | ||
1180 | */ | ||
1181 | mei_host_start_message(dev); | ||
1182 | mutex_unlock(&dev->device_lock); | ||
1183 | return IRQ_HANDLED; | ||
1184 | } else { | ||
1185 | dev_dbg(&dev->pdev->dev, "FW not ready.\n"); | ||
1186 | mutex_unlock(&dev->device_lock); | ||
1187 | return IRQ_HANDLED; | ||
1188 | } | ||
1189 | } | ||
1190 | /* check slots available for reading */ | ||
1191 | slots = mei_count_full_read_slots(dev); | ||
1192 | while (slots > 0) { | ||
1193 | /* we have urgent data to send so break the read */ | ||
1194 | if (dev->wr_ext_msg.hdr.length) | ||
1195 | break; | ||
1196 | dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots); | ||
1197 | dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n"); | ||
1198 | rets = mei_irq_thread_read_handler(&complete_list, dev, &slots); | ||
1199 | if (rets) | ||
1200 | goto end; | ||
1201 | } | ||
1202 | rets = mei_irq_thread_write_handler(dev, &complete_list); | ||
1203 | end: | ||
1204 | dev_dbg(&dev->pdev->dev, "end of bottom half function.\n"); | ||
1205 | dev->host_hw_state = mei_hcsr_read(dev); | ||
1206 | dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev); | ||
1207 | |||
1208 | bus_message_received = false; | ||
1209 | if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) { | ||
1210 | dev_dbg(&dev->pdev->dev, "received waiting bus message\n"); | ||
1211 | bus_message_received = true; | ||
1212 | } | ||
1213 | mutex_unlock(&dev->device_lock); | ||
1214 | if (bus_message_received) { | ||
1215 | dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n"); | ||
1216 | wake_up_interruptible(&dev->wait_recvd_msg); | ||
1217 | bus_message_received = false; | ||
1218 | } | ||
1219 | if (list_empty(&complete_list.list)) | ||
1220 | return IRQ_HANDLED; | ||
1221 | |||
1222 | |||
1223 | list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) { | ||
1224 | cl = cb_pos->cl; | ||
1225 | list_del(&cb_pos->list); | ||
1226 | if (cl) { | ||
1227 | if (cl != &dev->iamthif_cl) { | ||
1228 | dev_dbg(&dev->pdev->dev, "completing call back.\n"); | ||
1229 | _mei_cmpl(cl, cb_pos); | ||
1230 | cb_pos = NULL; | ||
1231 | } else if (cl == &dev->iamthif_cl) { | ||
1232 | mei_amthif_complete(dev, cb_pos); | ||
1233 | } | ||
1234 | } | ||
1235 | } | ||
1236 | return IRQ_HANDLED; | ||
1237 | } | ||