.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 = {
.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 = {
.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 = {
.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 = {
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);
}
}
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);
+}
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
*
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);
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);
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;
};
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;