Merge tag 'please-pull-fix-ia64-warnings' of git://git.kernel.org/pub/scm/linux/kerne...
[cascardo/linux.git] / drivers / net / wireless / mwifiex / main.c
index 2eb88ea..e15ab72 100644 (file)
 #define VERSION        "1.0"
 
 const char driver_version[] = "mwifiex " VERSION " (%s) ";
+static char *cal_data_cfg;
+module_param(cal_data_cfg, charp, 0);
+
+static void scan_delay_timer_fn(unsigned long data)
+{
+       struct mwifiex_private *priv = (struct mwifiex_private *)data;
+       struct mwifiex_adapter *adapter = priv->adapter;
+       struct cmd_ctrl_node *cmd_node, *tmp_node;
+       unsigned long flags;
+
+       if (adapter->surprise_removed)
+               return;
+
+       if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
+               /*
+                * Abort scan operation by cancelling all pending scan
+                * commands
+                */
+               spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+               list_for_each_entry_safe(cmd_node, tmp_node,
+                                        &adapter->scan_pending_q, list) {
+                       list_del(&cmd_node->list);
+                       mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+               }
+               spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+               spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+               adapter->scan_processing = false;
+               adapter->scan_delay_cnt = 0;
+               adapter->empty_tx_q_cnt = 0;
+               spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+               if (priv->scan_request) {
+                       dev_dbg(adapter->dev, "info: aborting scan\n");
+                       cfg80211_scan_done(priv->scan_request, 1);
+                       priv->scan_request = NULL;
+               } else {
+                       priv->scan_aborting = false;
+                       dev_dbg(adapter->dev, "info: scan already aborted\n");
+               }
+               goto done;
+       }
+
+       if (!atomic_read(&priv->adapter->is_tx_received)) {
+               adapter->empty_tx_q_cnt++;
+               if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) {
+                       /*
+                        * No Tx traffic for 200msec. Get scan command from
+                        * scan pending queue and put to cmd pending queue to
+                        * resume scan operation
+                        */
+                       adapter->scan_delay_cnt = 0;
+                       adapter->empty_tx_q_cnt = 0;
+                       spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+                       cmd_node = list_first_entry(&adapter->scan_pending_q,
+                                                   struct cmd_ctrl_node, list);
+                       list_del(&cmd_node->list);
+                       spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+                                              flags);
+
+                       mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
+                                                       true);
+                       queue_work(adapter->workqueue, &adapter->main_work);
+                       goto done;
+               }
+       } else {
+               adapter->empty_tx_q_cnt = 0;
+       }
+
+       /* Delay scan operation further by 20msec */
+       mod_timer(&priv->scan_delay_timer, jiffies +
+                 msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
+       adapter->scan_delay_cnt++;
+
+done:
+       if (atomic_read(&priv->adapter->is_tx_received))
+               atomic_set(&priv->adapter->is_tx_received, false);
+
+       return;
+}
 
 /*
  * This function registers the device and performs all the necessary
@@ -73,6 +153,10 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
 
                adapter->priv[i]->adapter = adapter;
                adapter->priv_num++;
+
+               setup_timer(&adapter->priv[i]->scan_delay_timer,
+                           scan_delay_timer_fn,
+                           (unsigned long)adapter->priv[i]);
        }
        mwifiex_init_lock_list(adapter);
 
@@ -336,6 +420,13 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
 
        dev_notice(adapter->dev, "WLAN FW is active\n");
 
+       if (cal_data_cfg) {
+               if ((request_firmware(&adapter->cal_data, cal_data_cfg,
+                                     adapter->dev)) < 0)
+                       dev_err(adapter->dev,
+                               "Cal data request_firmware() failed\n");
+       }
+
        adapter->init_wait_q_woken = false;
        ret = mwifiex_init_fw(adapter);
        if (ret == -1) {
@@ -390,6 +481,10 @@ err_init_fw:
        pr_debug("info: %s: unregister device\n", __func__);
        adapter->if_ops.unregister_dev(adapter);
 done:
+       if (adapter->cal_data) {
+               release_firmware(adapter->cal_data);
+               adapter->cal_data = NULL;
+       }
        release_firmware(adapter->firmware);
        complete(&adapter->fw_load);
        return;
@@ -436,6 +531,7 @@ mwifiex_close(struct net_device *dev)
                dev_dbg(priv->adapter->dev, "aborting scan on ndo_stop\n");
                cfg80211_scan_done(priv->scan_request, 1);
                priv->scan_request = NULL;
+               priv->scan_aborting = true;
        }
 
        return 0;
@@ -573,9 +669,8 @@ static void mwifiex_set_multicast_list(struct net_device *dev)
                mcast_list.mode = MWIFIEX_ALL_MULTI_MODE;
        } else {
                mcast_list.mode = MWIFIEX_MULTICAST_MODE;
-               if (netdev_mc_count(dev))
-                       mcast_list.num_multicast_addr =
-                               mwifiex_copy_mcast_addr(&mcast_list, dev);
+               mcast_list.num_multicast_addr =
+                       mwifiex_copy_mcast_addr(&mcast_list, dev);
        }
        mwifiex_request_set_multicast_list(priv, &mcast_list);
 }