diff options
Diffstat (limited to 'drivers/misc/mei/interrupt.c')
-rw-r--r-- | drivers/misc/mei/interrupt.c | 122 |
1 files changed, 66 insertions, 56 deletions
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 7a95c07e59a6..f0fbb5179f80 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c | |||
@@ -31,7 +31,7 @@ | |||
31 | 31 | ||
32 | 32 | ||
33 | /** | 33 | /** |
34 | * mei_irq_compl_handler - dispatch complete handelers | 34 | * mei_irq_compl_handler - dispatch complete handlers |
35 | * for the completed callbacks | 35 | * for the completed callbacks |
36 | * | 36 | * |
37 | * @dev - mei device | 37 | * @dev - mei device |
@@ -301,13 +301,11 @@ int mei_irq_read_handler(struct mei_device *dev, | |||
301 | struct mei_cl_cb *cmpl_list, s32 *slots) | 301 | struct mei_cl_cb *cmpl_list, s32 *slots) |
302 | { | 302 | { |
303 | struct mei_msg_hdr *mei_hdr; | 303 | struct mei_msg_hdr *mei_hdr; |
304 | struct mei_cl *cl_pos = NULL; | 304 | struct mei_cl *cl; |
305 | struct mei_cl *cl_next = NULL; | 305 | int ret; |
306 | int ret = 0; | ||
307 | 306 | ||
308 | if (!dev->rd_msg_hdr) { | 307 | if (!dev->rd_msg_hdr) { |
309 | dev->rd_msg_hdr = mei_read_hdr(dev); | 308 | dev->rd_msg_hdr = mei_read_hdr(dev); |
310 | dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); | ||
311 | (*slots)--; | 309 | (*slots)--; |
312 | dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); | 310 | dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); |
313 | } | 311 | } |
@@ -315,61 +313,67 @@ int mei_irq_read_handler(struct mei_device *dev, | |||
315 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); | 313 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); |
316 | 314 | ||
317 | if (mei_hdr->reserved || !dev->rd_msg_hdr) { | 315 | if (mei_hdr->reserved || !dev->rd_msg_hdr) { |
318 | dev_dbg(&dev->pdev->dev, "corrupted message header.\n"); | 316 | dev_err(&dev->pdev->dev, "corrupted message header 0x%08X\n", |
317 | dev->rd_msg_hdr); | ||
319 | ret = -EBADMSG; | 318 | ret = -EBADMSG; |
320 | goto end; | 319 | goto end; |
321 | } | 320 | } |
322 | 321 | ||
323 | if (mei_hdr->host_addr || mei_hdr->me_addr) { | 322 | if (mei_slots2data(*slots) < mei_hdr->length) { |
324 | list_for_each_entry_safe(cl_pos, cl_next, | 323 | dev_err(&dev->pdev->dev, "less data available than length=%08x.\n", |
325 | &dev->file_list, link) { | ||
326 | dev_dbg(&dev->pdev->dev, | ||
327 | "list_for_each_entry_safe read host" | ||
328 | " client = %d, ME client = %d\n", | ||
329 | cl_pos->host_client_id, | ||
330 | cl_pos->me_client_id); | ||
331 | if (mei_cl_hbm_equal(cl_pos, mei_hdr)) | ||
332 | break; | ||
333 | } | ||
334 | |||
335 | if (&cl_pos->link == &dev->file_list) { | ||
336 | dev_dbg(&dev->pdev->dev, "corrupted message header\n"); | ||
337 | ret = -EBADMSG; | ||
338 | goto end; | ||
339 | } | ||
340 | } | ||
341 | if (((*slots) * sizeof(u32)) < mei_hdr->length) { | ||
342 | dev_err(&dev->pdev->dev, | ||
343 | "we can't read the message slots =%08x.\n", | ||
344 | *slots); | 324 | *slots); |
345 | /* we can't read the message */ | 325 | /* we can't read the message */ |
346 | ret = -ERANGE; | 326 | ret = -ERANGE; |
347 | goto end; | 327 | goto end; |
348 | } | 328 | } |
349 | 329 | ||
350 | /* decide where to read the message too */ | 330 | /* HBM message */ |
351 | if (!mei_hdr->host_addr) { | 331 | if (mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0) { |
352 | dev_dbg(&dev->pdev->dev, "call mei_hbm_dispatch.\n"); | 332 | ret = mei_hbm_dispatch(dev, mei_hdr); |
353 | mei_hbm_dispatch(dev, mei_hdr); | 333 | if (ret) { |
354 | dev_dbg(&dev->pdev->dev, "end mei_hbm_dispatch.\n"); | 334 | dev_dbg(&dev->pdev->dev, "mei_hbm_dispatch failed ret = %d\n", |
355 | } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && | 335 | ret); |
356 | (MEI_FILE_CONNECTED == dev->iamthif_cl.state) && | 336 | goto end; |
357 | (dev->iamthif_state == MEI_IAMTHIF_READING)) { | 337 | } |
338 | goto reset_slots; | ||
339 | } | ||
340 | |||
341 | /* find recipient cl */ | ||
342 | list_for_each_entry(cl, &dev->file_list, link) { | ||
343 | if (mei_cl_hbm_equal(cl, mei_hdr)) { | ||
344 | cl_dbg(dev, cl, "got a message\n"); | ||
345 | break; | ||
346 | } | ||
347 | } | ||
348 | |||
349 | /* if no recipient cl was found we assume corrupted header */ | ||
350 | if (&cl->link == &dev->file_list) { | ||
351 | dev_err(&dev->pdev->dev, "no destination client found 0x%08X\n", | ||
352 | dev->rd_msg_hdr); | ||
353 | ret = -EBADMSG; | ||
354 | goto end; | ||
355 | } | ||
358 | 356 | ||
359 | dev_dbg(&dev->pdev->dev, "call mei_amthif_irq_read_msg.\n"); | 357 | if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && |
360 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); | 358 | MEI_FILE_CONNECTED == dev->iamthif_cl.state && |
359 | dev->iamthif_state == MEI_IAMTHIF_READING) { | ||
361 | 360 | ||
362 | ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list); | 361 | ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list); |
363 | if (ret) | 362 | if (ret) { |
363 | dev_err(&dev->pdev->dev, "mei_amthif_irq_read_msg failed = %d\n", | ||
364 | ret); | ||
364 | goto end; | 365 | goto end; |
366 | } | ||
365 | } else { | 367 | } else { |
366 | dev_dbg(&dev->pdev->dev, "call mei_cl_irq_read_msg.\n"); | ||
367 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); | ||
368 | ret = mei_cl_irq_read_msg(dev, mei_hdr, cmpl_list); | 368 | ret = mei_cl_irq_read_msg(dev, mei_hdr, cmpl_list); |
369 | if (ret) | 369 | if (ret) { |
370 | dev_err(&dev->pdev->dev, "mei_cl_irq_read_msg failed = %d\n", | ||
371 | ret); | ||
370 | goto end; | 372 | goto end; |
373 | } | ||
371 | } | 374 | } |
372 | 375 | ||
376 | reset_slots: | ||
373 | /* reset the number of slots and header */ | 377 | /* reset the number of slots and header */ |
374 | *slots = mei_count_full_read_slots(dev); | 378 | *slots = mei_count_full_read_slots(dev); |
375 | dev->rd_msg_hdr = 0; | 379 | dev->rd_msg_hdr = 0; |
@@ -533,7 +537,6 @@ EXPORT_SYMBOL_GPL(mei_irq_write_handler); | |||
533 | * | 537 | * |
534 | * @work: pointer to the work_struct structure | 538 | * @work: pointer to the work_struct structure |
535 | * | 539 | * |
536 | * NOTE: This function is called by timer interrupt work | ||
537 | */ | 540 | */ |
538 | void mei_timer(struct work_struct *work) | 541 | void mei_timer(struct work_struct *work) |
539 | { | 542 | { |
@@ -548,24 +551,30 @@ void mei_timer(struct work_struct *work) | |||
548 | 551 | ||
549 | 552 | ||
550 | mutex_lock(&dev->device_lock); | 553 | mutex_lock(&dev->device_lock); |
551 | if (dev->dev_state != MEI_DEV_ENABLED) { | 554 | |
552 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS) { | 555 | /* Catch interrupt stalls during HBM init handshake */ |
553 | if (dev->init_clients_timer) { | 556 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && |
554 | if (--dev->init_clients_timer == 0) { | 557 | dev->hbm_state != MEI_HBM_IDLE) { |
555 | dev_err(&dev->pdev->dev, "reset: init clients timeout hbm_state = %d.\n", | 558 | |
556 | dev->hbm_state); | 559 | if (dev->init_clients_timer) { |
557 | mei_reset(dev, 1); | 560 | if (--dev->init_clients_timer == 0) { |
558 | } | 561 | dev_err(&dev->pdev->dev, "timer: init clients timeout hbm_state = %d.\n", |
562 | dev->hbm_state); | ||
563 | mei_reset(dev); | ||
564 | goto out; | ||
559 | } | 565 | } |
560 | } | 566 | } |
561 | goto out; | ||
562 | } | 567 | } |
568 | |||
569 | if (dev->dev_state != MEI_DEV_ENABLED) | ||
570 | goto out; | ||
571 | |||
563 | /*** connect/disconnect timeouts ***/ | 572 | /*** connect/disconnect timeouts ***/ |
564 | list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { | 573 | list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { |
565 | if (cl_pos->timer_count) { | 574 | if (cl_pos->timer_count) { |
566 | if (--cl_pos->timer_count == 0) { | 575 | if (--cl_pos->timer_count == 0) { |
567 | dev_err(&dev->pdev->dev, "reset: connect/disconnect timeout.\n"); | 576 | dev_err(&dev->pdev->dev, "timer: connect/disconnect timeout.\n"); |
568 | mei_reset(dev, 1); | 577 | mei_reset(dev); |
569 | goto out; | 578 | goto out; |
570 | } | 579 | } |
571 | } | 580 | } |
@@ -573,8 +582,8 @@ void mei_timer(struct work_struct *work) | |||
573 | 582 | ||
574 | if (dev->iamthif_stall_timer) { | 583 | if (dev->iamthif_stall_timer) { |
575 | if (--dev->iamthif_stall_timer == 0) { | 584 | if (--dev->iamthif_stall_timer == 0) { |
576 | dev_err(&dev->pdev->dev, "reset: amthif hanged.\n"); | 585 | dev_err(&dev->pdev->dev, "timer: amthif hanged.\n"); |
577 | mei_reset(dev, 1); | 586 | mei_reset(dev); |
578 | dev->iamthif_msg_buf_size = 0; | 587 | dev->iamthif_msg_buf_size = 0; |
579 | dev->iamthif_msg_buf_index = 0; | 588 | dev->iamthif_msg_buf_index = 0; |
580 | dev->iamthif_canceled = false; | 589 | dev->iamthif_canceled = false; |
@@ -627,7 +636,8 @@ void mei_timer(struct work_struct *work) | |||
627 | } | 636 | } |
628 | } | 637 | } |
629 | out: | 638 | out: |
630 | schedule_delayed_work(&dev->timer_work, 2 * HZ); | 639 | if (dev->dev_state != MEI_DEV_DISABLED) |
640 | schedule_delayed_work(&dev->timer_work, 2 * HZ); | ||
631 | mutex_unlock(&dev->device_lock); | 641 | mutex_unlock(&dev->device_lock); |
632 | } | 642 | } |
633 | 643 | ||