diff options
author | Daniel C Halperin <daniel.c.halperin@intel.com> | 2009-08-13 16:30:56 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-20 11:33:11 -0400 |
commit | 9f30e04e041cf9943940f71fd76094dd5a237018 (patch) | |
tree | 9ce669ba936410be62cefb29cda708428d30cf90 /drivers/net/wireless/iwlwifi/iwl-rx.c | |
parent | 367ca28da433ed9639468be851e1f33468e3485e (diff) |
iwlwifi: refactor packet reception code
This patch fixes a number of issues in iwl_rx_reply_rx and
iwl_pass_packet_to_mac80211. These issues stem from the complexities of
managing two different types of packet commands for different hardware.
- Unify code handling rx_phy_res in SKB or cached to eliminate redundancy and
remove potential NULL pointer accesses
- Replace magic number with proper constant
- Optimize functions by moving early exit conditions before computation
- Comment code and improve some variable names
- Remove redundant computation in iwl_pass_packet_to_mac80211 by passing in the
correct, already-computed arguments.
Signed-off-by: Daniel C Halperin <daniel.c.halperin@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-rx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rx.c | 204 |
1 files changed, 77 insertions, 127 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 43b2fce4cbf0..092d3276175a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -853,61 +853,12 @@ static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) | |||
853 | } | 853 | } |
854 | 854 | ||
855 | static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, | 855 | static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, |
856 | int include_phy, | 856 | struct ieee80211_hdr *hdr, |
857 | struct iwl_rx_mem_buffer *rxb, | 857 | u16 len, |
858 | struct ieee80211_rx_status *stats) | 858 | u32 ampdu_status, |
859 | struct iwl_rx_mem_buffer *rxb, | ||
860 | struct ieee80211_rx_status *stats) | ||
859 | { | 861 | { |
860 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
861 | struct iwl_rx_phy_res *rx_start = (include_phy) ? | ||
862 | (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : NULL; | ||
863 | struct ieee80211_hdr *hdr; | ||
864 | u16 len; | ||
865 | __le32 *rx_end; | ||
866 | unsigned int skblen; | ||
867 | u32 ampdu_status; | ||
868 | u32 ampdu_status_legacy; | ||
869 | |||
870 | if (!include_phy && priv->last_phy_res[0]) | ||
871 | rx_start = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; | ||
872 | |||
873 | if (!rx_start) { | ||
874 | IWL_ERR(priv, "MPDU frame without a PHY data\n"); | ||
875 | return; | ||
876 | } | ||
877 | if (include_phy) { | ||
878 | hdr = (struct ieee80211_hdr *)((u8 *) &rx_start[1] + | ||
879 | rx_start->cfg_phy_cnt); | ||
880 | |||
881 | len = le16_to_cpu(rx_start->byte_count); | ||
882 | |||
883 | rx_end = (__le32 *)((u8 *) &pkt->u.raw[0] + | ||
884 | sizeof(struct iwl_rx_phy_res) + | ||
885 | rx_start->cfg_phy_cnt + len); | ||
886 | |||
887 | } else { | ||
888 | struct iwl4965_rx_mpdu_res_start *amsdu = | ||
889 | (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; | ||
890 | |||
891 | hdr = (struct ieee80211_hdr *)(pkt->u.raw + | ||
892 | sizeof(struct iwl4965_rx_mpdu_res_start)); | ||
893 | len = le16_to_cpu(amsdu->byte_count); | ||
894 | rx_start->byte_count = amsdu->byte_count; | ||
895 | rx_end = (__le32 *) (((u8 *) hdr) + len); | ||
896 | } | ||
897 | |||
898 | ampdu_status = le32_to_cpu(*rx_end); | ||
899 | skblen = ((u8 *) rx_end - (u8 *) &pkt->u.raw[0]) + sizeof(u32); | ||
900 | |||
901 | if (!include_phy) { | ||
902 | /* New status scheme, need to translate */ | ||
903 | ampdu_status_legacy = ampdu_status; | ||
904 | ampdu_status = iwl_translate_rx_status(priv, ampdu_status); | ||
905 | } | ||
906 | |||
907 | /* start from MAC */ | ||
908 | skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); | ||
909 | skb_put(rxb->skb, len); /* end where data ends */ | ||
910 | |||
911 | /* We only process data packets if the interface is open */ | 862 | /* We only process data packets if the interface is open */ |
912 | if (unlikely(!priv->is_open)) { | 863 | if (unlikely(!priv->is_open)) { |
913 | IWL_DEBUG_DROP_LIMIT(priv, | 864 | IWL_DEBUG_DROP_LIMIT(priv, |
@@ -915,13 +866,15 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
915 | return; | 866 | return; |
916 | } | 867 | } |
917 | 868 | ||
918 | hdr = (struct ieee80211_hdr *)rxb->skb->data; | 869 | /* In case of HW accelerated crypto and bad decryption, drop */ |
919 | |||
920 | /* in case of HW accelerated crypto and bad decryption, drop */ | ||
921 | if (!priv->cfg->mod_params->sw_crypto && | 870 | if (!priv->cfg->mod_params->sw_crypto && |
922 | iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) | 871 | iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) |
923 | return; | 872 | return; |
924 | 873 | ||
874 | /* Resize SKB from mac header to end of packet */ | ||
875 | skb_reserve(rxb->skb, (void *)hdr - (void *)rxb->skb->data); | ||
876 | skb_put(rxb->skb, len); | ||
877 | |||
925 | iwl_update_stats(priv, false, hdr->frame_control, len); | 878 | iwl_update_stats(priv, false, hdr->frame_control, len); |
926 | memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); | 879 | memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats)); |
927 | ieee80211_rx_irqsafe(priv->hw, rxb->skb); | 880 | ieee80211_rx_irqsafe(priv->hw, rxb->skb); |
@@ -955,25 +908,66 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, | |||
955 | struct ieee80211_hdr *header; | 908 | struct ieee80211_hdr *header; |
956 | struct ieee80211_rx_status rx_status; | 909 | struct ieee80211_rx_status rx_status; |
957 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | 910 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; |
958 | /* Use phy data (Rx signal strength, etc.) contained within | 911 | struct iwl_rx_phy_res *phy_res; |
959 | * this rx packet for legacy frames, | 912 | __le32 rx_pkt_status; |
960 | * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ | 913 | struct iwl4965_rx_mpdu_res_start *amsdu; |
961 | int include_phy = (pkt->hdr.cmd == REPLY_RX); | 914 | u32 len; |
962 | struct iwl_rx_phy_res *rx_start = (include_phy) ? | 915 | u32 ampdu_status; |
963 | (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : | ||
964 | (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; | ||
965 | __le32 *rx_end; | ||
966 | unsigned int len = 0; | ||
967 | u16 fc; | 916 | u16 fc; |
968 | u8 network_packet; | ||
969 | 917 | ||
970 | rx_status.mactime = le64_to_cpu(rx_start->timestamp); | 918 | /** |
919 | * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. | ||
920 | * REPLY_RX: physical layer info is in this buffer | ||
921 | * REPLY_RX_MPDU_CMD: physical layer info was sent in separate | ||
922 | * command and cached in priv->last_phy_res | ||
923 | * | ||
924 | * Here we set up local variables depending on which command is | ||
925 | * received. | ||
926 | */ | ||
927 | if (pkt->hdr.cmd == REPLY_RX) { | ||
928 | phy_res = (struct iwl_rx_phy_res *)pkt->u.raw; | ||
929 | header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res) | ||
930 | + phy_res->cfg_phy_cnt); | ||
931 | |||
932 | len = le16_to_cpu(phy_res->byte_count); | ||
933 | rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) + | ||
934 | phy_res->cfg_phy_cnt + len); | ||
935 | ampdu_status = le32_to_cpu(rx_pkt_status); | ||
936 | } else { | ||
937 | if (!priv->last_phy_res[0]) { | ||
938 | IWL_ERR(priv, "MPDU frame without cached PHY data\n"); | ||
939 | return; | ||
940 | } | ||
941 | phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; | ||
942 | amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; | ||
943 | header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); | ||
944 | len = le16_to_cpu(amsdu->byte_count); | ||
945 | rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len); | ||
946 | ampdu_status = iwl_translate_rx_status(priv, | ||
947 | le32_to_cpu(rx_pkt_status)); | ||
948 | } | ||
949 | |||
950 | if ((unlikely(phy_res->cfg_phy_cnt > 20))) { | ||
951 | IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", | ||
952 | phy_res->cfg_phy_cnt); | ||
953 | return; | ||
954 | } | ||
955 | |||
956 | if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || | ||
957 | !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { | ||
958 | IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", | ||
959 | le32_to_cpu(rx_pkt_status)); | ||
960 | return; | ||
961 | } | ||
962 | |||
963 | /* rx_status carries information about the packet to mac80211 */ | ||
964 | rx_status.mactime = le64_to_cpu(phy_res->timestamp); | ||
971 | rx_status.freq = | 965 | rx_status.freq = |
972 | ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel)); | 966 | ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel)); |
973 | rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? | 967 | rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? |
974 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | 968 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; |
975 | rx_status.rate_idx = | 969 | rx_status.rate_idx = |
976 | iwl_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags)); | 970 | iwl_hwrate_to_plcp_idx(le32_to_cpu(phy_res->rate_n_flags)); |
977 | if (rx_status.band == IEEE80211_BAND_5GHZ) | 971 | if (rx_status.band == IEEE80211_BAND_5GHZ) |
978 | rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; | 972 | rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; |
979 | 973 | ||
@@ -983,54 +977,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, | |||
983 | * this W/A doesn't propagate it to the mac80211 */ | 977 | * this W/A doesn't propagate it to the mac80211 */ |
984 | /*rx_status.flag |= RX_FLAG_TSFT;*/ | 978 | /*rx_status.flag |= RX_FLAG_TSFT;*/ |
985 | 979 | ||
986 | if ((unlikely(rx_start->cfg_phy_cnt > 20))) { | 980 | priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); |
987 | IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", | ||
988 | rx_start->cfg_phy_cnt); | ||
989 | return; | ||
990 | } | ||
991 | |||
992 | if (!include_phy) { | ||
993 | if (priv->last_phy_res[0]) | ||
994 | rx_start = (struct iwl_rx_phy_res *) | ||
995 | &priv->last_phy_res[1]; | ||
996 | else | ||
997 | rx_start = NULL; | ||
998 | } | ||
999 | |||
1000 | if (!rx_start) { | ||
1001 | IWL_ERR(priv, "MPDU frame without a PHY data\n"); | ||
1002 | return; | ||
1003 | } | ||
1004 | |||
1005 | if (include_phy) { | ||
1006 | header = (struct ieee80211_hdr *)((u8 *) &rx_start[1] | ||
1007 | + rx_start->cfg_phy_cnt); | ||
1008 | |||
1009 | len = le16_to_cpu(rx_start->byte_count); | ||
1010 | rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + | ||
1011 | sizeof(struct iwl_rx_phy_res) + len); | ||
1012 | } else { | ||
1013 | struct iwl4965_rx_mpdu_res_start *amsdu = | ||
1014 | (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; | ||
1015 | |||
1016 | header = (void *)(pkt->u.raw + | ||
1017 | sizeof(struct iwl4965_rx_mpdu_res_start)); | ||
1018 | len = le16_to_cpu(amsdu->byte_count); | ||
1019 | rx_end = (__le32 *) (pkt->u.raw + | ||
1020 | sizeof(struct iwl4965_rx_mpdu_res_start) + len); | ||
1021 | } | ||
1022 | |||
1023 | if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) || | ||
1024 | !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) { | ||
1025 | IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", | ||
1026 | le32_to_cpu(*rx_end)); | ||
1027 | return; | ||
1028 | } | ||
1029 | |||
1030 | priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); | ||
1031 | 981 | ||
1032 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ | 982 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ |
1033 | rx_status.signal = iwl_calc_rssi(priv, rx_start); | 983 | rx_status.signal = iwl_calc_rssi(priv, phy_res); |
1034 | 984 | ||
1035 | /* Meaningful noise values are available only from beacon statistics, | 985 | /* Meaningful noise values are available only from beacon statistics, |
1036 | * which are gathered only when associated, and indicate noise | 986 | * which are gathered only when associated, and indicate noise |
@@ -1050,10 +1000,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, | |||
1050 | if (!iwl_is_associated(priv)) | 1000 | if (!iwl_is_associated(priv)) |
1051 | priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | 1001 | priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; |
1052 | 1002 | ||
1053 | /* Set "1" to report good data frames in groups of 100 */ | ||
1054 | #ifdef CONFIG_IWLWIFI_DEBUG | 1003 | #ifdef CONFIG_IWLWIFI_DEBUG |
1004 | /* Set "1" to report good data frames in groups of 100 */ | ||
1055 | if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) | 1005 | if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) |
1056 | iwl_dbg_report_frame(priv, rx_start, len, header, 1); | 1006 | iwl_dbg_report_frame(priv, phy_res, len, header, 1); |
1057 | #endif | 1007 | #endif |
1058 | iwl_dbg_log_rx_data_frame(priv, len, header); | 1008 | iwl_dbg_log_rx_data_frame(priv, len, header); |
1059 | IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", | 1009 | IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", |
@@ -1073,18 +1023,18 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, | |||
1073 | * new 802.11n radiotap field "RX chains" that is defined | 1023 | * new 802.11n radiotap field "RX chains" that is defined |
1074 | * as a bitmask. | 1024 | * as a bitmask. |
1075 | */ | 1025 | */ |
1076 | rx_status.antenna = le16_to_cpu(rx_start->phy_flags & | 1026 | rx_status.antenna = |
1077 | RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; | 1027 | le16_to_cpu(phy_res->phy_flags & RX_RES_PHY_FLAGS_ANTENNA_MSK) |
1028 | >> RX_RES_PHY_FLAGS_ANTENNA_POS; | ||
1078 | 1029 | ||
1079 | /* set the preamble flag if appropriate */ | 1030 | /* set the preamble flag if appropriate */ |
1080 | if (rx_start->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) | 1031 | if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) |
1081 | rx_status.flag |= RX_FLAG_SHORTPRE; | 1032 | rx_status.flag |= RX_FLAG_SHORTPRE; |
1082 | 1033 | ||
1083 | network_packet = iwl_is_network_packet(priv, header); | 1034 | if (iwl_is_network_packet(priv, header)) { |
1084 | if (network_packet) { | ||
1085 | priv->last_rx_rssi = rx_status.signal; | 1035 | priv->last_rx_rssi = rx_status.signal; |
1086 | priv->last_beacon_time = priv->ucode_beacon_time; | 1036 | priv->last_beacon_time = priv->ucode_beacon_time; |
1087 | priv->last_tsf = le64_to_cpu(rx_start->timestamp); | 1037 | priv->last_tsf = le64_to_cpu(phy_res->timestamp); |
1088 | } | 1038 | } |
1089 | 1039 | ||
1090 | fc = le16_to_cpu(header->frame_control); | 1040 | fc = le16_to_cpu(header->frame_control); |
@@ -1096,8 +1046,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, | |||
1096 | header->addr2); | 1046 | header->addr2); |
1097 | /* fall through */ | 1047 | /* fall through */ |
1098 | default: | 1048 | default: |
1099 | iwl_pass_packet_to_mac80211(priv, include_phy, rxb, | 1049 | iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, |
1100 | &rx_status); | 1050 | rxb, &rx_status); |
1101 | break; | 1051 | break; |
1102 | 1052 | ||
1103 | } | 1053 | } |