aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorDaniel C Halperin <daniel.c.halperin@intel.com>2009-08-13 16:30:56 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-20 11:33:11 -0400
commit9f30e04e041cf9943940f71fd76094dd5a237018 (patch)
tree9ce669ba936410be62cefb29cda708428d30cf90 /drivers/net/wireless
parent367ca28da433ed9639468be851e1f33468e3485e (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')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c204
2 files changed, 78 insertions, 127 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 68d7719071f7..9398ad7e42b1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -1156,6 +1156,7 @@ struct iwl_wep_cmd {
1156#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) 1156#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2)
1157#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) 1157#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3)
1158#define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0) 1158#define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0)
1159#define RX_RES_PHY_FLAGS_ANTENNA_POS 4
1159 1160
1160#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) 1161#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8)
1161#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) 1162#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8)
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
855static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, 855static 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 }