summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-trans.c
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2011-08-26 08:11:00 +0200
committerJohn W. Linville <linville@tuxdriver.com>2011-08-29 21:25:34 +0200
commita0eaad713f6fc1f63fe293ad6ce63cb01e05c03c (patch)
tree72dee57cdee0bfb9e796d6b12159b75eae17f5c7 /drivers/net/wireless/iwlwifi/iwl-trans.c
parentiwlagn: move isr_statistics to transport layer (diff)
downloadlinux-a0eaad713f6fc1f63fe293ad6ce63cb01e05c03c.tar.xz
linux-a0eaad713f6fc1f63fe293ad6ce63cb01e05c03c.zip
iwlagn: reclaim the packets in transport layer
The reclaim flow is really transport related. Define a simple API to allow the upper layer to request from the transport layer to reclaim packets until an index written in the Tx response / BA notification. The transport layer prepares a list of the packets that are being freed and passes this list to the upper layer. Between the two layers, the CB of the skb is used to pass a pointer to the context (BSS / PAN) in which the skb was sent. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-trans.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.c31
1 files changed, 30 insertions, 1 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c
index 63a310135f76..06cec8268c6c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.c
@@ -1106,7 +1106,7 @@ static int iwl_trans_pcie_tx(struct iwl_priv *priv, struct sk_buff *skb,
* regardless of the value of ret. "ret" only indicates
* whether or not we should update the write pointer.
*/
- if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
+ if (iwl_queue_space(q) < q->high_mark) {
if (wait_write_ptr) {
txq->need_update = 1;
iwl_txq_update_write_ptr(priv, txq);
@@ -1148,6 +1148,34 @@ static int iwl_trans_pcie_request_irq(struct iwl_trans *trans)
return 0;
}
+static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id,
+ int ssn, u32 status, struct sk_buff_head *skbs)
+{
+ struct iwl_priv *priv = priv(trans);
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ /* n_bd is usually 256 => n_bd - 1 = 0xff */
+ int tfd_num = ssn & (txq->q.n_bd - 1);
+ u8 agg_state;
+ bool cond;
+
+ if (txq->sched_retry) {
+ agg_state =
+ priv->stations[txq->sta_id].tid[txq->tid].agg.state;
+ cond = (agg_state != IWL_EMPTYING_HW_QUEUE_DELBA);
+ } else {
+ cond = (status != TX_STATUS_FAIL_PASSIVE_NO_RX);
+ }
+
+ if (txq->q.read_ptr != tfd_num) {
+ IWL_DEBUG_TX_REPLY(trans, "Retry scheduler reclaim "
+ "scd_ssn=%d idx=%d txq=%d swq=%d\n",
+ ssn , tfd_num, txq_id, txq->swq_id);
+ iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
+ if (iwl_queue_space(&txq->q) > txq->q.low_mark && cond)
+ iwl_wake_queue(priv, txq);
+ }
+}
+
static void iwl_trans_pcie_disable_sync_irq(struct iwl_trans *trans)
{
unsigned long flags;
@@ -1626,6 +1654,7 @@ const struct iwl_trans_ops trans_ops_pcie = {
.get_tx_cmd = iwl_trans_pcie_get_tx_cmd,
.tx = iwl_trans_pcie_tx,
+ .reclaim = iwl_trans_pcie_reclaim,
.txq_agg_disable = iwl_trans_pcie_txq_agg_disable,
.txq_agg_setup = iwl_trans_pcie_txq_agg_setup,