diff options
author | Alexander Aring <alex.aring@gmail.com> | 2014-10-07 04:38:32 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-10-25 01:56:23 -0400 |
commit | 97fed795e70d97fb89ebd8c3efc30b33aa4ac1fa (patch) | |
tree | 7a8549a6f79f4ae5870445b2edba86982590a218 /drivers/net/ieee802154 | |
parent | 35e92a8e1b9058a5f7da271a7a60264a4888f4b9 (diff) |
at86rf230: fix enable_irq handling on async spi
Sometimes the async state function is call in an context where the spi
irq is diabled. This patch fix the handling to enable the irq when
spi_async failed in the async state change calling chain. We do this by
a context parameter irq_enable and evaluate this parameter when
spi_async failed instead of returning spi_async errno.
Signed-off-by: Alexander Aring <alex.aring@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'drivers/net/ieee802154')
-rw-r--r-- | drivers/net/ieee802154/at86rf230.c | 157 |
1 files changed, 77 insertions, 80 deletions
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 5dbec64eb786..7a1a8e39b130 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c | |||
@@ -74,6 +74,8 @@ struct at86rf230_state_change { | |||
74 | void (*complete)(void *context); | 74 | void (*complete)(void *context); |
75 | u8 from_state; | 75 | u8 from_state; |
76 | u8 to_state; | 76 | u8 to_state; |
77 | |||
78 | bool irq_enable; | ||
77 | }; | 79 | }; |
78 | 80 | ||
79 | struct at86rf230_local { | 81 | struct at86rf230_local { |
@@ -292,10 +294,11 @@ struct at86rf230_local { | |||
292 | 294 | ||
293 | #define AT86RF2XX_NUMREGS 0x3F | 295 | #define AT86RF2XX_NUMREGS 0x3F |
294 | 296 | ||
295 | static int | 297 | static void |
296 | at86rf230_async_state_change(struct at86rf230_local *lp, | 298 | at86rf230_async_state_change(struct at86rf230_local *lp, |
297 | struct at86rf230_state_change *ctx, | 299 | struct at86rf230_state_change *ctx, |
298 | const u8 state, void (*complete)(void *context)); | 300 | const u8 state, void (*complete)(void *context), |
301 | const bool irq_enable); | ||
299 | 302 | ||
300 | static inline int | 303 | static inline int |
301 | __at86rf230_write(struct at86rf230_local *lp, | 304 | __at86rf230_write(struct at86rf230_local *lp, |
@@ -452,7 +455,7 @@ at86rf230_async_error_recover(void *context) | |||
452 | struct at86rf230_state_change *ctx = context; | 455 | struct at86rf230_state_change *ctx = context; |
453 | struct at86rf230_local *lp = ctx->lp; | 456 | struct at86rf230_local *lp = ctx->lp; |
454 | 457 | ||
455 | at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL); | 458 | at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL, false); |
456 | } | 459 | } |
457 | 460 | ||
458 | static void | 461 | static void |
@@ -462,21 +465,31 @@ at86rf230_async_error(struct at86rf230_local *lp, | |||
462 | dev_err(&lp->spi->dev, "spi_async error %d\n", rc); | 465 | dev_err(&lp->spi->dev, "spi_async error %d\n", rc); |
463 | 466 | ||
464 | at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, | 467 | at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, |
465 | at86rf230_async_error_recover); | 468 | at86rf230_async_error_recover, false); |
466 | } | 469 | } |
467 | 470 | ||
468 | /* Generic function to get some register value in async mode */ | 471 | /* Generic function to get some register value in async mode */ |
469 | static int | 472 | static void |
470 | at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, | 473 | at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, |
471 | struct at86rf230_state_change *ctx, | 474 | struct at86rf230_state_change *ctx, |
472 | void (*complete)(void *context)) | 475 | void (*complete)(void *context), |
476 | const bool irq_enable) | ||
473 | { | 477 | { |
478 | int rc; | ||
479 | |||
474 | u8 *tx_buf = ctx->buf; | 480 | u8 *tx_buf = ctx->buf; |
475 | 481 | ||
476 | tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG; | 482 | tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG; |
477 | ctx->trx.len = 2; | 483 | ctx->trx.len = 2; |
478 | ctx->msg.complete = complete; | 484 | ctx->msg.complete = complete; |
479 | return spi_async(lp->spi, &ctx->msg); | 485 | ctx->irq_enable = irq_enable; |
486 | rc = spi_async(lp->spi, &ctx->msg); | ||
487 | if (rc) { | ||
488 | if (irq_enable) | ||
489 | enable_irq(lp->spi->irq); | ||
490 | |||
491 | at86rf230_async_error(lp, ctx, rc); | ||
492 | } | ||
480 | } | 493 | } |
481 | 494 | ||
482 | static void | 495 | static void |
@@ -513,7 +526,8 @@ at86rf230_async_state_assert(void *context) | |||
513 | if (ctx->to_state == STATE_TX_ON) { | 526 | if (ctx->to_state == STATE_TX_ON) { |
514 | at86rf230_async_state_change(lp, ctx, | 527 | at86rf230_async_state_change(lp, ctx, |
515 | STATE_FORCE_TX_ON, | 528 | STATE_FORCE_TX_ON, |
516 | ctx->complete); | 529 | ctx->complete, |
530 | ctx->irq_enable); | ||
517 | return; | 531 | return; |
518 | } | 532 | } |
519 | } | 533 | } |
@@ -536,7 +550,6 @@ at86rf230_async_state_delay(void *context) | |||
536 | struct at86rf230_local *lp = ctx->lp; | 550 | struct at86rf230_local *lp = ctx->lp; |
537 | struct at86rf2xx_chip_data *c = lp->data; | 551 | struct at86rf2xx_chip_data *c = lp->data; |
538 | bool force = false; | 552 | bool force = false; |
539 | int rc; | ||
540 | 553 | ||
541 | /* The force state changes are will show as normal states in the | 554 | /* The force state changes are will show as normal states in the |
542 | * state status subregister. We change the to_state to the | 555 | * state status subregister. We change the to_state to the |
@@ -605,10 +618,9 @@ at86rf230_async_state_delay(void *context) | |||
605 | udelay(1); | 618 | udelay(1); |
606 | 619 | ||
607 | change: | 620 | change: |
608 | rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, | 621 | at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, |
609 | at86rf230_async_state_assert); | 622 | at86rf230_async_state_assert, |
610 | if (rc) | 623 | ctx->irq_enable); |
611 | dev_err(&lp->spi->dev, "spi_async error %d\n", rc); | ||
612 | } | 624 | } |
613 | 625 | ||
614 | static void | 626 | static void |
@@ -623,10 +635,9 @@ at86rf230_async_state_change_start(void *context) | |||
623 | /* Check for "possible" STATE_TRANSITION_IN_PROGRESS */ | 635 | /* Check for "possible" STATE_TRANSITION_IN_PROGRESS */ |
624 | if (trx_state == STATE_TRANSITION_IN_PROGRESS) { | 636 | if (trx_state == STATE_TRANSITION_IN_PROGRESS) { |
625 | udelay(1); | 637 | udelay(1); |
626 | rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, | 638 | at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, |
627 | at86rf230_async_state_change_start); | 639 | at86rf230_async_state_change_start, |
628 | if (rc) | 640 | ctx->irq_enable); |
629 | dev_err(&lp->spi->dev, "spi_async error %d\n", rc); | ||
630 | return; | 641 | return; |
631 | } | 642 | } |
632 | 643 | ||
@@ -648,20 +659,28 @@ at86rf230_async_state_change_start(void *context) | |||
648 | ctx->trx.len = 2; | 659 | ctx->trx.len = 2; |
649 | ctx->msg.complete = at86rf230_async_state_delay; | 660 | ctx->msg.complete = at86rf230_async_state_delay; |
650 | rc = spi_async(lp->spi, &ctx->msg); | 661 | rc = spi_async(lp->spi, &ctx->msg); |
651 | if (rc) | 662 | if (rc) { |
663 | if (ctx->irq_enable) | ||
664 | enable_irq(lp->spi->irq); | ||
665 | |||
666 | at86rf230_async_error(lp, &lp->state, rc); | ||
652 | dev_err(&lp->spi->dev, "spi_async error %d\n", rc); | 667 | dev_err(&lp->spi->dev, "spi_async error %d\n", rc); |
668 | } | ||
653 | } | 669 | } |
654 | 670 | ||
655 | static int | 671 | static void |
656 | at86rf230_async_state_change(struct at86rf230_local *lp, | 672 | at86rf230_async_state_change(struct at86rf230_local *lp, |
657 | struct at86rf230_state_change *ctx, | 673 | struct at86rf230_state_change *ctx, |
658 | const u8 state, void (*complete)(void *context)) | 674 | const u8 state, void (*complete)(void *context), |
675 | const bool irq_enable) | ||
659 | { | 676 | { |
660 | /* Initialization for the state change context */ | 677 | /* Initialization for the state change context */ |
661 | ctx->to_state = state; | 678 | ctx->to_state = state; |
662 | ctx->complete = complete; | 679 | ctx->complete = complete; |
663 | return at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, | 680 | ctx->irq_enable = irq_enable; |
664 | at86rf230_async_state_change_start); | 681 | at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, |
682 | at86rf230_async_state_change_start, | ||
683 | irq_enable); | ||
665 | } | 684 | } |
666 | 685 | ||
667 | static void | 686 | static void |
@@ -682,12 +701,9 @@ at86rf230_sync_state_change(struct at86rf230_local *lp, unsigned int state) | |||
682 | { | 701 | { |
683 | int rc; | 702 | int rc; |
684 | 703 | ||
685 | rc = at86rf230_async_state_change(lp, &lp->state, state, | 704 | at86rf230_async_state_change(lp, &lp->state, state, |
686 | at86rf230_sync_state_change_complete); | 705 | at86rf230_sync_state_change_complete, |
687 | if (rc) { | 706 | false); |
688 | at86rf230_async_error(lp, &lp->state, rc); | ||
689 | return rc; | ||
690 | } | ||
691 | 707 | ||
692 | rc = wait_for_completion_timeout(&lp->state_complete, | 708 | rc = wait_for_completion_timeout(&lp->state_complete, |
693 | msecs_to_jiffies(100)); | 709 | msecs_to_jiffies(100)); |
@@ -714,12 +730,9 @@ at86rf230_tx_on(void *context) | |||
714 | { | 730 | { |
715 | struct at86rf230_state_change *ctx = context; | 731 | struct at86rf230_state_change *ctx = context; |
716 | struct at86rf230_local *lp = ctx->lp; | 732 | struct at86rf230_local *lp = ctx->lp; |
717 | int rc; | ||
718 | 733 | ||
719 | rc = at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON, | 734 | at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON, |
720 | at86rf230_tx_complete); | 735 | at86rf230_tx_complete, true); |
721 | if (rc) | ||
722 | at86rf230_async_error(lp, ctx, rc); | ||
723 | } | 736 | } |
724 | 737 | ||
725 | static void | 738 | static void |
@@ -727,12 +740,9 @@ at86rf230_tx_trac_error(void *context) | |||
727 | { | 740 | { |
728 | struct at86rf230_state_change *ctx = context; | 741 | struct at86rf230_state_change *ctx = context; |
729 | struct at86rf230_local *lp = ctx->lp; | 742 | struct at86rf230_local *lp = ctx->lp; |
730 | int rc; | ||
731 | 743 | ||
732 | rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON, | 744 | at86rf230_async_state_change(lp, ctx, STATE_TX_ON, |
733 | at86rf230_tx_on); | 745 | at86rf230_tx_on, true); |
734 | if (rc) | ||
735 | at86rf230_async_error(lp, ctx, rc); | ||
736 | } | 746 | } |
737 | 747 | ||
738 | static void | 748 | static void |
@@ -742,17 +752,14 @@ at86rf230_tx_trac_check(void *context) | |||
742 | struct at86rf230_local *lp = ctx->lp; | 752 | struct at86rf230_local *lp = ctx->lp; |
743 | const u8 *buf = ctx->buf; | 753 | const u8 *buf = ctx->buf; |
744 | const u8 trac = (buf[1] & 0xe0) >> 5; | 754 | const u8 trac = (buf[1] & 0xe0) >> 5; |
745 | int rc; | ||
746 | 755 | ||
747 | /* If trac status is different than zero we need to do a state change | 756 | /* If trac status is different than zero we need to do a state change |
748 | * to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver | 757 | * to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver |
749 | * state to TX_ON. | 758 | * state to TX_ON. |
750 | */ | 759 | */ |
751 | if (trac) { | 760 | if (trac) { |
752 | rc = at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, | 761 | at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, |
753 | at86rf230_tx_trac_error); | 762 | at86rf230_tx_trac_error, true); |
754 | if (rc) | ||
755 | at86rf230_async_error(lp, ctx, rc); | ||
756 | return; | 763 | return; |
757 | } | 764 | } |
758 | 765 | ||
@@ -765,12 +772,9 @@ at86rf230_tx_trac_status(void *context) | |||
765 | { | 772 | { |
766 | struct at86rf230_state_change *ctx = context; | 773 | struct at86rf230_state_change *ctx = context; |
767 | struct at86rf230_local *lp = ctx->lp; | 774 | struct at86rf230_local *lp = ctx->lp; |
768 | int rc; | ||
769 | 775 | ||
770 | rc = at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx, | 776 | at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx, |
771 | at86rf230_tx_trac_check); | 777 | at86rf230_tx_trac_check, true); |
772 | if (rc) | ||
773 | at86rf230_async_error(lp, ctx, rc); | ||
774 | } | 778 | } |
775 | 779 | ||
776 | static void | 780 | static void |
@@ -823,15 +827,21 @@ at86rf230_rx_read_frame_complete(void *context) | |||
823 | at86rf230_rx(lp, buf + 2, len); | 827 | at86rf230_rx(lp, buf + 2, len); |
824 | } | 828 | } |
825 | 829 | ||
826 | static int | 830 | static void |
827 | at86rf230_rx_read_frame(struct at86rf230_local *lp) | 831 | at86rf230_rx_read_frame(struct at86rf230_local *lp) |
828 | { | 832 | { |
833 | int rc; | ||
834 | |||
829 | u8 *buf = lp->irq.buf; | 835 | u8 *buf = lp->irq.buf; |
830 | 836 | ||
831 | buf[0] = CMD_FB; | 837 | buf[0] = CMD_FB; |
832 | lp->irq.trx.len = AT86RF2XX_MAX_BUF; | 838 | lp->irq.trx.len = AT86RF2XX_MAX_BUF; |
833 | lp->irq.msg.complete = at86rf230_rx_read_frame_complete; | 839 | lp->irq.msg.complete = at86rf230_rx_read_frame_complete; |
834 | return spi_async(lp->spi, &lp->irq.msg); | 840 | rc = spi_async(lp->spi, &lp->irq.msg); |
841 | if (rc) { | ||
842 | enable_irq(lp->spi->irq); | ||
843 | at86rf230_async_error(lp, &lp->irq, rc); | ||
844 | } | ||
835 | } | 845 | } |
836 | 846 | ||
837 | static void | 847 | static void |
@@ -839,7 +849,6 @@ at86rf230_rx_trac_check(void *context) | |||
839 | { | 849 | { |
840 | struct at86rf230_state_change *ctx = context; | 850 | struct at86rf230_state_change *ctx = context; |
841 | struct at86rf230_local *lp = ctx->lp; | 851 | struct at86rf230_local *lp = ctx->lp; |
842 | int rc; | ||
843 | 852 | ||
844 | /* Possible check on trac status here. This could be useful to make | 853 | /* Possible check on trac status here. This could be useful to make |
845 | * some stats why receive is failed. Not used at the moment, but it's | 854 | * some stats why receive is failed. Not used at the moment, but it's |
@@ -847,14 +856,10 @@ at86rf230_rx_trac_check(void *context) | |||
847 | * The programming guide say do it so. | 856 | * The programming guide say do it so. |
848 | */ | 857 | */ |
849 | 858 | ||
850 | rc = at86rf230_rx_read_frame(lp); | 859 | at86rf230_rx_read_frame(lp); |
851 | if (rc) { | ||
852 | enable_irq(lp->spi->irq); | ||
853 | at86rf230_async_error(lp, ctx, rc); | ||
854 | } | ||
855 | } | 860 | } |
856 | 861 | ||
857 | static int | 862 | static void |
858 | at86rf230_irq_trx_end(struct at86rf230_local *lp) | 863 | at86rf230_irq_trx_end(struct at86rf230_local *lp) |
859 | { | 864 | { |
860 | spin_lock(&lp->lock); | 865 | spin_lock(&lp->lock); |
@@ -863,17 +868,19 @@ at86rf230_irq_trx_end(struct at86rf230_local *lp) | |||
863 | spin_unlock(&lp->lock); | 868 | spin_unlock(&lp->lock); |
864 | 869 | ||
865 | if (lp->tx_aret) | 870 | if (lp->tx_aret) |
866 | return at86rf230_async_state_change(lp, &lp->irq, | 871 | at86rf230_async_state_change(lp, &lp->irq, |
867 | STATE_FORCE_TX_ON, | 872 | STATE_FORCE_TX_ON, |
868 | at86rf230_tx_trac_status); | 873 | at86rf230_tx_trac_status, |
874 | true); | ||
869 | else | 875 | else |
870 | return at86rf230_async_state_change(lp, &lp->irq, | 876 | at86rf230_async_state_change(lp, &lp->irq, |
871 | STATE_RX_AACK_ON, | 877 | STATE_RX_AACK_ON, |
872 | at86rf230_tx_complete); | 878 | at86rf230_tx_complete, |
879 | true); | ||
873 | } else { | 880 | } else { |
874 | spin_unlock(&lp->lock); | 881 | spin_unlock(&lp->lock); |
875 | return at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq, | 882 | at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq, |
876 | at86rf230_rx_trac_check); | 883 | at86rf230_rx_trac_check, true); |
877 | } | 884 | } |
878 | } | 885 | } |
879 | 886 | ||
@@ -884,12 +891,9 @@ at86rf230_irq_status(void *context) | |||
884 | struct at86rf230_local *lp = ctx->lp; | 891 | struct at86rf230_local *lp = ctx->lp; |
885 | const u8 *buf = lp->irq.buf; | 892 | const u8 *buf = lp->irq.buf; |
886 | const u8 irq = buf[1]; | 893 | const u8 irq = buf[1]; |
887 | int rc; | ||
888 | 894 | ||
889 | if (irq & IRQ_TRX_END) { | 895 | if (irq & IRQ_TRX_END) { |
890 | rc = at86rf230_irq_trx_end(lp); | 896 | at86rf230_irq_trx_end(lp); |
891 | if (rc) | ||
892 | at86rf230_async_error(lp, ctx, rc); | ||
893 | } else { | 897 | } else { |
894 | enable_irq(lp->spi->irq); | 898 | enable_irq(lp->spi->irq); |
895 | dev_err(&lp->spi->dev, "not supported irq %02x received\n", | 899 | dev_err(&lp->spi->dev, "not supported irq %02x received\n", |
@@ -964,12 +968,9 @@ at86rf230_xmit_tx_on(void *context) | |||
964 | { | 968 | { |
965 | struct at86rf230_state_change *ctx = context; | 969 | struct at86rf230_state_change *ctx = context; |
966 | struct at86rf230_local *lp = ctx->lp; | 970 | struct at86rf230_local *lp = ctx->lp; |
967 | int rc; | ||
968 | 971 | ||
969 | rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON, | 972 | at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON, |
970 | at86rf230_write_frame); | 973 | at86rf230_write_frame, false); |
971 | if (rc) | ||
972 | at86rf230_async_error(lp, ctx, rc); | ||
973 | } | 974 | } |
974 | 975 | ||
975 | static int | 976 | static int |
@@ -990,12 +991,8 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb) | |||
990 | if (lp->tx_aret) | 991 | if (lp->tx_aret) |
991 | tx_complete = at86rf230_xmit_tx_on; | 992 | tx_complete = at86rf230_xmit_tx_on; |
992 | 993 | ||
993 | rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON, | 994 | at86rf230_async_state_change(lp, ctx, STATE_TX_ON, tx_complete, false); |
994 | tx_complete); | 995 | |
995 | if (rc) { | ||
996 | at86rf230_async_error(lp, ctx, rc); | ||
997 | return rc; | ||
998 | } | ||
999 | rc = wait_for_completion_interruptible_timeout(&lp->tx_complete, | 996 | rc = wait_for_completion_interruptible_timeout(&lp->tx_complete, |
1000 | msecs_to_jiffies(lp->data->t_tx_timeout)); | 997 | msecs_to_jiffies(lp->data->t_tx_timeout)); |
1001 | if (!rc) { | 998 | if (!rc) { |