mwl8k: Stop bsses before hw specific commands
authorYogesh Ashok Powar <yogeshp@marvell.com>
Fri, 25 Jan 2013 10:47:32 +0000 (16:17 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 30 Jan 2013 20:06:47 +0000 (15:06 -0500)
For the commands, that might change the hw characteristics
of the PHY device, stop the running bsses and resume them
once command is complete.

Signed-off-by: Yogesh Ashok Powar <yogeshp@marvell.com>
Signed-off-by: Nishant Sarmukadam <nishants@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwl8k.c

index 224cf91..398b8b1 100644 (file)
@@ -285,6 +285,9 @@ struct mwl8k_priv {
        char *fw_pref;
        char *fw_alt;
        struct completion firmware_loading_complete;
+
+       /* bitmap of running BSSes */
+       u32 running_bsses;
 };
 
 #define MAX_WEP_KEY_LEN         13
@@ -2156,6 +2159,8 @@ static void mwl8k_fw_unlock(struct ieee80211_hw *hw)
        }
 }
 
+static void mwl8k_enable_bsses(struct ieee80211_hw *hw, bool enable,
+                              u32 bitmap);
 
 /*
  * Command processing.
@@ -2174,6 +2179,34 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
        int rc;
        unsigned long timeout = 0;
        u8 buf[32];
+       u32 bitmap = 0;
+
+       wiphy_dbg(hw->wiphy, "Posting %s [%d]\n",
+                 mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), cmd->macid);
+
+       /* Before posting firmware commands that could change the hardware
+        * characteristics, make sure that all BSSes are stopped temporary.
+        * Enable these stopped BSSes after completion of the commands
+        */
+
+       rc = mwl8k_fw_lock(hw);
+       if (rc)
+               return rc;
+
+       if (priv->ap_fw && priv->running_bsses) {
+               switch (le16_to_cpu(cmd->code)) {
+               case MWL8K_CMD_SET_RF_CHANNEL:
+               case MWL8K_CMD_RADIO_CONTROL:
+               case MWL8K_CMD_RF_TX_POWER:
+               case MWL8K_CMD_TX_POWER:
+               case MWL8K_CMD_RF_ANTENNA:
+               case MWL8K_CMD_RTS_THRESHOLD:
+               case MWL8K_CMD_MIMO_CONFIG:
+                       bitmap = priv->running_bsses;
+                       mwl8k_enable_bsses(hw, false, bitmap);
+                       break;
+               }
+       }
 
        cmd->result = (__force __le16) 0xffff;
        dma_size = le16_to_cpu(cmd->length);
@@ -2182,13 +2215,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
        if (pci_dma_mapping_error(priv->pdev, dma_addr))
                return -ENOMEM;
 
-       rc = mwl8k_fw_lock(hw);
-       if (rc) {
-               pci_unmap_single(priv->pdev, dma_addr, dma_size,
-                                               PCI_DMA_BIDIRECTIONAL);
-               return rc;
-       }
-
        priv->hostcmd_wait = &cmd_wait;
        iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR);
        iowrite32(MWL8K_H2A_INT_DOORBELL,
@@ -2201,7 +2227,6 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
 
        priv->hostcmd_wait = NULL;
 
-       mwl8k_fw_unlock(hw);
 
        pci_unmap_single(priv->pdev, dma_addr, dma_size,
                                        PCI_DMA_BIDIRECTIONAL);
@@ -2228,6 +2253,11 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
                                     ms);
        }
 
+       if (bitmap)
+               mwl8k_enable_bsses(hw, true, bitmap);
+
+       mwl8k_fw_unlock(hw);
+
        return rc;
 }
 
@@ -3680,8 +3710,16 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif, int enable)
 {
        struct mwl8k_cmd_bss_start *cmd;
+       struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+       struct mwl8k_priv *priv = hw->priv;
        int rc;
 
+       if (enable && (priv->running_bsses & (1 << mwl8k_vif->macid)))
+               return 0;
+
+       if (!enable && !(priv->running_bsses & (1 << mwl8k_vif->macid)))
+               return 0;
+
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (cmd == NULL)
                return -ENOMEM;
@@ -3693,9 +3731,31 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw,
        rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
        kfree(cmd);
 
+       if (!rc) {
+               if (enable)
+                       priv->running_bsses |= (1 << mwl8k_vif->macid);
+               else
+                       priv->running_bsses &= ~(1 << mwl8k_vif->macid);
+       }
        return rc;
 }
 
+static void mwl8k_enable_bsses(struct ieee80211_hw *hw, bool enable, u32 bitmap)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_vif *mwl8k_vif, *tmp_vif;
+       struct ieee80211_vif *vif;
+
+       list_for_each_entry_safe(mwl8k_vif, tmp_vif, &priv->vif_list, list) {
+               vif = mwl8k_vif->vif;
+
+               if (!(bitmap & (1 << mwl8k_vif->macid)))
+                       continue;
+
+               if (vif->type == NL80211_IFTYPE_AP)
+                       mwl8k_cmd_bss_start(hw, vif, enable);
+       }
+}
 /*
  * CMD_BASTREAM.
  */
@@ -5948,6 +6008,8 @@ static int mwl8k_probe(struct pci_dev *pdev,
 
        priv->hw_restart_in_progress = false;
 
+       priv->running_bsses = 0;
+
        return rc;
 
 err_stop_firmware: