diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-rx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rx.c | 168 |
1 files changed, 47 insertions, 121 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index f3f6ea49fdd2..7cde9d76ff5d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -376,7 +376,9 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) | |||
376 | { | 376 | { |
377 | int ret; | 377 | int ret; |
378 | unsigned long flags; | 378 | unsigned long flags; |
379 | unsigned int rb_size; | 379 | u32 rb_size; |
380 | const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ | ||
381 | const u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT why this stalls RX */ | ||
380 | 382 | ||
381 | spin_lock_irqsave(&priv->lock, flags); | 383 | spin_lock_irqsave(&priv->lock, flags); |
382 | ret = iwl_grab_nic_access(priv); | 384 | ret = iwl_grab_nic_access(priv); |
@@ -398,26 +400,32 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) | |||
398 | 400 | ||
399 | /* Tell device where to find RBD circular buffer in DRAM */ | 401 | /* Tell device where to find RBD circular buffer in DRAM */ |
400 | iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, | 402 | iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, |
401 | rxq->dma_addr >> 8); | 403 | (u32)(rxq->dma_addr >> 8)); |
402 | 404 | ||
403 | /* Tell device where in DRAM to update its Rx status */ | 405 | /* Tell device where in DRAM to update its Rx status */ |
404 | iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, | 406 | iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, |
405 | (priv->shared_phys + priv->rb_closed_offset) >> 4); | 407 | (priv->shared_phys + priv->rb_closed_offset) >> 4); |
406 | 408 | ||
407 | /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */ | 409 | /* Enable Rx DMA |
410 | * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set becuase of HW bug in | ||
411 | * the credit mechanism in 5000 HW RX FIFO | ||
412 | * Direct rx interrupts to hosts | ||
413 | * Rx buffer size 4 or 8k | ||
414 | * RB timeout 0x10 | ||
415 | * 256 RBDs | ||
416 | */ | ||
408 | iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, | 417 | iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, |
409 | FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | | 418 | FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | |
419 | FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | | ||
410 | FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | | 420 | FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | |
411 | rb_size | | 421 | rb_size| |
412 | /* 0x10 << 4 | */ | 422 | (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| |
413 | (RX_QUEUE_SIZE_LOG << | 423 | (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); |
414 | FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT)); | ||
415 | |||
416 | /* | ||
417 | * iwl_write32(priv,CSR_INT_COAL_REG,0); | ||
418 | */ | ||
419 | 424 | ||
420 | iwl_release_nic_access(priv); | 425 | iwl_release_nic_access(priv); |
426 | |||
427 | iwl_write32(priv, CSR_INT_COALESCING, 0x40); | ||
428 | |||
421 | spin_unlock_irqrestore(&priv->lock, flags); | 429 | spin_unlock_irqrestore(&priv->lock, flags); |
422 | 430 | ||
423 | return 0; | 431 | return 0; |
@@ -789,107 +797,6 @@ static inline void iwl_dbg_report_frame(struct iwl_priv *priv, | |||
789 | } | 797 | } |
790 | #endif | 798 | #endif |
791 | 799 | ||
792 | static void iwl_add_radiotap(struct iwl_priv *priv, | ||
793 | struct sk_buff *skb, | ||
794 | struct iwl_rx_phy_res *rx_start, | ||
795 | struct ieee80211_rx_status *stats, | ||
796 | u32 ampdu_status) | ||
797 | { | ||
798 | s8 signal = stats->signal; | ||
799 | s8 noise = 0; | ||
800 | int rate = stats->rate_idx; | ||
801 | u64 tsf = stats->mactime; | ||
802 | __le16 antenna; | ||
803 | __le16 phy_flags_hw = rx_start->phy_flags; | ||
804 | struct iwl4965_rt_rx_hdr { | ||
805 | struct ieee80211_radiotap_header rt_hdr; | ||
806 | __le64 rt_tsf; /* TSF */ | ||
807 | u8 rt_flags; /* radiotap packet flags */ | ||
808 | u8 rt_rate; /* rate in 500kb/s */ | ||
809 | __le16 rt_channelMHz; /* channel in MHz */ | ||
810 | __le16 rt_chbitmask; /* channel bitfield */ | ||
811 | s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ | ||
812 | s8 rt_dbmnoise; | ||
813 | u8 rt_antenna; /* antenna number */ | ||
814 | } __attribute__ ((packed)) *iwl4965_rt; | ||
815 | |||
816 | /* TODO: We won't have enough headroom for HT frames. Fix it later. */ | ||
817 | if (skb_headroom(skb) < sizeof(*iwl4965_rt)) { | ||
818 | if (net_ratelimit()) | ||
819 | printk(KERN_ERR "not enough headroom [%d] for " | ||
820 | "radiotap head [%zd]\n", | ||
821 | skb_headroom(skb), sizeof(*iwl4965_rt)); | ||
822 | return; | ||
823 | } | ||
824 | |||
825 | /* put radiotap header in front of 802.11 header and data */ | ||
826 | iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt)); | ||
827 | |||
828 | /* initialise radiotap header */ | ||
829 | iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; | ||
830 | iwl4965_rt->rt_hdr.it_pad = 0; | ||
831 | |||
832 | /* total header + data */ | ||
833 | put_unaligned_le16(sizeof(*iwl4965_rt), &iwl4965_rt->rt_hdr.it_len); | ||
834 | |||
835 | /* Indicate all the fields we add to the radiotap header */ | ||
836 | put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) | | ||
837 | (1 << IEEE80211_RADIOTAP_FLAGS) | | ||
838 | (1 << IEEE80211_RADIOTAP_RATE) | | ||
839 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
840 | (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | | ||
841 | (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | | ||
842 | (1 << IEEE80211_RADIOTAP_ANTENNA), | ||
843 | &(iwl4965_rt->rt_hdr.it_present)); | ||
844 | |||
845 | /* Zero the flags, we'll add to them as we go */ | ||
846 | iwl4965_rt->rt_flags = 0; | ||
847 | |||
848 | put_unaligned_le64(tsf, &iwl4965_rt->rt_tsf); | ||
849 | |||
850 | iwl4965_rt->rt_dbmsignal = signal; | ||
851 | iwl4965_rt->rt_dbmnoise = noise; | ||
852 | |||
853 | /* Convert the channel frequency and set the flags */ | ||
854 | put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz); | ||
855 | if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) | ||
856 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, | ||
857 | &iwl4965_rt->rt_chbitmask); | ||
858 | else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) | ||
859 | put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, | ||
860 | &iwl4965_rt->rt_chbitmask); | ||
861 | else /* 802.11g */ | ||
862 | put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, | ||
863 | &iwl4965_rt->rt_chbitmask); | ||
864 | |||
865 | if (rate == -1) | ||
866 | iwl4965_rt->rt_rate = 0; | ||
867 | else | ||
868 | iwl4965_rt->rt_rate = iwl_rates[rate].ieee; | ||
869 | |||
870 | /* | ||
871 | * "antenna number" | ||
872 | * | ||
873 | * It seems that the antenna field in the phy flags value | ||
874 | * is actually a bitfield. This is undefined by radiotap, | ||
875 | * it wants an actual antenna number but I always get "7" | ||
876 | * for most legacy frames I receive indicating that the | ||
877 | * same frame was received on all three RX chains. | ||
878 | * | ||
879 | * I think this field should be removed in favour of a | ||
880 | * new 802.11n radiotap field "RX chains" that is defined | ||
881 | * as a bitmask. | ||
882 | */ | ||
883 | antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; | ||
884 | iwl4965_rt->rt_antenna = le16_to_cpu(antenna) >> 4; | ||
885 | |||
886 | /* set the preamble flag if appropriate */ | ||
887 | if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) | ||
888 | iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; | ||
889 | |||
890 | stats->flag |= RX_FLAG_RADIOTAP; | ||
891 | } | ||
892 | |||
893 | static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) | 800 | static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) |
894 | { | 801 | { |
895 | /* 0 - mgmt, 1 - cnt, 2 - data */ | 802 | /* 0 - mgmt, 1 - cnt, 2 - data */ |
@@ -1074,9 +981,6 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
1074 | iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) | 981 | iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) |
1075 | return; | 982 | return; |
1076 | 983 | ||
1077 | if (priv->add_radiotap) | ||
1078 | iwl_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status); | ||
1079 | |||
1080 | iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); | 984 | iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); |
1081 | ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); | 985 | ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); |
1082 | priv->alloc_rxb_skb--; | 986 | priv->alloc_rxb_skb--; |
@@ -1130,10 +1034,10 @@ static int iwl_is_network_packet(struct iwl_priv *priv, | |||
1130 | /* Filter incoming packets to determine if they are targeted toward | 1034 | /* Filter incoming packets to determine if they are targeted toward |
1131 | * this network, discarding packets coming from ourselves */ | 1035 | * this network, discarding packets coming from ourselves */ |
1132 | switch (priv->iw_mode) { | 1036 | switch (priv->iw_mode) { |
1133 | case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ | 1037 | case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source | BSSID */ |
1134 | /* packets to our IBSS update information */ | 1038 | /* packets to our IBSS update information */ |
1135 | return !compare_ether_addr(header->addr3, priv->bssid); | 1039 | return !compare_ether_addr(header->addr3, priv->bssid); |
1136 | case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ | 1040 | case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */ |
1137 | /* packets to our IBSS update information */ | 1041 | /* packets to our IBSS update information */ |
1138 | return !compare_ether_addr(header->addr2, priv->bssid); | 1042 | return !compare_ether_addr(header->addr2, priv->bssid); |
1139 | default: | 1043 | default: |
@@ -1171,9 +1075,11 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, | |||
1171 | if (rx_status.band == IEEE80211_BAND_5GHZ) | 1075 | if (rx_status.band == IEEE80211_BAND_5GHZ) |
1172 | rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; | 1076 | rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; |
1173 | 1077 | ||
1174 | rx_status.antenna = 0; | ||
1175 | rx_status.flag = 0; | 1078 | rx_status.flag = 0; |
1176 | rx_status.flag |= RX_FLAG_TSFT; | 1079 | |
1080 | /* TSF isn't reliable. In order to allow smooth user experience, | ||
1081 | * this W/A doesn't propagate it to the mac80211 */ | ||
1082 | /*rx_status.flag |= RX_FLAG_TSFT;*/ | ||
1177 | 1083 | ||
1178 | if ((unlikely(rx_start->cfg_phy_cnt > 20))) { | 1084 | if ((unlikely(rx_start->cfg_phy_cnt > 20))) { |
1179 | IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n", | 1085 | IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n", |
@@ -1250,8 +1156,28 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, | |||
1250 | rx_status.signal, rx_status.noise, rx_status.signal, | 1156 | rx_status.signal, rx_status.noise, rx_status.signal, |
1251 | (unsigned long long)rx_status.mactime); | 1157 | (unsigned long long)rx_status.mactime); |
1252 | 1158 | ||
1159 | /* | ||
1160 | * "antenna number" | ||
1161 | * | ||
1162 | * It seems that the antenna field in the phy flags value | ||
1163 | * is actually a bitfield. This is undefined by radiotap, | ||
1164 | * it wants an actual antenna number but I always get "7" | ||
1165 | * for most legacy frames I receive indicating that the | ||
1166 | * same frame was received on all three RX chains. | ||
1167 | * | ||
1168 | * I think this field should be removed in favour of a | ||
1169 | * new 802.11n radiotap field "RX chains" that is defined | ||
1170 | * as a bitmask. | ||
1171 | */ | ||
1172 | rx_status.antenna = le16_to_cpu(rx_start->phy_flags & | ||
1173 | RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; | ||
1174 | |||
1175 | /* set the preamble flag if appropriate */ | ||
1176 | if (rx_start->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) | ||
1177 | rx_status.flag |= RX_FLAG_SHORTPRE; | ||
1178 | |||
1253 | /* Take shortcut when only in monitor mode */ | 1179 | /* Take shortcut when only in monitor mode */ |
1254 | if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { | 1180 | if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { |
1255 | iwl_pass_packet_to_mac80211(priv, include_phy, | 1181 | iwl_pass_packet_to_mac80211(priv, include_phy, |
1256 | rxb, &rx_status); | 1182 | rxb, &rx_status); |
1257 | return; | 1183 | return; |
@@ -1268,7 +1194,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, | |||
1268 | switch (fc & IEEE80211_FCTL_FTYPE) { | 1194 | switch (fc & IEEE80211_FCTL_FTYPE) { |
1269 | case IEEE80211_FTYPE_MGMT: | 1195 | case IEEE80211_FTYPE_MGMT: |
1270 | case IEEE80211_FTYPE_DATA: | 1196 | case IEEE80211_FTYPE_DATA: |
1271 | if (priv->iw_mode == IEEE80211_IF_TYPE_AP) | 1197 | if (priv->iw_mode == NL80211_IFTYPE_AP) |
1272 | iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, | 1198 | iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, |
1273 | header->addr2); | 1199 | header->addr2); |
1274 | /* fall through */ | 1200 | /* fall through */ |