aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2010-03-17 16:34:36 -0400
committerReinette Chatre <reinette.chatre@intel.com>2010-03-25 14:19:54 -0400
commit8d801080dd8d28bf7d85cacba131f18b7653ee49 (patch)
treedbc76a2a17d979695dfdfde95698c4eb72c95cfe /drivers/net/wireless/iwlwifi/iwl-agn-lib.c
parent54b81550dd674466fe7d01629d2aab015c545a1e (diff)
iwlwifi: more clean up to move agn only rx functions from iwlcore to iwlagn
Move more functions only used by agn driver from iwlcore to iwlagn. Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-lib.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c436
1 files changed, 433 insertions, 3 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 3117382cfd48..226862d3d5ac 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -26,7 +26,7 @@
26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
27 * 27 *
28 *****************************************************************************/ 28 *****************************************************************************/
29 29#include <linux/etherdevice.h>
30#include <linux/kernel.h> 30#include <linux/kernel.h>
31#include <linux/module.h> 31#include <linux/module.h>
32#include <linux/init.h> 32#include <linux/init.h>
@@ -80,7 +80,7 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
80 info->status.rates[0].count = tx_resp->failure_frame + 1; 80 info->status.rates[0].count = tx_resp->failure_frame + 1;
81 info->flags &= ~IEEE80211_TX_CTL_AMPDU; 81 info->flags &= ~IEEE80211_TX_CTL_AMPDU;
82 info->flags |= iwl_tx_status_to_mac80211(status); 82 info->flags |= iwl_tx_status_to_mac80211(status);
83 iwl_hwrate_to_tx_control(priv, rate_n_flags, info); 83 iwlagn_hwrate_to_tx_control(priv, rate_n_flags, info);
84 84
85 /* FIXME: code repetition end */ 85 /* FIXME: code repetition end */
86 86
@@ -225,7 +225,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
225 225
226 info->status.rates[0].count = tx_resp->failure_frame + 1; 226 info->status.rates[0].count = tx_resp->failure_frame + 1;
227 info->flags |= iwl_tx_status_to_mac80211(status); 227 info->flags |= iwl_tx_status_to_mac80211(status);
228 iwl_hwrate_to_tx_control(priv, 228 iwlagn_hwrate_to_tx_control(priv,
229 le32_to_cpu(tx_resp->rate_n_flags), 229 le32_to_cpu(tx_resp->rate_n_flags),
230 info); 230 info);
231 231
@@ -709,3 +709,433 @@ int iwlagn_rxq_stop(struct iwl_priv *priv)
709 709
710 return 0; 710 return 0;
711} 711}
712
713int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
714{
715 int idx = 0;
716 int band_offset = 0;
717
718 /* HT rate format: mac80211 wants an MCS number, which is just LSB */
719 if (rate_n_flags & RATE_MCS_HT_MSK) {
720 idx = (rate_n_flags & 0xff);
721 return idx;
722 /* Legacy rate format, search for match in table */
723 } else {
724 if (band == IEEE80211_BAND_5GHZ)
725 band_offset = IWL_FIRST_OFDM_RATE;
726 for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
727 if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
728 return idx - band_offset;
729 }
730
731 return -1;
732}
733
734/* Calc max signal level (dBm) among 3 possible receivers */
735static inline int iwlagn_calc_rssi(struct iwl_priv *priv,
736 struct iwl_rx_phy_res *rx_resp)
737{
738 return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
739}
740
741#ifdef CONFIG_IWLWIFI_DEBUG
742/**
743 * iwlagn_dbg_report_frame - dump frame to syslog during debug sessions
744 *
745 * You may hack this function to show different aspects of received frames,
746 * including selective frame dumps.
747 * group100 parameter selects whether to show 1 out of 100 good data frames.
748 * All beacon and probe response frames are printed.
749 */
750static void iwlagn_dbg_report_frame(struct iwl_priv *priv,
751 struct iwl_rx_phy_res *phy_res, u16 length,
752 struct ieee80211_hdr *header, int group100)
753{
754 u32 to_us;
755 u32 print_summary = 0;
756 u32 print_dump = 0; /* set to 1 to dump all frames' contents */
757 u32 hundred = 0;
758 u32 dataframe = 0;
759 __le16 fc;
760 u16 seq_ctl;
761 u16 channel;
762 u16 phy_flags;
763 u32 rate_n_flags;
764 u32 tsf_low;
765 int rssi;
766
767 if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX)))
768 return;
769
770 /* MAC header */
771 fc = header->frame_control;
772 seq_ctl = le16_to_cpu(header->seq_ctrl);
773
774 /* metadata */
775 channel = le16_to_cpu(phy_res->channel);
776 phy_flags = le16_to_cpu(phy_res->phy_flags);
777 rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
778
779 /* signal statistics */
780 rssi = iwlagn_calc_rssi(priv, phy_res);
781 tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff;
782
783 to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
784
785 /* if data frame is to us and all is good,
786 * (optionally) print summary for only 1 out of every 100 */
787 if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) ==
788 cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
789 dataframe = 1;
790 if (!group100)
791 print_summary = 1; /* print each frame */
792 else if (priv->framecnt_to_us < 100) {
793 priv->framecnt_to_us++;
794 print_summary = 0;
795 } else {
796 priv->framecnt_to_us = 0;
797 print_summary = 1;
798 hundred = 1;
799 }
800 } else {
801 /* print summary for all other frames */
802 print_summary = 1;
803 }
804
805 if (print_summary) {
806 char *title;
807 int rate_idx;
808 u32 bitrate;
809
810 if (hundred)
811 title = "100Frames";
812 else if (ieee80211_has_retry(fc))
813 title = "Retry";
814 else if (ieee80211_is_assoc_resp(fc))
815 title = "AscRsp";
816 else if (ieee80211_is_reassoc_resp(fc))
817 title = "RasRsp";
818 else if (ieee80211_is_probe_resp(fc)) {
819 title = "PrbRsp";
820 print_dump = 1; /* dump frame contents */
821 } else if (ieee80211_is_beacon(fc)) {
822 title = "Beacon";
823 print_dump = 1; /* dump frame contents */
824 } else if (ieee80211_is_atim(fc))
825 title = "ATIM";
826 else if (ieee80211_is_auth(fc))
827 title = "Auth";
828 else if (ieee80211_is_deauth(fc))
829 title = "DeAuth";
830 else if (ieee80211_is_disassoc(fc))
831 title = "DisAssoc";
832 else
833 title = "Frame";
834
835 rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
836 if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) {
837 bitrate = 0;
838 WARN_ON_ONCE(1);
839 } else {
840 bitrate = iwl_rates[rate_idx].ieee / 2;
841 }
842
843 /* print frame summary.
844 * MAC addresses show just the last byte (for brevity),
845 * but you can hack it to show more, if you'd like to. */
846 if (dataframe)
847 IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
848 "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
849 title, le16_to_cpu(fc), header->addr1[5],
850 length, rssi, channel, bitrate);
851 else {
852 /* src/dst addresses assume managed mode */
853 IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, src=0x%02x, "
854 "len=%u, rssi=%d, tim=%lu usec, "
855 "phy=0x%02x, chnl=%d\n",
856 title, le16_to_cpu(fc), header->addr1[5],
857 header->addr3[5], length, rssi,
858 tsf_low - priv->scan_start_tsf,
859 phy_flags, channel);
860 }
861 }
862 if (print_dump)
863 iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
864}
865#endif
866
867static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
868{
869 u32 decrypt_out = 0;
870
871 if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) ==
872 RX_RES_STATUS_STATION_FOUND)
873 decrypt_out |= (RX_RES_STATUS_STATION_FOUND |
874 RX_RES_STATUS_NO_STATION_INFO_MISMATCH);
875
876 decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK);
877
878 /* packet was not encrypted */
879 if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
880 RX_RES_STATUS_SEC_TYPE_NONE)
881 return decrypt_out;
882
883 /* packet was encrypted with unknown alg */
884 if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
885 RX_RES_STATUS_SEC_TYPE_ERR)
886 return decrypt_out;
887
888 /* decryption was not done in HW */
889 if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) !=
890 RX_MPDU_RES_STATUS_DEC_DONE_MSK)
891 return decrypt_out;
892
893 switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) {
894
895 case RX_RES_STATUS_SEC_TYPE_CCMP:
896 /* alg is CCM: check MIC only */
897 if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK))
898 /* Bad MIC */
899 decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
900 else
901 decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
902
903 break;
904
905 case RX_RES_STATUS_SEC_TYPE_TKIP:
906 if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) {
907 /* Bad TTAK */
908 decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK;
909 break;
910 }
911 /* fall through if TTAK OK */
912 default:
913 if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK))
914 decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
915 else
916 decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
917 break;
918 };
919
920 IWL_DEBUG_RX(priv, "decrypt_in:0x%x decrypt_out = 0x%x\n",
921 decrypt_in, decrypt_out);
922
923 return decrypt_out;
924}
925
926static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
927 struct ieee80211_hdr *hdr,
928 u16 len,
929 u32 ampdu_status,
930 struct iwl_rx_mem_buffer *rxb,
931 struct ieee80211_rx_status *stats)
932{
933 struct sk_buff *skb;
934 int ret = 0;
935 __le16 fc = hdr->frame_control;
936
937 /* We only process data packets if the interface is open */
938 if (unlikely(!priv->is_open)) {
939 IWL_DEBUG_DROP_LIMIT(priv,
940 "Dropping packet while interface is not open.\n");
941 return;
942 }
943
944 /* In case of HW accelerated crypto and bad decryption, drop */
945 if (!priv->cfg->mod_params->sw_crypto &&
946 iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
947 return;
948
949 skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC);
950 if (!skb) {
951 IWL_ERR(priv, "alloc_skb failed\n");
952 return;
953 }
954
955 skb_reserve(skb, IWL_LINK_HDR_MAX);
956 skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
957
958 /* mac80211 currently doesn't support paged SKB. Convert it to
959 * linear SKB for management frame and data frame requires
960 * software decryption or software defragementation. */
961 if (ieee80211_is_mgmt(fc) ||
962 ieee80211_has_protected(fc) ||
963 ieee80211_has_morefrags(fc) ||
964 le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG ||
965 (ieee80211_is_data_qos(fc) &&
966 *ieee80211_get_qos_ctl(hdr) &
967 IEEE80211_QOS_CONTROL_A_MSDU_PRESENT))
968 ret = skb_linearize(skb);
969 else
970 ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
971 0 : -ENOMEM;
972
973 if (ret) {
974 kfree_skb(skb);
975 goto out;
976 }
977
978 /*
979 * XXX: We cannot touch the page and its virtual memory (hdr) after
980 * here. It might have already been freed by the above skb change.
981 */
982
983 iwl_update_stats(priv, false, fc, len);
984 memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
985
986 ieee80211_rx(priv->hw, skb);
987 out:
988 priv->alloc_rxb_page--;
989 rxb->page = NULL;
990}
991
992/* Called for REPLY_RX (legacy ABG frames), or
993 * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
994void iwlagn_rx_reply_rx(struct iwl_priv *priv,
995 struct iwl_rx_mem_buffer *rxb)
996{
997 struct ieee80211_hdr *header;
998 struct ieee80211_rx_status rx_status;
999 struct iwl_rx_packet *pkt = rxb_addr(rxb);
1000 struct iwl_rx_phy_res *phy_res;
1001 __le32 rx_pkt_status;
1002 struct iwl4965_rx_mpdu_res_start *amsdu;
1003 u32 len;
1004 u32 ampdu_status;
1005 u32 rate_n_flags;
1006
1007 /**
1008 * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently.
1009 * REPLY_RX: physical layer info is in this buffer
1010 * REPLY_RX_MPDU_CMD: physical layer info was sent in separate
1011 * command and cached in priv->last_phy_res
1012 *
1013 * Here we set up local variables depending on which command is
1014 * received.
1015 */
1016 if (pkt->hdr.cmd == REPLY_RX) {
1017 phy_res = (struct iwl_rx_phy_res *)pkt->u.raw;
1018 header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res)
1019 + phy_res->cfg_phy_cnt);
1020
1021 len = le16_to_cpu(phy_res->byte_count);
1022 rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) +
1023 phy_res->cfg_phy_cnt + len);
1024 ampdu_status = le32_to_cpu(rx_pkt_status);
1025 } else {
1026 if (!priv->last_phy_res[0]) {
1027 IWL_ERR(priv, "MPDU frame without cached PHY data\n");
1028 return;
1029 }
1030 phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1];
1031 amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
1032 header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu));
1033 len = le16_to_cpu(amsdu->byte_count);
1034 rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len);
1035 ampdu_status = iwlagn_translate_rx_status(priv,
1036 le32_to_cpu(rx_pkt_status));
1037 }
1038
1039 if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
1040 IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n",
1041 phy_res->cfg_phy_cnt);
1042 return;
1043 }
1044
1045 if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
1046 !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
1047 IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
1048 le32_to_cpu(rx_pkt_status));
1049 return;
1050 }
1051
1052 /* This will be used in several places later */
1053 rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
1054
1055 /* rx_status carries information about the packet to mac80211 */
1056 rx_status.mactime = le64_to_cpu(phy_res->timestamp);
1057 rx_status.freq =
1058 ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel));
1059 rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
1060 IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
1061 rx_status.rate_idx =
1062 iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
1063 rx_status.flag = 0;
1064
1065 /* TSF isn't reliable. In order to allow smooth user experience,
1066 * this W/A doesn't propagate it to the mac80211 */
1067 /*rx_status.flag |= RX_FLAG_TSFT;*/
1068
1069 priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
1070
1071 /* Find max signal strength (dBm) among 3 antenna/receiver chains */
1072 rx_status.signal = iwlagn_calc_rssi(priv, phy_res);
1073
1074 /* Meaningful noise values are available only from beacon statistics,
1075 * which are gathered only when associated, and indicate noise
1076 * only for the associated network channel ...
1077 * Ignore these noise values while scanning (other channels) */
1078 if (iwl_is_associated(priv) &&
1079 !test_bit(STATUS_SCANNING, &priv->status)) {
1080 rx_status.noise = priv->last_rx_noise;
1081 } else {
1082 rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
1083 }
1084
1085 /* Reset beacon noise level if not associated. */
1086 if (!iwl_is_associated(priv))
1087 priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
1088
1089#ifdef CONFIG_IWLWIFI_DEBUG
1090 /* Set "1" to report good data frames in groups of 100 */
1091 if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX))
1092 iwlagn_dbg_report_frame(priv, phy_res, len, header, 1);
1093#endif
1094 iwl_dbg_log_rx_data_frame(priv, len, header);
1095 IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, TSF %llu\n",
1096 rx_status.signal, rx_status.noise,
1097 (unsigned long long)rx_status.mactime);
1098
1099 /*
1100 * "antenna number"
1101 *
1102 * It seems that the antenna field in the phy flags value
1103 * is actually a bit field. This is undefined by radiotap,
1104 * it wants an actual antenna number but I always get "7"
1105 * for most legacy frames I receive indicating that the
1106 * same frame was received on all three RX chains.
1107 *
1108 * I think this field should be removed in favor of a
1109 * new 802.11n radiotap field "RX chains" that is defined
1110 * as a bitmask.
1111 */
1112 rx_status.antenna =
1113 (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK)
1114 >> RX_RES_PHY_FLAGS_ANTENNA_POS;
1115
1116 /* set the preamble flag if appropriate */
1117 if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
1118 rx_status.flag |= RX_FLAG_SHORTPRE;
1119
1120 /* Set up the HT phy flags */
1121 if (rate_n_flags & RATE_MCS_HT_MSK)
1122 rx_status.flag |= RX_FLAG_HT;
1123 if (rate_n_flags & RATE_MCS_HT40_MSK)
1124 rx_status.flag |= RX_FLAG_40MHZ;
1125 if (rate_n_flags & RATE_MCS_SGI_MSK)
1126 rx_status.flag |= RX_FLAG_SHORT_GI;
1127
1128 iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status,
1129 rxb, &rx_status);
1130}
1131
1132/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
1133 * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
1134void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
1135 struct iwl_rx_mem_buffer *rxb)
1136{
1137 struct iwl_rx_packet *pkt = rxb_addr(rxb);
1138 priv->last_phy_res[0] = 1;
1139 memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
1140 sizeof(struct iwl_rx_phy_res));
1141}