diff options
| author | David S. Miller <davem@davemloft.net> | 2011-05-05 17:09:28 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-05-05 17:09:28 -0400 |
| commit | 90864fbc7639d7a2300c67a18c9fb9fbcf7d51d2 (patch) | |
| tree | 6951c8d0e529dbfc7c4cec75d4cec63350e39b7c /drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | |
| parent | 228e548e602061b08ee8e8966f567c12aa079682 (diff) | |
| parent | a70171dce9cd44cb06c7d299eba9fa87a8933045 (diff) | |
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
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 | } |
