iwlagn: fix dual-mode RXON
authorJohannes Berg <johannes.berg@intel.com>
Fri, 27 May 2011 15:40:26 +0000 (08:40 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 1 Jun 2011 19:36:32 +0000 (15:36 -0400)
 The PAN context has three states: disabled, disassociated
 and associated. It seems that wasn't quite as much of an
 issue in previous versions of the microcode, but now we
 really have to use all the three states properly. So add
 code to switch accordingly.

Additionally, PAN parameters need to be sent differently
and the timing for PAN RXON needs to be inbetween.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c

index 58c095c00c0cceb227f616296bac690204df19bd..afb2f202afb93e8ab0d9c0fcf05124438f08db5f 100644 (file)
@@ -81,6 +81,21 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
        return ret;
 }
 
+static int iwlagn_disconn_pan(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx,
+                             struct iwl_rxon_cmd *send)
+{
+       __le32 old_filter = send->filter_flags;
+       int ret;
+
+       send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send);
+
+       send->filter_flags = old_filter;
+
+       return ret;
+}
+
 static void iwlagn_update_qos(struct iwl_priv *priv,
                              struct iwl_rxon_context *ctx)
 {
@@ -175,10 +190,21 @@ static int iwlagn_rxon_disconn(struct iwl_priv *priv,
        int ret;
        struct iwl_rxon_cmd *active = (void *)&ctx->active;
 
-       if (ctx->ctxid == IWL_RXON_CTX_BSS)
+       if (ctx->ctxid == IWL_RXON_CTX_BSS) {
                ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
-       else
+       } else {
                ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
+               if (ret)
+                       return ret;
+               if (ctx->vif) {
+                       ret = iwl_send_rxon_timing(priv, ctx);
+                       if (ret) {
+                               IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+                               return ret;
+                       }
+                       ret = iwlagn_disconn_pan(priv, ctx, &ctx->staging);
+               }
+       }
        if (ret)
                return ret;
 
@@ -205,10 +231,12 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv,
        struct iwl_rxon_cmd *active = (void *)&ctx->active;
 
        /* RXON timing must be before associated RXON */
-       ret = iwl_send_rxon_timing(priv, ctx);
-       if (ret) {
-               IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
-               return ret;
+       if (ctx->ctxid == IWL_RXON_CTX_BSS) {
+               ret = iwl_send_rxon_timing(priv, ctx);
+               if (ret) {
+                       IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+                       return ret;
+               }
        }
        /* QoS info may be cleared by previous un-assoc RXON */
        iwlagn_update_qos(priv, ctx);
@@ -370,12 +398,6 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
                return 0;
        }
 
-       if (priv->cfg->ops->hcmd->set_pan_params) {
-               ret = priv->cfg->ops->hcmd->set_pan_params(priv);
-               if (ret)
-                       return ret;
-       }
-
        iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto);
 
        IWL_DEBUG_INFO(priv,
@@ -397,6 +419,12 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        if (ret)
                return ret;
 
+       if (priv->cfg->ops->hcmd->set_pan_params) {
+               ret = priv->cfg->ops->hcmd->set_pan_params(priv);
+               if (ret)
+                       return ret;
+       }
+
        if (new_assoc)
                return iwlagn_rxon_connect(priv, ctx);