iwlwifi: add support for device tx flush request
authorWey-Yi Guy <wey-yi.w.guy@intel.com>
Thu, 24 Jun 2010 20:18:35 +0000 (13:18 -0700)
committerWey-Yi Guy <wey-yi.w.guy@intel.com>
Fri, 2 Jul 2010 18:10:45 +0000 (11:10 -0700)
"Flush" request can come from two different sources, it can either from
mac80211, or from device when the operation is needed. Here
adding the support for device issue "flush" request.

When receive tx complete with status is TX_STATUS_FAIL_RFKILL_FLUSH,
issue REPLY_TXFIFO_FLUSH command to uCode to flush out all the tx frames
in queues.

In this condition, since mac80211 has no knowledge of "flush" operation,
driver need to stop all the tx queues and wait for the operation
completed before wake up the queues for frames transmission.

Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-dev.h

index 00808ee5ce2a8223ea6fa5ffbc71ea6754d1e45d..96a4888ea242a66051097dc4182c520f505df9f2 100644 (file)
@@ -227,6 +227,7 @@ static struct iwl_lib_ops iwl1000_lib = {
        .check_plcp_health = iwl_good_plcp_health,
        .check_ack_health = iwl_good_ack_health,
        .txfifo_flush = iwlagn_txfifo_flush,
+       .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
 
 static const struct iwl_ops iwl1000_ops = {
index 1182498c1d8fedcbf8d41d83967c8cdd5fa97dd0..648d53b65a78d536000865cb46f1030ec0a94b87 100644 (file)
@@ -403,6 +403,7 @@ static struct iwl_lib_ops iwl5000_lib = {
        .check_plcp_health = iwl_good_plcp_health,
        .check_ack_health = iwl_good_ack_health,
        .txfifo_flush = iwlagn_txfifo_flush,
+       .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
 
 static struct iwl_lib_ops iwl5150_lib = {
@@ -467,6 +468,7 @@ static struct iwl_lib_ops iwl5150_lib = {
        .check_plcp_health = iwl_good_plcp_health,
        .check_ack_health = iwl_good_ack_health,
        .txfifo_flush = iwlagn_txfifo_flush,
+       .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
 
 static const struct iwl_ops iwl5000_ops = {
index e1959fbafd0012efd0425b2e130a94385bb498a5..79ba7adbcef91deb031717089b4b179137914f71 100644 (file)
@@ -328,6 +328,7 @@ static struct iwl_lib_ops iwl6000_lib = {
        .check_plcp_health = iwl_good_plcp_health,
        .check_ack_health = iwl_good_ack_health,
        .txfifo_flush = iwlagn_txfifo_flush,
+       .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
 };
 
 static const struct iwl_ops iwl6000_ops = {
index 95666e565c77241a427c77df9270616d9f47bbf4..74623e0d535f7b2b46487d4e831f92b3fc8bf434 100644 (file)
@@ -205,7 +205,9 @@ void iwl_check_abort_status(struct iwl_priv *priv,
                            u8 frame_count, u32 status)
 {
        if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) {
-               IWL_ERR(priv, "TODO: Implement Tx flush command!!!\n");
+               IWL_ERR(priv, "Tx flush command to flush out all frames\n");
+               if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+                       queue_work(priv->workqueue, &priv->tx_flush);
        }
 }
 
@@ -1498,3 +1500,18 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
 
        return iwl_send_cmd(priv, &cmd);
 }
+
+void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
+{
+       mutex_lock(&priv->mutex);
+       ieee80211_stop_queues(priv->hw);
+       if (priv->cfg->ops->lib->txfifo_flush(priv, IWL_DROP_ALL)) {
+               IWL_ERR(priv, "flush request fail\n");
+               goto done;
+       }
+       IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n");
+       iwlagn_wait_tx_queue_empty(priv);
+done:
+       ieee80211_wake_queues(priv->hw);
+       mutex_unlock(&priv->mutex);
+}
index c735a39ec176ba7c41043a8e27bf2d0cf9725bb1..60af54210f99aa0beec25f31a481c5d66ce15dda 100644 (file)
@@ -859,6 +859,24 @@ int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
        return 0;
 }
 
+static void iwl_bg_tx_flush(struct work_struct *work)
+{
+       struct iwl_priv *priv =
+               container_of(work, struct iwl_priv, tx_flush);
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       /* do nothing if rf-kill is on */
+       if (!iwl_is_ready_rf(priv))
+               return;
+
+       if (priv->cfg->ops->lib->txfifo_flush) {
+               IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n");
+               iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
+       }
+}
+
 /**
  * iwl_setup_rx_handlers - Initialize Rx handler callbacks
  *
@@ -3693,6 +3711,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
        INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
        INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
        INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
+       INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
        INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
        INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
 
index 0298642d1d75f441d387d39d67cdf6bd3afa9fd1..5c46b2cd8e91db351b52d926332e5624d86ab427 100644 (file)
@@ -149,6 +149,7 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 int iwlagn_hw_nic_init(struct iwl_priv *priv);
 int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv);
 int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
+void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
 
 /* rx */
 void iwlagn_rx_queue_restock(struct iwl_priv *priv);
index db315b05f988f783572198908a95a6539ca15c3d..fcbba3d604de391a2853dd7b1b29a4d3e81506d1 100644 (file)
@@ -206,6 +206,7 @@ struct iwl_lib_ops {
        bool (*check_ack_health)(struct iwl_priv *priv,
                                        struct iwl_rx_packet *pkt);
        int (*txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
+       void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
 
        struct iwl_debugfs_ops debugfs_ops;
 };
index df07a144c78686ed882d02ffa227218c7e245deb..c637376a22dbb1a7fcc3de3b604bf68b51ddcff1 100644 (file)
@@ -1345,6 +1345,7 @@ struct iwl_priv {
        struct work_struct ct_enter;
        struct work_struct ct_exit;
        struct work_struct start_internal_scan;
+       struct work_struct tx_flush;
 
        struct tasklet_struct irq_tasklet;