diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2008-05-15 01:54:04 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-05-21 21:47:58 -0400 |
commit | 4f40e4d9fb8fe028db9ba2a7b4d3ac7328f73bbc (patch) | |
tree | 2fee89bbf870a188fb36c0c6a1cecc5c48fe8173 /drivers/net/wireless/iwlwifi/iwl-sta.c | |
parent | 57bd1bea485bf6f37ff365dec2203ba6467b41a1 (diff) |
iwlwifi: move more station managment into iwl-sta.c
This patch moves station management functions into iwl-sta.c (iwlcore).
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-sta.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index f2267047d102..c8e468fb3caa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -117,6 +117,130 @@ int iwl_send_add_sta(struct iwl_priv *priv, | |||
117 | } | 117 | } |
118 | EXPORT_SYMBOL(iwl_send_add_sta); | 118 | EXPORT_SYMBOL(iwl_send_add_sta); |
119 | 119 | ||
120 | #ifdef CONFIG_IWL4965_HT | ||
121 | |||
122 | static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, | ||
123 | struct ieee80211_ht_info *sta_ht_inf) | ||
124 | { | ||
125 | __le32 sta_flags; | ||
126 | u8 mimo_ps_mode; | ||
127 | |||
128 | if (!sta_ht_inf || !sta_ht_inf->ht_supported) | ||
129 | goto done; | ||
130 | |||
131 | mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2; | ||
132 | |||
133 | sta_flags = priv->stations[index].sta.station_flags; | ||
134 | |||
135 | sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); | ||
136 | |||
137 | switch (mimo_ps_mode) { | ||
138 | case WLAN_HT_CAP_MIMO_PS_STATIC: | ||
139 | sta_flags |= STA_FLG_MIMO_DIS_MSK; | ||
140 | break; | ||
141 | case WLAN_HT_CAP_MIMO_PS_DYNAMIC: | ||
142 | sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; | ||
143 | break; | ||
144 | case WLAN_HT_CAP_MIMO_PS_DISABLED: | ||
145 | break; | ||
146 | default: | ||
147 | IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode); | ||
148 | break; | ||
149 | } | ||
150 | |||
151 | sta_flags |= cpu_to_le32( | ||
152 | (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); | ||
153 | |||
154 | sta_flags |= cpu_to_le32( | ||
155 | (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); | ||
156 | |||
157 | if (iwl_is_fat_tx_allowed(priv, sta_ht_inf)) | ||
158 | sta_flags |= STA_FLG_FAT_EN_MSK; | ||
159 | else | ||
160 | sta_flags &= ~STA_FLG_FAT_EN_MSK; | ||
161 | |||
162 | priv->stations[index].sta.station_flags = sta_flags; | ||
163 | done: | ||
164 | return; | ||
165 | } | ||
166 | #else | ||
167 | static inline void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, | ||
168 | struct ieee80211_ht_info *sta_ht_info) | ||
169 | { | ||
170 | } | ||
171 | #endif | ||
172 | |||
173 | /** | ||
174 | * iwl_add_station_flags - Add station to tables in driver and device | ||
175 | */ | ||
176 | u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, | ||
177 | u8 flags, struct ieee80211_ht_info *ht_info) | ||
178 | { | ||
179 | int i; | ||
180 | int index = IWL_INVALID_STATION; | ||
181 | struct iwl_station_entry *station; | ||
182 | unsigned long flags_spin; | ||
183 | DECLARE_MAC_BUF(mac); | ||
184 | |||
185 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
186 | if (is_ap) | ||
187 | index = IWL_AP_ID; | ||
188 | else if (is_broadcast_ether_addr(addr)) | ||
189 | index = priv->hw_params.bcast_sta_id; | ||
190 | else | ||
191 | for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { | ||
192 | if (!compare_ether_addr(priv->stations[i].sta.sta.addr, | ||
193 | addr)) { | ||
194 | index = i; | ||
195 | break; | ||
196 | } | ||
197 | |||
198 | if (!priv->stations[i].used && | ||
199 | index == IWL_INVALID_STATION) | ||
200 | index = i; | ||
201 | } | ||
202 | |||
203 | |||
204 | /* These two conditions have the same outcome, but keep them separate | ||
205 | since they have different meanings */ | ||
206 | if (unlikely(index == IWL_INVALID_STATION)) { | ||
207 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
208 | return index; | ||
209 | } | ||
210 | |||
211 | if (priv->stations[index].used && | ||
212 | !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { | ||
213 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
214 | return index; | ||
215 | } | ||
216 | |||
217 | |||
218 | IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); | ||
219 | station = &priv->stations[index]; | ||
220 | station->used = 1; | ||
221 | priv->num_stations++; | ||
222 | |||
223 | /* Set up the REPLY_ADD_STA command to send to device */ | ||
224 | memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); | ||
225 | memcpy(station->sta.sta.addr, addr, ETH_ALEN); | ||
226 | station->sta.mode = 0; | ||
227 | station->sta.sta.sta_id = index; | ||
228 | station->sta.station_flags = 0; | ||
229 | |||
230 | /* BCAST station and IBSS stations do not work in HT mode */ | ||
231 | if (index != priv->hw_params.bcast_sta_id && | ||
232 | priv->iw_mode != IEEE80211_IF_TYPE_IBSS) | ||
233 | iwl_set_ht_add_station(priv, index, ht_info); | ||
234 | |||
235 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
236 | |||
237 | /* Add station to device's station table */ | ||
238 | iwl_send_add_sta(priv, &station->sta, flags); | ||
239 | return index; | ||
240 | |||
241 | } | ||
242 | EXPORT_SYMBOL(iwl_add_station_flags); | ||
243 | |||
120 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv) | 244 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv) |
121 | { | 245 | { |
122 | int i; | 246 | int i; |
@@ -470,3 +594,148 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, | |||
470 | } | 594 | } |
471 | EXPORT_SYMBOL(iwl_send_lq_cmd); | 595 | EXPORT_SYMBOL(iwl_send_lq_cmd); |
472 | 596 | ||
597 | /** | ||
598 | * iwl_sta_init_lq - Initialize a station's hardware rate table | ||
599 | * | ||
600 | * The uCode's station table contains a table of fallback rates | ||
601 | * for automatic fallback during transmission. | ||
602 | * | ||
603 | * NOTE: This sets up a default set of values. These will be replaced later | ||
604 | * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of | ||
605 | * rc80211_simple. | ||
606 | * | ||
607 | * NOTE: Run REPLY_ADD_STA command to set up station table entry, before | ||
608 | * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, | ||
609 | * which requires station table entry to exist). | ||
610 | */ | ||
611 | static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) | ||
612 | { | ||
613 | int i, r; | ||
614 | struct iwl_link_quality_cmd link_cmd = { | ||
615 | .reserved1 = 0, | ||
616 | }; | ||
617 | u16 rate_flags; | ||
618 | |||
619 | /* Set up the rate scaling to start at selected rate, fall back | ||
620 | * all the way down to 1M in IEEE order, and then spin on 1M */ | ||
621 | if (is_ap) | ||
622 | r = IWL_RATE_54M_INDEX; | ||
623 | else if (priv->band == IEEE80211_BAND_5GHZ) | ||
624 | r = IWL_RATE_6M_INDEX; | ||
625 | else | ||
626 | r = IWL_RATE_1M_INDEX; | ||
627 | |||
628 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { | ||
629 | rate_flags = 0; | ||
630 | if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) | ||
631 | rate_flags |= RATE_MCS_CCK_MSK; | ||
632 | |||
633 | /* Use Tx antenna B only */ | ||
634 | rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ | ||
635 | |||
636 | link_cmd.rs_table[i].rate_n_flags = | ||
637 | iwl4965_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); | ||
638 | r = iwl4965_get_prev_ieee_rate(r); | ||
639 | } | ||
640 | |||
641 | link_cmd.general_params.single_stream_ant_msk = 2; | ||
642 | link_cmd.general_params.dual_stream_ant_msk = 3; | ||
643 | link_cmd.agg_params.agg_dis_start_th = 3; | ||
644 | link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); | ||
645 | |||
646 | /* Update the rate scaling for control frame Tx to AP */ | ||
647 | link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; | ||
648 | |||
649 | iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, | ||
650 | sizeof(link_cmd), &link_cmd, NULL); | ||
651 | } | ||
652 | /** | ||
653 | * iwl_rxon_add_station - add station into station table. | ||
654 | * | ||
655 | * there is only one AP station with id= IWL_AP_ID | ||
656 | * NOTE: mutex must be held before calling this fnction | ||
657 | */ | ||
658 | int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) | ||
659 | { | ||
660 | u8 sta_id; | ||
661 | |||
662 | /* Add station to device's station table */ | ||
663 | #ifdef CONFIG_IWL4965_HT | ||
664 | struct ieee80211_conf *conf = &priv->hw->conf; | ||
665 | struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf; | ||
666 | |||
667 | if ((is_ap) && | ||
668 | (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && | ||
669 | (priv->iw_mode == IEEE80211_IF_TYPE_STA)) | ||
670 | sta_id = iwl_add_station_flags(priv, addr, is_ap, | ||
671 | 0, cur_ht_config); | ||
672 | else | ||
673 | #endif /* CONFIG_IWL4965_HT */ | ||
674 | sta_id = iwl_add_station_flags(priv, addr, is_ap, | ||
675 | 0, NULL); | ||
676 | |||
677 | /* Set up default rate scaling table in device's station table */ | ||
678 | iwl_sta_init_lq(priv, addr, is_ap); | ||
679 | |||
680 | return sta_id; | ||
681 | } | ||
682 | EXPORT_SYMBOL(iwl_rxon_add_station); | ||
683 | |||
684 | |||
685 | /** | ||
686 | * iwl_get_sta_id - Find station's index within station table | ||
687 | * | ||
688 | * If new IBSS station, create new entry in station table | ||
689 | */ | ||
690 | int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) | ||
691 | { | ||
692 | int sta_id; | ||
693 | u16 fc = le16_to_cpu(hdr->frame_control); | ||
694 | DECLARE_MAC_BUF(mac); | ||
695 | |||
696 | /* If this frame is broadcast or management, use broadcast station id */ | ||
697 | if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || | ||
698 | is_multicast_ether_addr(hdr->addr1)) | ||
699 | return priv->hw_params.bcast_sta_id; | ||
700 | |||
701 | switch (priv->iw_mode) { | ||
702 | |||
703 | /* If we are a client station in a BSS network, use the special | ||
704 | * AP station entry (that's the only station we communicate with) */ | ||
705 | case IEEE80211_IF_TYPE_STA: | ||
706 | return IWL_AP_ID; | ||
707 | |||
708 | /* If we are an AP, then find the station, or use BCAST */ | ||
709 | case IEEE80211_IF_TYPE_AP: | ||
710 | sta_id = iwl_find_station(priv, hdr->addr1); | ||
711 | if (sta_id != IWL_INVALID_STATION) | ||
712 | return sta_id; | ||
713 | return priv->hw_params.bcast_sta_id; | ||
714 | |||
715 | /* If this frame is going out to an IBSS network, find the station, | ||
716 | * or create a new station table entry */ | ||
717 | case IEEE80211_IF_TYPE_IBSS: | ||
718 | sta_id = iwl_find_station(priv, hdr->addr1); | ||
719 | if (sta_id != IWL_INVALID_STATION) | ||
720 | return sta_id; | ||
721 | |||
722 | /* Create new station table entry */ | ||
723 | sta_id = iwl_add_station_flags(priv, hdr->addr1, | ||
724 | 0, CMD_ASYNC, NULL); | ||
725 | |||
726 | if (sta_id != IWL_INVALID_STATION) | ||
727 | return sta_id; | ||
728 | |||
729 | IWL_DEBUG_DROP("Station %s not in station map. " | ||
730 | "Defaulting to broadcast...\n", | ||
731 | print_mac(mac, hdr->addr1)); | ||
732 | iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); | ||
733 | return priv->hw_params.bcast_sta_id; | ||
734 | |||
735 | default: | ||
736 | IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode); | ||
737 | return priv->hw_params.bcast_sta_id; | ||
738 | } | ||
739 | } | ||
740 | EXPORT_SYMBOL(iwl_get_sta_id); | ||
741 | |||