[PATCH] Back off if ring buffer is full

Eugene Krasnikov k.eugene.e at gmail.com
Tue Jul 16 09:17:08 EDT 2013


If ring is full stop mac80211 queues so upper layers will not try to
send any frames until bottom half has capacity for sending frames.

Signed-off-by: Eugene Krasnikov <k.eugene.e at gmail.com>
---
 dxe.c     | 22 ++++++++++++++++++++++
 dxe.h     |  1 +
 wcn36xx.h |  1 +
 3 files changed, 24 insertions(+)

diff --git a/dxe.c b/dxe.c
index fd6cbae..502e0df 100644
--- a/dxe.c
+++ b/dxe.c
@@ -319,6 +319,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
 {
 	struct wcn36xx_dxe_ctl *ctl = ch->tail_blk_ctl;
 	struct ieee80211_tx_info *info;
+	unsigned long flags;
 
 	while (ctl != ch->head_blk_ctl &&
 	       !(ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) {
@@ -330,6 +331,13 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
 				/* Keep frame until TX status comes */
 				ieee80211_free_txskb(wcn->hw, ctl->skb);
 			}
+			spin_lock_irqsave(&ctl->skb_lock, flags);
+			if (wcn->queues_stopped) {
+				wcn->queues_stopped = false;
+				ieee80211_wake_queues(wcn->hw);
+			}
+			spin_unlock_irqrestore(&ctl->skb_lock, flags);
+
 			ctl->skb = NULL;
 		}
 		ctl = ctl->next;
@@ -539,10 +547,24 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
 	struct wcn36xx_dxe_ctl *ctl = NULL;
 	struct wcn36xx_dxe_desc *desc = NULL;
 	struct wcn36xx_dxe_ch *ch = NULL;
+	unsigned long flags;
 
 	ch = is_low ? &wcn->dxe_tx_l_ch : &wcn->dxe_tx_h_ch;
 
 	ctl = ch->head_blk_ctl;
+	spin_lock_irqsave(&ctl->next->skb_lock, flags);
+	/*
+	 * If skb is not null that means that we reached the tail of the ring
+	 * hence ring is full. Stop queues to let mac80211 back off until ring
+	 * has an empty slot again.
+	 */
+	if (NULL != ctl->next->skb) {
+		ieee80211_stop_queues(wcn->hw);
+		wcn->queues_stopped = true;
+		spin_unlock_irqrestore(&ctl->next->skb_lock, flags);
+		return -EBUSY;
+	}
+	spin_unlock_irqrestore(&ctl->next->skb_lock, flags);
 	ctl->skb = NULL;
 	desc = ctl->desc;
 
diff --git a/dxe.h b/dxe.h
index 0b154bb..16f0b12 100644
--- a/dxe.h
+++ b/dxe.h
@@ -195,6 +195,7 @@ struct wcn36xx_dxe_ctl {
 	unsigned int		desc_phy_addr;
 	int			ctl_blk_order;
 	struct sk_buff		*skb;
+	spinlock_t              skb_lock;
 	void			*bd_cpu_addr;
 	dma_addr_t		bd_phy_addr;
 };
diff --git a/wcn36xx.h b/wcn36xx.h
index 743325e..ff349ea 100644
--- a/wcn36xx.h
+++ b/wcn36xx.h
@@ -166,6 +166,7 @@ struct wcn36xx {
 
 	/* For synchronization of DXE resources from BH, IRQ and WQ contexts */
 	spinlock_t	dxe_lock;
+	bool                    queues_stopped;
 
 	/* Memory pools */
 	struct wcn36xx_dxe_mem_pool mgmt_mem_pool;
-- 
1.7.11.3




More information about the wcn36xx mailing list