diff options
author | Michael Hennerich <michael.hennerich@analog.com> | 2017-11-28 07:53:15 -0500 |
---|---|---|
committer | Stefan Schmidt <stefan@osg.samsung.com> | 2017-11-29 10:49:41 -0500 |
commit | 8f1878a182dcc5a15a57c7fc7d8182bea0733dfa (patch) | |
tree | bb933e39458a1f36bff86e8d3dd973689cbd2910 | |
parent | c78c1b01394406182fab5caff25ac58f754c702d (diff) |
net: ieee802154: adf7242: Rework IRQ and packet handling
* Stop unconditionally polling for RC_STATUS_PHY_RDY at the entry of
the threaded IRQ handler. Once IRQ_RX_PKT_RCVD is received we can
read immediately the packet from the buffer. However we still need
to wait afterwards for RC_STATUS_PHY_RDY, to make sure that the
ACK (in case requested) was processed and send out by the
Radio Controller, before we issue the next CMD_RC_RX.
This significantly reduces the overall time spend in the threaded
IRQ handler.
* Avoid raise condition between xmit and coincident packet reception,
by disabling the IRQ and clearing the IRQ status upon xmit entry.
* Introduce helper functions adf7242_clear_irqstat() and adf7242_cmd_rx()
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Stefan Schmidt <stefan@osg.samsung.com>
-rw-r--r-- | drivers/net/ieee802154/adf7242.c | 54 |
1 files changed, 39 insertions, 15 deletions
diff --git a/drivers/net/ieee802154/adf7242.c b/drivers/net/ieee802154/adf7242.c index 548bec16906e..64f1b1e77bc0 100644 --- a/drivers/net/ieee802154/adf7242.c +++ b/drivers/net/ieee802154/adf7242.c | |||
@@ -563,6 +563,22 @@ static int adf7242_verify_firmware(struct adf7242_local *lp, | |||
563 | return 0; | 563 | return 0; |
564 | } | 564 | } |
565 | 565 | ||
566 | static void adf7242_clear_irqstat(struct adf7242_local *lp) | ||
567 | { | ||
568 | adf7242_write_reg(lp, REG_IRQ1_SRC1, IRQ_CCA_COMPLETE | IRQ_SFD_RX | | ||
569 | IRQ_SFD_TX | IRQ_RX_PKT_RCVD | IRQ_TX_PKT_SENT | | ||
570 | IRQ_FRAME_VALID | IRQ_ADDRESS_VALID | IRQ_CSMA_CA); | ||
571 | } | ||
572 | |||
573 | static int adf7242_cmd_rx(struct adf7242_local *lp) | ||
574 | { | ||
575 | /* Wait until the ACK is sent */ | ||
576 | adf7242_wait_status(lp, RC_STATUS_PHY_RDY, RC_STATUS_MASK, __LINE__); | ||
577 | adf7242_clear_irqstat(lp); | ||
578 | |||
579 | return adf7242_cmd(lp, CMD_RC_RX); | ||
580 | } | ||
581 | |||
566 | static int adf7242_set_txpower(struct ieee802154_hw *hw, int mbm) | 582 | static int adf7242_set_txpower(struct ieee802154_hw *hw, int mbm) |
567 | { | 583 | { |
568 | struct adf7242_local *lp = hw->priv; | 584 | struct adf7242_local *lp = hw->priv; |
@@ -666,7 +682,7 @@ static int adf7242_start(struct ieee802154_hw *hw) | |||
666 | struct adf7242_local *lp = hw->priv; | 682 | struct adf7242_local *lp = hw->priv; |
667 | 683 | ||
668 | adf7242_cmd(lp, CMD_RC_PHY_RDY); | 684 | adf7242_cmd(lp, CMD_RC_PHY_RDY); |
669 | adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF); | 685 | adf7242_clear_irqstat(lp); |
670 | enable_irq(lp->spi->irq); | 686 | enable_irq(lp->spi->irq); |
671 | set_bit(FLAG_START, &lp->flags); | 687 | set_bit(FLAG_START, &lp->flags); |
672 | 688 | ||
@@ -677,10 +693,10 @@ static void adf7242_stop(struct ieee802154_hw *hw) | |||
677 | { | 693 | { |
678 | struct adf7242_local *lp = hw->priv; | 694 | struct adf7242_local *lp = hw->priv; |
679 | 695 | ||
696 | disable_irq(lp->spi->irq); | ||
680 | adf7242_cmd(lp, CMD_RC_IDLE); | 697 | adf7242_cmd(lp, CMD_RC_IDLE); |
681 | clear_bit(FLAG_START, &lp->flags); | 698 | clear_bit(FLAG_START, &lp->flags); |
682 | disable_irq(lp->spi->irq); | 699 | adf7242_clear_irqstat(lp); |
683 | adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF); | ||
684 | } | 700 | } |
685 | 701 | ||
686 | static int adf7242_channel(struct ieee802154_hw *hw, u8 page, u8 channel) | 702 | static int adf7242_channel(struct ieee802154_hw *hw, u8 page, u8 channel) |
@@ -795,9 +811,12 @@ static int adf7242_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) | |||
795 | struct adf7242_local *lp = hw->priv; | 811 | struct adf7242_local *lp = hw->priv; |
796 | int ret; | 812 | int ret; |
797 | 813 | ||
814 | /* ensure existing instances of the IRQ handler have completed */ | ||
815 | disable_irq(lp->spi->irq); | ||
798 | set_bit(FLAG_XMIT, &lp->flags); | 816 | set_bit(FLAG_XMIT, &lp->flags); |
799 | reinit_completion(&lp->tx_complete); | 817 | reinit_completion(&lp->tx_complete); |
800 | adf7242_cmd(lp, CMD_RC_PHY_RDY); | 818 | adf7242_cmd(lp, CMD_RC_PHY_RDY); |
819 | adf7242_clear_irqstat(lp); | ||
801 | 820 | ||
802 | ret = adf7242_write_fbuf(lp, skb->data, skb->len); | 821 | ret = adf7242_write_fbuf(lp, skb->data, skb->len); |
803 | if (ret) | 822 | if (ret) |
@@ -806,6 +825,7 @@ static int adf7242_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) | |||
806 | ret = adf7242_cmd(lp, CMD_RC_CSMACA); | 825 | ret = adf7242_cmd(lp, CMD_RC_CSMACA); |
807 | if (ret) | 826 | if (ret) |
808 | goto err; | 827 | goto err; |
828 | enable_irq(lp->spi->irq); | ||
809 | 829 | ||
810 | ret = wait_for_completion_interruptible_timeout(&lp->tx_complete, | 830 | ret = wait_for_completion_interruptible_timeout(&lp->tx_complete, |
811 | HZ / 10); | 831 | HZ / 10); |
@@ -828,7 +848,7 @@ static int adf7242_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) | |||
828 | 848 | ||
829 | err: | 849 | err: |
830 | clear_bit(FLAG_XMIT, &lp->flags); | 850 | clear_bit(FLAG_XMIT, &lp->flags); |
831 | adf7242_cmd(lp, CMD_RC_RX); | 851 | adf7242_cmd_rx(lp); |
832 | 852 | ||
833 | return ret; | 853 | return ret; |
834 | } | 854 | } |
@@ -852,7 +872,7 @@ static int adf7242_rx(struct adf7242_local *lp) | |||
852 | 872 | ||
853 | skb = dev_alloc_skb(len); | 873 | skb = dev_alloc_skb(len); |
854 | if (!skb) { | 874 | if (!skb) { |
855 | adf7242_cmd(lp, CMD_RC_RX); | 875 | adf7242_cmd_rx(lp); |
856 | return -ENOMEM; | 876 | return -ENOMEM; |
857 | } | 877 | } |
858 | 878 | ||
@@ -860,14 +880,14 @@ static int adf7242_rx(struct adf7242_local *lp) | |||
860 | ret = adf7242_read_fbuf(lp, data, len, true); | 880 | ret = adf7242_read_fbuf(lp, data, len, true); |
861 | if (ret < 0) { | 881 | if (ret < 0) { |
862 | kfree_skb(skb); | 882 | kfree_skb(skb); |
863 | adf7242_cmd(lp, CMD_RC_RX); | 883 | adf7242_cmd_rx(lp); |
864 | return ret; | 884 | return ret; |
865 | } | 885 | } |
866 | 886 | ||
867 | lqi = data[len - 2]; | 887 | lqi = data[len - 2]; |
868 | lp->rssi = data[len - 1]; | 888 | lp->rssi = data[len - 1]; |
869 | 889 | ||
870 | adf7242_cmd(lp, CMD_RC_RX); | 890 | ret = adf7242_cmd_rx(lp); |
871 | 891 | ||
872 | skb_trim(skb, len - 2); /* Don't put RSSI/LQI or CRC into the frame */ | 892 | skb_trim(skb, len - 2); /* Don't put RSSI/LQI or CRC into the frame */ |
873 | 893 | ||
@@ -876,7 +896,7 @@ static int adf7242_rx(struct adf7242_local *lp) | |||
876 | dev_dbg(&lp->spi->dev, "%s: ret=%d len=%d lqi=%d rssi=%d\n", | 896 | dev_dbg(&lp->spi->dev, "%s: ret=%d len=%d lqi=%d rssi=%d\n", |
877 | __func__, ret, (int)len, (int)lqi, lp->rssi); | 897 | __func__, ret, (int)len, (int)lqi, lp->rssi); |
878 | 898 | ||
879 | return 0; | 899 | return ret; |
880 | } | 900 | } |
881 | 901 | ||
882 | static const struct ieee802154_ops adf7242_ops = { | 902 | static const struct ieee802154_ops adf7242_ops = { |
@@ -932,10 +952,7 @@ static irqreturn_t adf7242_isr(int irq, void *data) | |||
932 | unsigned int xmit; | 952 | unsigned int xmit; |
933 | u8 irq1; | 953 | u8 irq1; |
934 | 954 | ||
935 | adf7242_wait_status(lp, RC_STATUS_PHY_RDY, RC_STATUS_MASK, __LINE__); | ||
936 | |||
937 | adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1); | 955 | adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1); |
938 | adf7242_write_reg(lp, REG_IRQ1_SRC1, irq1); | ||
939 | 956 | ||
940 | if (!(irq1 & (IRQ_RX_PKT_RCVD | IRQ_CSMA_CA))) | 957 | if (!(irq1 & (IRQ_RX_PKT_RCVD | IRQ_CSMA_CA))) |
941 | dev_err(&lp->spi->dev, "%s :ERROR IRQ1 = 0x%X\n", | 958 | dev_err(&lp->spi->dev, "%s :ERROR IRQ1 = 0x%X\n", |
@@ -946,6 +963,9 @@ static irqreturn_t adf7242_isr(int irq, void *data) | |||
946 | xmit = test_bit(FLAG_XMIT, &lp->flags); | 963 | xmit = test_bit(FLAG_XMIT, &lp->flags); |
947 | 964 | ||
948 | if (xmit && (irq1 & IRQ_CSMA_CA)) { | 965 | if (xmit && (irq1 & IRQ_CSMA_CA)) { |
966 | adf7242_wait_status(lp, RC_STATUS_PHY_RDY, | ||
967 | RC_STATUS_MASK, __LINE__); | ||
968 | |||
949 | if (ADF7242_REPORT_CSMA_CA_STAT) { | 969 | if (ADF7242_REPORT_CSMA_CA_STAT) { |
950 | u8 astat; | 970 | u8 astat; |
951 | 971 | ||
@@ -966,6 +986,7 @@ static irqreturn_t adf7242_isr(int irq, void *data) | |||
966 | lp->tx_stat = SUCCESS; | 986 | lp->tx_stat = SUCCESS; |
967 | } | 987 | } |
968 | complete(&lp->tx_complete); | 988 | complete(&lp->tx_complete); |
989 | adf7242_clear_irqstat(lp); | ||
969 | } else if (!xmit && (irq1 & IRQ_RX_PKT_RCVD) && | 990 | } else if (!xmit && (irq1 & IRQ_RX_PKT_RCVD) && |
970 | (irq1 & IRQ_FRAME_VALID)) { | 991 | (irq1 & IRQ_FRAME_VALID)) { |
971 | adf7242_rx(lp); | 992 | adf7242_rx(lp); |
@@ -974,16 +995,19 @@ static irqreturn_t adf7242_isr(int irq, void *data) | |||
974 | dev_dbg(&lp->spi->dev, "%s:%d : ERROR IRQ1 = 0x%X\n", | 995 | dev_dbg(&lp->spi->dev, "%s:%d : ERROR IRQ1 = 0x%X\n", |
975 | __func__, __LINE__, irq1); | 996 | __func__, __LINE__, irq1); |
976 | adf7242_cmd(lp, CMD_RC_PHY_RDY); | 997 | adf7242_cmd(lp, CMD_RC_PHY_RDY); |
977 | adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF); | 998 | adf7242_cmd_rx(lp); |
978 | adf7242_cmd(lp, CMD_RC_RX); | ||
979 | } else { | 999 | } else { |
980 | /* This can only be xmit without IRQ, likely a RX packet. | 1000 | /* This can only be xmit without IRQ, likely a RX packet. |
981 | * we get an TX IRQ shortly - do nothing or let the xmit | 1001 | * we get an TX IRQ shortly - do nothing or let the xmit |
982 | * timeout handle this | 1002 | * timeout handle this |
983 | */ | 1003 | */ |
1004 | |||
984 | dev_dbg(&lp->spi->dev, "%s:%d : ERROR IRQ1 = 0x%X, xmit %d\n", | 1005 | dev_dbg(&lp->spi->dev, "%s:%d : ERROR IRQ1 = 0x%X, xmit %d\n", |
985 | __func__, __LINE__, irq1, xmit); | 1006 | __func__, __LINE__, irq1, xmit); |
1007 | adf7242_wait_status(lp, RC_STATUS_PHY_RDY, | ||
1008 | RC_STATUS_MASK, __LINE__); | ||
986 | complete(&lp->tx_complete); | 1009 | complete(&lp->tx_complete); |
1010 | adf7242_clear_irqstat(lp); | ||
987 | } | 1011 | } |
988 | 1012 | ||
989 | return IRQ_HANDLED; | 1013 | return IRQ_HANDLED; |
@@ -1003,7 +1027,7 @@ static int adf7242_soft_reset(struct adf7242_local *lp, int line) | |||
1003 | adf7242_set_promiscuous_mode(lp->hw, lp->promiscuous); | 1027 | adf7242_set_promiscuous_mode(lp->hw, lp->promiscuous); |
1004 | adf7242_set_csma_params(lp->hw, lp->min_be, lp->max_be, | 1028 | adf7242_set_csma_params(lp->hw, lp->min_be, lp->max_be, |
1005 | lp->max_cca_retries); | 1029 | lp->max_cca_retries); |
1006 | adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF); | 1030 | adf7242_clear_irqstat(lp); |
1007 | 1031 | ||
1008 | if (test_bit(FLAG_START, &lp->flags)) { | 1032 | if (test_bit(FLAG_START, &lp->flags)) { |
1009 | enable_irq(lp->spi->irq); | 1033 | enable_irq(lp->spi->irq); |
@@ -1069,7 +1093,7 @@ static int adf7242_hw_init(struct adf7242_local *lp) | |||
1069 | adf7242_write_reg(lp, REG_IRQ1_EN0, 0); | 1093 | adf7242_write_reg(lp, REG_IRQ1_EN0, 0); |
1070 | adf7242_write_reg(lp, REG_IRQ1_EN1, IRQ_RX_PKT_RCVD | IRQ_CSMA_CA); | 1094 | adf7242_write_reg(lp, REG_IRQ1_EN1, IRQ_RX_PKT_RCVD | IRQ_CSMA_CA); |
1071 | 1095 | ||
1072 | adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF); | 1096 | adf7242_clear_irqstat(lp); |
1073 | adf7242_write_reg(lp, REG_IRQ1_SRC0, 0xFF); | 1097 | adf7242_write_reg(lp, REG_IRQ1_SRC0, 0xFF); |
1074 | 1098 | ||
1075 | adf7242_cmd(lp, CMD_RC_IDLE); | 1099 | adf7242_cmd(lp, CMD_RC_IDLE); |