aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless')
-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.c63
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h2
8 files changed, 114 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 1daf159914a..00808ee5ce2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -226,6 +226,7 @@ static struct iwl_lib_ops iwl1000_lib = {
226 .recover_from_tx_stall = iwl_bg_monitor_recover, 226 .recover_from_tx_stall = iwl_bg_monitor_recover,
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}; 230};
230 231
231static const struct iwl_ops iwl1000_ops = { 232static 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 b8f3e20f2c8..1182498c1d8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -402,6 +402,7 @@ static struct iwl_lib_ops iwl5000_lib = {
402 .recover_from_tx_stall = iwl_bg_monitor_recover, 402 .recover_from_tx_stall = iwl_bg_monitor_recover,
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}; 406};
406 407
407static struct iwl_lib_ops iwl5150_lib = { 408static struct iwl_lib_ops iwl5150_lib = {
@@ -465,6 +466,7 @@ static struct iwl_lib_ops iwl5150_lib = {
465 .recover_from_tx_stall = iwl_bg_monitor_recover, 466 .recover_from_tx_stall = iwl_bg_monitor_recover,
466 .check_plcp_health = iwl_good_plcp_health, 467 .check_plcp_health = iwl_good_plcp_health,
467 .check_ack_health = iwl_good_ack_health, 468 .check_ack_health = iwl_good_ack_health,
469 .txfifo_flush = iwlagn_txfifo_flush,
468}; 470};
469 471
470static const struct iwl_ops iwl5000_ops = { 472static 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 8577664da77..e1959fbafd0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -327,6 +327,7 @@ static struct iwl_lib_ops iwl6000_lib = {
327 .recover_from_tx_stall = iwl_bg_monitor_recover, 327 .recover_from_tx_stall = iwl_bg_monitor_recover,
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}; 331};
331 332
332static const struct iwl_ops iwl6000_ops = { 333static 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 5f1e7d802cb..95666e565c7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -1435,3 +1435,66 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv,
1435 priv->stations[sta_id].tid[tid].tfds_in_queue = 0; 1435 priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
1436 } 1436 }
1437} 1437}
1438
1439#define IWL_FLUSH_WAIT_MS 2000
1440
1441int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv)
1442{
1443 struct iwl_tx_queue *txq;
1444 struct iwl_queue *q;
1445 int cnt;
1446 unsigned long now = jiffies;
1447 int ret = 0;
1448
1449 /* waiting for all the tx frames complete might take a while */
1450 for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
1451 if (cnt == IWL_CMD_QUEUE_NUM)
1452 continue;
1453 txq = &priv->txq[cnt];
1454 q = &txq->q;
1455 while (q->read_ptr != q->write_ptr && !time_after(jiffies,
1456 now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS)))
1457 msleep(1);
1458
1459 if (q->read_ptr != q->write_ptr) {
1460 IWL_ERR(priv, "fail to flush all tx fifo queues\n");
1461 ret = -ETIMEDOUT;
1462 break;
1463 }
1464 }
1465 return ret;
1466}
1467
1468#define IWL_TX_QUEUE_MSK 0xfffff
1469
1470/**
1471 * iwlagn_txfifo_flush: send REPLY_TXFIFO_FLUSH command to uCode
1472 *
1473 * pre-requirements:
1474 * 1. acquire mutex before calling
1475 * 2. make sure rf is on and not in exit state
1476 */
1477int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
1478{
1479 struct iwl_txfifo_flush_cmd flush_cmd;
1480 struct iwl_host_cmd cmd = {
1481 .id = REPLY_TXFIFO_FLUSH,
1482 .len = sizeof(struct iwl_txfifo_flush_cmd),
1483 .flags = CMD_SYNC,
1484 .data = &flush_cmd,
1485 };
1486
1487 might_sleep();
1488
1489 memset(&flush_cmd, 0, sizeof(flush_cmd));
1490 flush_cmd.fifo_control = IWL_TX_FIFO_VO_MSK | IWL_TX_FIFO_VI_MSK |
1491 IWL_TX_FIFO_BE_MSK | IWL_TX_FIFO_BK_MSK;
1492 if (priv->cfg->sku & IWL_SKU_N)
1493 flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK;
1494
1495 IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n",
1496 flush_cmd.fifo_control);
1497 flush_cmd.flush_control = cpu_to_le16(flush_control);
1498
1499 return iwl_send_cmd(priv, &cmd);
1500}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 22c0149e5d4..c735a39ec17 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -3639,6 +3639,44 @@ out_exit:
3639 IWL_DEBUG_MAC80211(priv, "leave\n"); 3639 IWL_DEBUG_MAC80211(priv, "leave\n");
3640} 3640}
3641 3641
3642static void iwl_mac_flush(struct ieee80211_hw *hw, bool drop)
3643{
3644 struct iwl_priv *priv = hw->priv;
3645
3646 mutex_lock(&priv->mutex);
3647 IWL_DEBUG_MAC80211(priv, "enter\n");
3648
3649 /* do not support "flush" */
3650 if (!priv->cfg->ops->lib->txfifo_flush)
3651 goto done;
3652
3653 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
3654 IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
3655 goto done;
3656 }
3657 if (iwl_is_rfkill(priv)) {
3658 IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
3659 goto done;
3660 }
3661
3662 /*
3663 * mac80211 will not push any more frames for transmit
3664 * until the flush is completed
3665 */
3666 if (drop) {
3667 IWL_DEBUG_MAC80211(priv, "send flush command\n");
3668 if (priv->cfg->ops->lib->txfifo_flush(priv, IWL_DROP_ALL)) {
3669 IWL_ERR(priv, "flush request fail\n");
3670 goto done;
3671 }
3672 }
3673 IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
3674 iwlagn_wait_tx_queue_empty(priv);
3675done:
3676 mutex_unlock(&priv->mutex);
3677 IWL_DEBUG_MAC80211(priv, "leave\n");
3678}
3679
3642/***************************************************************************** 3680/*****************************************************************************
3643 * 3681 *
3644 * driver setup and teardown 3682 * driver setup and teardown
@@ -3812,6 +3850,7 @@ static struct ieee80211_ops iwl_hw_ops = {
3812 .sta_add = iwlagn_mac_sta_add, 3850 .sta_add = iwlagn_mac_sta_add,
3813 .sta_remove = iwl_mac_sta_remove, 3851 .sta_remove = iwl_mac_sta_remove,
3814 .channel_switch = iwl_mac_channel_switch, 3852 .channel_switch = iwl_mac_channel_switch,
3853 .flush = iwl_mac_flush,
3815}; 3854};
3816 3855
3817static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 3856static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index be9d298cae2..0298642d1d7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -147,6 +147,8 @@ const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
147void iwlagn_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); 147void iwlagn_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
148int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); 148int 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);
151int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
150 152
151/* rx */ 153/* rx */
152void iwlagn_rx_queue_restock(struct iwl_priv *priv); 154void iwlagn_rx_queue_restock(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index b28cb4ffedc..08449556220 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -1216,6 +1216,10 @@ struct iwl_rem_sta_cmd {
1216#define IWL_TX_FIFO_VO_MSK cpu_to_le32(BIT(3)) 1216#define IWL_TX_FIFO_VO_MSK cpu_to_le32(BIT(3))
1217#define IWL_AGG_TX_QUEUE_MSK cpu_to_le32(0xffc00) 1217#define IWL_AGG_TX_QUEUE_MSK cpu_to_le32(0xffc00)
1218 1218
1219#define IWL_DROP_SINGLE 0
1220#define IWL_DROP_SELECTED 1
1221#define IWL_DROP_ALL 2
1222
1219/* 1223/*
1220 * REPLY_TXFIFO_FLUSH = 0x1e(command and response) 1224 * REPLY_TXFIFO_FLUSH = 0x1e(command and response)
1221 * 1225 *
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index bfa34561d9d..db315b05f98 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -205,6 +205,8 @@ struct iwl_lib_ops {
205 /* check for ack health */ 205 /* check for ack health */
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);
209
208 struct iwl_debugfs_ops debugfs_ops; 210 struct iwl_debugfs_ops debugfs_ops;
209}; 211};
210 212