This patch improves the link stability under load
by reordering and rewriting parts of the tx retry
procedure. It's all based on long hours of trail
and error, but sadly QoS + AMPDU is still not
working.
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
#include "linux/ieee80211.h"
#include "wol.h"
#include "linux/ieee80211.h"
#include "wol.h"
-static void wlan_txunstuck(unsigned int queue)
+static void wlan_txunstuck(unsigned int qidx)
- set_wlan_txq_dma_addr(queue, ((uint32_t) fw.wlan.tx_queue[queue].head) | 1);
+ struct dma_queue *queue = &fw.wlan.tx_queue[qidx];
+ struct dma_desc *iter;
+
+ /*
+ * walk up to the last descriptor which hasn't been
+ * processed by the hardware before it bailed out
+ * due to a TX error.
+ * Note: if there was no more "pending" frame
+ * in the queue, it iter will be on the
+ * queue->terminator (which is fine)
+ */
+ __for_each_desc_bits(iter, queue, AR9170_OWN_BITS_SW);
+
+ set_wlan_txq_dma_addr(qidx, ((uint32_t) iter) | 1);
+ wlan_trigger(BIT(qidx));
}
#ifdef CONFIG_CARL9170FW_DMA_QUEUE_BUMP
}
#ifdef CONFIG_CARL9170FW_DMA_QUEUE_BUMP
-static void wlan_txupdate(unsigned int queue)
+static void wlan_txupdate(unsigned int qidx)
- set_wlan_txq_dma_addr(queue, ((uint32_t) fw.wlan.tx_queue[queue].head));
+ struct dma_queue *queue = &fw.wlan.tx_queue[qidx];
+ struct dma_desc *iter;
+ /* comment in wlan_txunstuck applies here too. */
+ __for_each_desc_bits(iter, queue, AR9170_OWN_BITS_SW);
+
+ set_wlan_txq_dma_addr(qidx, ((uint32_t) iter));
+ wlan_trigger(BIT(qidx));
}
void wlan_dma_bump(unsigned int qidx)
}
void wlan_dma_bump(unsigned int qidx)
wlan_txunstuck(qidx);
/* abort cycle - this is necessary due to HW design */
wlan_txunstuck(qidx);
/* abort cycle - this is necessary due to HW design */
} else {
/* (HT-) BlockACK failure */
} else {
/* (HT-) BlockACK failure */
BUG_ON(dma_unlink_head(queue) != desc);
#endif /* CONFIG_CARL9170FW_DEBUG */
dma_put(&fw.wlan.tx_retry, desc);
BUG_ON(dma_unlink_head(queue) != desc);
#endif /* CONFIG_CARL9170FW_DEBUG */
dma_put(&fw.wlan.tx_retry, desc);
}
} else {
/* out of frame attempts - discard frame */
}
} else {
/* out of frame attempts - discard frame */
if (fw.wlan.fw_desc_callback)
fw.wlan.fw_desc_callback(super, success);
if (fw.wlan.fw_desc_callback)
fw.wlan.fw_desc_callback(super, success);
}
if (unlikely(super->s.cab))
}
if (unlikely(super->s.cab))
/* recycle freed descriptors */
dma_reclaim(&fw.pta.down_queue, desc);
down_trigger();
/* recycle freed descriptors */
dma_reclaim(&fw.pta.down_queue, desc);
down_trigger();
+out:
+ /*
+ * if we encounter a frame which run out of (normal)
+ * tx retries we have to stop too.
+ */
+ return !txfail;
}
void handle_wlan_tx_completion(void)
}
void handle_wlan_tx_completion(void)