diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-rxon.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 259 |
1 files changed, 166 insertions, 93 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 90e12c17801e..02387430f7fe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | |||
@@ -58,8 +58,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, | |||
58 | u8 old_dev_type = send->dev_type; | 58 | u8 old_dev_type = send->dev_type; |
59 | int ret; | 59 | int ret; |
60 | 60 | ||
61 | iwlagn_init_notification_wait(priv, &disable_wait, NULL, | 61 | iwlagn_init_notification_wait(priv, &disable_wait, |
62 | REPLY_WIPAN_DEACTIVATION_COMPLETE); | 62 | REPLY_WIPAN_DEACTIVATION_COMPLETE, |
63 | NULL, NULL); | ||
63 | 64 | ||
64 | send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 65 | send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
65 | send->dev_type = RXON_DEV_TYPE_P2P; | 66 | send->dev_type = RXON_DEV_TYPE_P2P; |
@@ -72,13 +73,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, | |||
72 | IWL_ERR(priv, "Error disabling PAN (%d)\n", ret); | 73 | IWL_ERR(priv, "Error disabling PAN (%d)\n", ret); |
73 | iwlagn_remove_notification(priv, &disable_wait); | 74 | iwlagn_remove_notification(priv, &disable_wait); |
74 | } else { | 75 | } else { |
75 | signed long wait_res; | 76 | ret = iwlagn_wait_notification(priv, &disable_wait, HZ); |
76 | 77 | if (ret) | |
77 | wait_res = iwlagn_wait_notification(priv, &disable_wait, HZ); | ||
78 | if (wait_res == 0) { | ||
79 | IWL_ERR(priv, "Timed out waiting for PAN disable\n"); | 78 | IWL_ERR(priv, "Timed out waiting for PAN disable\n"); |
80 | ret = -EIO; | ||
81 | } | ||
82 | } | 79 | } |
83 | 80 | ||
84 | return ret; | 81 | return ret; |
@@ -124,6 +121,151 @@ static int iwlagn_update_beacon(struct iwl_priv *priv, | |||
124 | return iwlagn_send_beacon_cmd(priv); | 121 | return iwlagn_send_beacon_cmd(priv); |
125 | } | 122 | } |
126 | 123 | ||
124 | static int iwlagn_send_rxon_assoc(struct iwl_priv *priv, | ||
125 | struct iwl_rxon_context *ctx) | ||
126 | { | ||
127 | int ret = 0; | ||
128 | struct iwl_rxon_assoc_cmd rxon_assoc; | ||
129 | const struct iwl_rxon_cmd *rxon1 = &ctx->staging; | ||
130 | const struct iwl_rxon_cmd *rxon2 = &ctx->active; | ||
131 | |||
132 | if ((rxon1->flags == rxon2->flags) && | ||
133 | (rxon1->filter_flags == rxon2->filter_flags) && | ||
134 | (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && | ||
135 | (rxon1->ofdm_ht_single_stream_basic_rates == | ||
136 | rxon2->ofdm_ht_single_stream_basic_rates) && | ||
137 | (rxon1->ofdm_ht_dual_stream_basic_rates == | ||
138 | rxon2->ofdm_ht_dual_stream_basic_rates) && | ||
139 | (rxon1->ofdm_ht_triple_stream_basic_rates == | ||
140 | rxon2->ofdm_ht_triple_stream_basic_rates) && | ||
141 | (rxon1->acquisition_data == rxon2->acquisition_data) && | ||
142 | (rxon1->rx_chain == rxon2->rx_chain) && | ||
143 | (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { | ||
144 | IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | rxon_assoc.flags = ctx->staging.flags; | ||
149 | rxon_assoc.filter_flags = ctx->staging.filter_flags; | ||
150 | rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; | ||
151 | rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; | ||
152 | rxon_assoc.reserved1 = 0; | ||
153 | rxon_assoc.reserved2 = 0; | ||
154 | rxon_assoc.reserved3 = 0; | ||
155 | rxon_assoc.ofdm_ht_single_stream_basic_rates = | ||
156 | ctx->staging.ofdm_ht_single_stream_basic_rates; | ||
157 | rxon_assoc.ofdm_ht_dual_stream_basic_rates = | ||
158 | ctx->staging.ofdm_ht_dual_stream_basic_rates; | ||
159 | rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain; | ||
160 | rxon_assoc.ofdm_ht_triple_stream_basic_rates = | ||
161 | ctx->staging.ofdm_ht_triple_stream_basic_rates; | ||
162 | rxon_assoc.acquisition_data = ctx->staging.acquisition_data; | ||
163 | |||
164 | ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd, | ||
165 | sizeof(rxon_assoc), &rxon_assoc, NULL); | ||
166 | if (ret) | ||
167 | return ret; | ||
168 | |||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | static int iwlagn_rxon_disconn(struct iwl_priv *priv, | ||
173 | struct iwl_rxon_context *ctx) | ||
174 | { | ||
175 | int ret; | ||
176 | struct iwl_rxon_cmd *active = (void *)&ctx->active; | ||
177 | |||
178 | if (ctx->ctxid == IWL_RXON_CTX_BSS) | ||
179 | ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); | ||
180 | else | ||
181 | ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); | ||
182 | if (ret) | ||
183 | return ret; | ||
184 | |||
185 | /* | ||
186 | * Un-assoc RXON clears the station table and WEP | ||
187 | * keys, so we have to restore those afterwards. | ||
188 | */ | ||
189 | iwl_clear_ucode_stations(priv, ctx); | ||
190 | iwl_restore_stations(priv, ctx); | ||
191 | ret = iwl_restore_default_wep_keys(priv, ctx); | ||
192 | if (ret) { | ||
193 | IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); | ||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | memcpy(active, &ctx->staging, sizeof(*active)); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static int iwlagn_rxon_connect(struct iwl_priv *priv, | ||
202 | struct iwl_rxon_context *ctx) | ||
203 | { | ||
204 | int ret; | ||
205 | struct iwl_rxon_cmd *active = (void *)&ctx->active; | ||
206 | |||
207 | /* RXON timing must be before associated RXON */ | ||
208 | ret = iwl_send_rxon_timing(priv, ctx); | ||
209 | if (ret) { | ||
210 | IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); | ||
211 | return ret; | ||
212 | } | ||
213 | /* QoS info may be cleared by previous un-assoc RXON */ | ||
214 | iwlagn_update_qos(priv, ctx); | ||
215 | |||
216 | /* | ||
217 | * We'll run into this code path when beaconing is | ||
218 | * enabled, but then we also need to send the beacon | ||
219 | * to the device. | ||
220 | */ | ||
221 | if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { | ||
222 | ret = iwlagn_update_beacon(priv, ctx->vif); | ||
223 | if (ret) { | ||
224 | IWL_ERR(priv, | ||
225 | "Error sending required beacon (%d)!\n", | ||
226 | ret); | ||
227 | return ret; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | priv->start_calib = 0; | ||
232 | /* | ||
233 | * Apply the new configuration. | ||
234 | * | ||
235 | * Associated RXON doesn't clear the station table in uCode, | ||
236 | * so we don't need to restore stations etc. after this. | ||
237 | */ | ||
238 | ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, | ||
239 | sizeof(struct iwl_rxon_cmd), &ctx->staging); | ||
240 | if (ret) { | ||
241 | IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); | ||
242 | return ret; | ||
243 | } | ||
244 | memcpy(active, &ctx->staging, sizeof(*active)); | ||
245 | |||
246 | iwl_reprogram_ap_sta(priv, ctx); | ||
247 | |||
248 | /* IBSS beacon needs to be sent after setting assoc */ | ||
249 | if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) | ||
250 | if (iwlagn_update_beacon(priv, ctx->vif)) | ||
251 | IWL_ERR(priv, "Error sending IBSS beacon\n"); | ||
252 | iwl_init_sensitivity(priv); | ||
253 | |||
254 | /* | ||
255 | * If we issue a new RXON command which required a tune then | ||
256 | * we must send a new TXPOWER command or we won't be able to | ||
257 | * Tx any frames. | ||
258 | * | ||
259 | * It's expected we set power here if channel is changing. | ||
260 | */ | ||
261 | ret = iwl_set_tx_power(priv, priv->tx_power_next, true); | ||
262 | if (ret) { | ||
263 | IWL_ERR(priv, "Error sending TX power (%d)\n", ret); | ||
264 | return ret; | ||
265 | } | ||
266 | return 0; | ||
267 | } | ||
268 | |||
127 | /** | 269 | /** |
128 | * iwlagn_commit_rxon - commit staging_rxon to hardware | 270 | * iwlagn_commit_rxon - commit staging_rxon to hardware |
129 | * | 271 | * |
@@ -131,6 +273,16 @@ static int iwlagn_update_beacon(struct iwl_priv *priv, | |||
131 | * the active_rxon structure is updated with the new data. This | 273 | * the active_rxon structure is updated with the new data. This |
132 | * function correctly transitions out of the RXON_ASSOC_MSK state if | 274 | * function correctly transitions out of the RXON_ASSOC_MSK state if |
133 | * a HW tune is required based on the RXON structure changes. | 275 | * a HW tune is required based on the RXON structure changes. |
276 | * | ||
277 | * The connect/disconnect flow should be as the following: | ||
278 | * | ||
279 | * 1. make sure send RXON command with association bit unset if not connect | ||
280 | * this should include the channel and the band for the candidate | ||
281 | * to be connected to | ||
282 | * 2. Add Station before RXON association with the AP | ||
283 | * 3. RXON_timing has to send before RXON for connection | ||
284 | * 4. full RXON command - associated bit set | ||
285 | * 5. use RXON_ASSOC command to update any flags changes | ||
134 | */ | 286 | */ |
135 | int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | 287 | int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) |
136 | { | 288 | { |
@@ -180,6 +332,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | |||
180 | else | 332 | else |
181 | ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; | 333 | ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; |
182 | 334 | ||
335 | iwl_print_rx_config_cmd(priv, ctx); | ||
183 | ret = iwl_check_rxon_cmd(priv, ctx); | 336 | ret = iwl_check_rxon_cmd(priv, ctx); |
184 | if (ret) { | 337 | if (ret) { |
185 | IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); | 338 | IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); |
@@ -203,14 +356,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | |||
203 | * and other flags for the current radio configuration. | 356 | * and other flags for the current radio configuration. |
204 | */ | 357 | */ |
205 | if (!iwl_full_rxon_required(priv, ctx)) { | 358 | if (!iwl_full_rxon_required(priv, ctx)) { |
206 | ret = iwl_send_rxon_assoc(priv, ctx); | 359 | ret = iwlagn_send_rxon_assoc(priv, ctx); |
207 | if (ret) { | 360 | if (ret) { |
208 | IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret); | 361 | IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret); |
209 | return ret; | 362 | return ret; |
210 | } | 363 | } |
211 | 364 | ||
212 | memcpy(active, &ctx->staging, sizeof(*active)); | 365 | memcpy(active, &ctx->staging, sizeof(*active)); |
213 | iwl_print_rx_config_cmd(priv, ctx); | ||
214 | return 0; | 366 | return 0; |
215 | } | 367 | } |
216 | 368 | ||
@@ -220,7 +372,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | |||
220 | return ret; | 372 | return ret; |
221 | } | 373 | } |
222 | 374 | ||
223 | iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto); | 375 | iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto); |
224 | 376 | ||
225 | IWL_DEBUG_INFO(priv, | 377 | IWL_DEBUG_INFO(priv, |
226 | "Going to commit RXON\n" | 378 | "Going to commit RXON\n" |
@@ -238,92 +390,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | |||
238 | * set up filters in the device. | 390 | * set up filters in the device. |
239 | */ | 391 | */ |
240 | if ((old_assoc && new_assoc) || !new_assoc) { | 392 | if ((old_assoc && new_assoc) || !new_assoc) { |
241 | if (ctx->ctxid == IWL_RXON_CTX_BSS) | 393 | ret = iwlagn_rxon_disconn(priv, ctx); |
242 | ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); | ||
243 | else | ||
244 | ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); | ||
245 | if (ret) | 394 | if (ret) |
246 | return ret; | 395 | return ret; |
247 | |||
248 | memcpy(active, &ctx->staging, sizeof(*active)); | ||
249 | |||
250 | /* | ||
251 | * Un-assoc RXON clears the station table and WEP | ||
252 | * keys, so we have to restore those afterwards. | ||
253 | */ | ||
254 | iwl_clear_ucode_stations(priv, ctx); | ||
255 | iwl_restore_stations(priv, ctx); | ||
256 | ret = iwl_restore_default_wep_keys(priv, ctx); | ||
257 | if (ret) { | ||
258 | IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); | ||
259 | return ret; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | /* RXON timing must be before associated RXON */ | ||
264 | ret = iwl_send_rxon_timing(priv, ctx); | ||
265 | if (ret) { | ||
266 | IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | if (new_assoc) { | ||
271 | /* QoS info may be cleared by previous un-assoc RXON */ | ||
272 | iwlagn_update_qos(priv, ctx); | ||
273 | |||
274 | /* | ||
275 | * We'll run into this code path when beaconing is | ||
276 | * enabled, but then we also need to send the beacon | ||
277 | * to the device. | ||
278 | */ | ||
279 | if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { | ||
280 | ret = iwlagn_update_beacon(priv, ctx->vif); | ||
281 | if (ret) { | ||
282 | IWL_ERR(priv, | ||
283 | "Error sending required beacon (%d)!\n", | ||
284 | ret); | ||
285 | return ret; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | priv->start_calib = 0; | ||
290 | /* | ||
291 | * Apply the new configuration. | ||
292 | * | ||
293 | * Associated RXON doesn't clear the station table in uCode, | ||
294 | * so we don't need to restore stations etc. after this. | ||
295 | */ | ||
296 | ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, | ||
297 | sizeof(struct iwl_rxon_cmd), &ctx->staging); | ||
298 | if (ret) { | ||
299 | IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); | ||
300 | return ret; | ||
301 | } | ||
302 | memcpy(active, &ctx->staging, sizeof(*active)); | ||
303 | |||
304 | iwl_reprogram_ap_sta(priv, ctx); | ||
305 | |||
306 | /* IBSS beacon needs to be sent after setting assoc */ | ||
307 | if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) | ||
308 | if (iwlagn_update_beacon(priv, ctx->vif)) | ||
309 | IWL_ERR(priv, "Error sending IBSS beacon\n"); | ||
310 | } | 396 | } |
311 | 397 | ||
312 | iwl_print_rx_config_cmd(priv, ctx); | 398 | if (new_assoc) |
313 | 399 | return iwlagn_rxon_connect(priv, ctx); | |
314 | iwl_init_sensitivity(priv); | ||
315 | |||
316 | /* | ||
317 | * If we issue a new RXON command which required a tune then we must | ||
318 | * send a new TXPOWER command or we won't be able to Tx any frames. | ||
319 | * | ||
320 | * It's expected we set power here if channel is changing. | ||
321 | */ | ||
322 | ret = iwl_set_tx_power(priv, priv->tx_power_next, true); | ||
323 | if (ret) { | ||
324 | IWL_ERR(priv, "Error sending TX power (%d)\n", ret); | ||
325 | return ret; | ||
326 | } | ||
327 | 400 | ||
328 | return 0; | 401 | return 0; |
329 | } | 402 | } |