aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2010-06-24 16:18:35 -0400
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2010-07-02 14:10:45 -0400
commit6555063666fea1fc81a14396aca53ab021ccb4f2 (patch)
treefdb12efd4445db8f27e90411ff182b30e33981ff /drivers/net
parent716c74b00717ad9caedb4a46059fb64a3da99808 (diff)
iwlwifi: add support for device tx flush request
"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>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h1
8 files changed, 44 insertions, 1 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 00808ee5ce2a..96a4888ea242 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -227,6 +227,7 @@ static struct iwl_lib_ops iwl1000_lib = {
227 .check_plcp_health = iwl_good_plcp_health, 227 .check_plcp_health = iwl_good_plcp_health,
228 .check_ack_health = iwl_good_ack_health, 228 .check_ack_health = iwl_good_ack_health,
229 .txfifo_flush = iwlagn_txfifo_flush, 229 .txfifo_flush = iwlagn_txfifo_flush,
230 .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
230}; 231};
231 232
232static const struct iwl_ops iwl1000_ops = { 233static const struct iwl_ops iwl1000_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 1182498c1d8f..648d53b65a78 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -403,6 +403,7 @@ static struct iwl_lib_ops iwl5000_lib = {
403 .check_plcp_health = iwl_good_plcp_health, 403 .check_plcp_health = iwl_good_plcp_health,
404 .check_ack_health = iwl_good_ack_health, 404 .check_ack_health = iwl_good_ack_health,
405 .txfifo_flush = iwlagn_txfifo_flush, 405 .txfifo_flush = iwlagn_txfifo_flush,
406 .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
406}; 407};
407 408
408static struct iwl_lib_ops iwl5150_lib = { 409static struct iwl_lib_ops iwl5150_lib = {
@@ -467,6 +468,7 @@ static struct iwl_lib_ops iwl5150_lib = {
467 .check_plcp_health = iwl_good_plcp_health, 468 .check_plcp_health = iwl_good_plcp_health,
468 .check_ack_health = iwl_good_ack_health, 469 .check_ack_health = iwl_good_ack_health,
469 .txfifo_flush = iwlagn_txfifo_flush, 470 .txfifo_flush = iwlagn_txfifo_flush,
471 .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
470}; 472};
471 473
472static const struct iwl_ops iwl5000_ops = { 474static const struct iwl_ops iwl5000_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index e1959fbafd00..79ba7adbcef9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -328,6 +328,7 @@ static struct iwl_lib_ops iwl6000_lib = {
328 .check_plcp_health = iwl_good_plcp_health, 328 .check_plcp_health = iwl_good_plcp_health,
329 .check_ack_health = iwl_good_ack_health, 329 .check_ack_health = iwl_good_ack_health,
330 .txfifo_flush = iwlagn_txfifo_flush, 330 .txfifo_flush = iwlagn_txfifo_flush,
331 .dev_txfifo_flush = iwlagn_dev_txfifo_flush,
331}; 332};
332 333
333static const struct iwl_ops iwl6000_ops = { 334static const struct iwl_ops iwl6000_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 95666e565c77..74623e0d535f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -205,7 +205,9 @@ void iwl_check_abort_status(struct iwl_priv *priv,
205 u8 frame_count, u32 status) 205 u8 frame_count, u32 status)
206{ 206{
207 if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) { 207 if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) {
208 IWL_ERR(priv, "TODO: Implement Tx flush command!!!\n"); 208 IWL_ERR(priv, "Tx flush command to flush out all frames\n");
209 if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
210 queue_work(priv->workqueue, &priv->tx_flush);
209 } 211 }
210} 212}
211 213
@@ -1498,3 +1500,18 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
1498 1500
1499 return iwl_send_cmd(priv, &cmd); 1501 return iwl_send_cmd(priv, &cmd);
1500} 1502}
1503
1504void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
1505{
1506 mutex_lock(&priv->mutex);
1507 ieee80211_stop_queues(priv->hw);
1508 if (priv->cfg->ops->lib->txfifo_flush(priv, IWL_DROP_ALL)) {
1509 IWL_ERR(priv, "flush request fail\n");
1510 goto done;
1511 }
1512 IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n");
1513 iwlagn_wait_tx_queue_empty(priv);
1514done:
1515 ieee80211_wake_queues(priv->hw);
1516 mutex_unlock(&priv->mutex);
1517}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index c735a39ec176..60af54210f99 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -859,6 +859,24 @@ int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
859 return 0; 859 return 0;
860} 860}
861 861
862static void iwl_bg_tx_flush(struct work_struct *work)
863{
864 struct iwl_priv *priv =
865 container_of(work, struct iwl_priv, tx_flush);
866
867 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
868 return;
869
870 /* do nothing if rf-kill is on */
871 if (!iwl_is_ready_rf(priv))
872 return;
873
874 if (priv->cfg->ops->lib->txfifo_flush) {
875 IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n");
876 iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
877 }
878}
879
862/** 880/**
863 * iwl_setup_rx_handlers - Initialize Rx handler callbacks 881 * iwl_setup_rx_handlers - Initialize Rx handler callbacks
864 * 882 *
@@ -3693,6 +3711,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
3693 INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); 3711 INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
3694 INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); 3712 INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
3695 INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); 3713 INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
3714 INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
3696 INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); 3715 INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
3697 INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); 3716 INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
3698 3717
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 0298642d1d75..5c46b2cd8e91 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -149,6 +149,7 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
149int iwlagn_hw_nic_init(struct iwl_priv *priv); 149int iwlagn_hw_nic_init(struct iwl_priv *priv);
150int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv); 150int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv);
151int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); 151int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
152void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
152 153
153/* rx */ 154/* rx */
154void iwlagn_rx_queue_restock(struct iwl_priv *priv); 155void iwlagn_rx_queue_restock(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index db315b05f988..fcbba3d604de 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -206,6 +206,7 @@ struct iwl_lib_ops {
206 bool (*check_ack_health)(struct iwl_priv *priv, 206 bool (*check_ack_health)(struct iwl_priv *priv,
207 struct iwl_rx_packet *pkt); 207 struct iwl_rx_packet *pkt);
208 int (*txfifo_flush)(struct iwl_priv *priv, u16 flush_control); 208 int (*txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
209 void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control);
209 210
210 struct iwl_debugfs_ops debugfs_ops; 211 struct iwl_debugfs_ops debugfs_ops;
211}; 212};
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index df07a144c786..c637376a22db 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1345,6 +1345,7 @@ struct iwl_priv {
1345 struct work_struct ct_enter; 1345 struct work_struct ct_enter;
1346 struct work_struct ct_exit; 1346 struct work_struct ct_exit;
1347 struct work_struct start_internal_scan; 1347 struct work_struct start_internal_scan;
1348 struct work_struct tx_flush;
1348 1349
1349 struct tasklet_struct irq_tasklet; 1350 struct tasklet_struct irq_tasklet;
1350 1351