Search Linux Wireless

[PATCH] ar9170: simplify & deBUG tx_status queueing and reporting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch simplifies the tx_status report code by using four tx_queues per
station instead of only one. (the skb lookup should be in O(1) now :-p ).

Also, it fixes a really obvious copy&paste bug in the janitor work code and
adds back a few spilled bits to the hardware definition header about QoS.

Signed-off-by: Christian Lamparter <chunkeey@xxxxxx>
---
Alina, does the driver - with this patch - still cause freeze/crash/hangs?

Regards,
	Chr
---
diff --git a/drivers/net/wireless/ar9170/ar9170.h b/drivers/net/wireless/ar9170/ar9170.h
index c49d713..f4fb2e9 100644
--- a/drivers/net/wireless/ar9170/ar9170.h
+++ b/drivers/net/wireless/ar9170/ar9170.h
@@ -159,7 +159,7 @@ struct ar9170 {
 };
 
 struct ar9170_sta_info {
-	struct sk_buff_head tx_status;
+	struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
 };
 
 #define IS_STARTED(a)		(a->state >= AR9170_STARTED)
diff --git a/drivers/net/wireless/ar9170/hw.h b/drivers/net/wireless/ar9170/hw.h
index ad205f8..231d347 100644
--- a/drivers/net/wireless/ar9170/hw.h
+++ b/drivers/net/wireless/ar9170/hw.h
@@ -397,10 +397,21 @@ struct ar9170_cmd_response {
 	};
 } __packed;
 
+/* QoS */
+
 /* mac80211 queue to HW/FW map */
 static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 };
 
 /* HW/FW queue to mac80211 map */
 static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 };
 
+enum ar9170_txq {
+	AR9170_TXQ_BE,
+	AR9170_TXQ_BK,
+	AR9170_TXQ_VI,
+	AR9170_TXQ_VO,
+
+	__AR9170_NUM_TXQ,
+};
+
 #endif /* __AR9170_HW_H */
diff --git a/drivers/net/wireless/ar9170/main.c b/drivers/net/wireless/ar9170/main.c
index a3b5323..f8c2357 100644
--- a/drivers/net/wireless/ar9170/main.c
+++ b/drivers/net/wireless/ar9170/main.c
@@ -277,54 +277,6 @@ static struct sk_buff *ar9170_find_skb_in_queue(struct ar9170 *ar,
 	return NULL;
 }
 
-static struct sk_buff *ar9170_find_skb_in_queue_by_mac(struct ar9170 *ar,
-						       const u8 *mac,
-						       struct sk_buff_head *q)
-{
-	unsigned long flags;
-	struct sk_buff *skb;
-
-	spin_lock_irqsave(&q->lock, flags);
-	skb_queue_walk(q, skb) {
-		struct ar9170_tx_control *txc = (void *) skb->data;
-		struct ieee80211_hdr *hdr = (void *) txc->frame_data;
-
-		if (compare_ether_addr(ieee80211_get_DA(hdr), mac))
-			continue;
-
-		__skb_unlink(skb, q);
-		spin_unlock_irqrestore(&q->lock, flags);
-		return skb;
-	}
-	spin_unlock_irqrestore(&q->lock, flags);
-	return NULL;
-}
-
-static struct sk_buff *ar9170_find_skb_in_queue_by_txcq(struct ar9170 *ar,
-							const u32 queue,
-							struct sk_buff_head *q)
-{
-	unsigned long flags;
-	struct sk_buff *skb;
-
-	spin_lock_irqsave(&q->lock, flags);
-	skb_queue_walk(q, skb) {
-		struct ar9170_tx_control *txc = (void *) skb->data;
-		u32 txc_queue = (le32_to_cpu(txc->phy_control) &
-				AR9170_TX_PHY_QOS_MASK) >>
-				AR9170_TX_PHY_QOS_SHIFT;
-
-		if (queue != txc_queue)
-			continue;
-
-		__skb_unlink(skb, q);
-		spin_unlock_irqrestore(&q->lock, flags);
-		return skb;
-	}
-	spin_unlock_irqrestore(&q->lock, flags);
-	return NULL;
-}
-
 static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
 					      const u32 queue)
 {
@@ -344,21 +296,21 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
 
 	if (likely(sta)) {
 		struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv;
-		skb = ar9170_find_skb_in_queue_by_txcq(ar, queue,
-						       &sta_priv->tx_status);
-	} else {
-		/* STA is not in database (yet/anymore). */
+		skb = skb_dequeue(&sta_priv->tx_status[queue]);
+		rcu_read_unlock();
+		if (likely(skb))
+			return skb;
+	} else
+		rcu_read_unlock();
 
-		/* scan the waste bin for likely candidates */
+	/* scan the waste queue for candidates */
+	skb = ar9170_find_skb_in_queue(ar, mac, queue,
+				       &ar->global_tx_status_waste);
+	if (!skb) {
+		/* so it still _must_ be in the global list. */
 		skb = ar9170_find_skb_in_queue(ar, mac, queue,
-					       &ar->global_tx_status_waste);
-		if (!skb) {
-			/* so it still _must_ be in the global list. */
-			skb = ar9170_find_skb_in_queue(ar, mac, queue,
-						       &ar->global_tx_status);
-		}
+					       &ar->global_tx_status);
 	}
-	rcu_read_unlock();
 
 #ifdef AR9170_QUEUE_DEBUG
 	if (unlikely((!skb) && net_ratelimit())) {
@@ -367,7 +319,6 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
 				wiphy_name(ar->hw->wiphy), mac, queue);
 	}
 #endif /* AR9170_QUEUE_DEBUG */
-
 	return skb;
 }
 
@@ -381,9 +332,13 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
 static void ar9170_tx_status_janitor(struct work_struct *work)
 {
 	struct ar9170 *ar = container_of(work, struct ar9170,
-					 filter_config_work);
+					 tx_status_janitor.work);
 	struct sk_buff *skb;
 
+	if (unlikely(!IS_STARTED(ar)))
+		return ;
+
+	mutex_lock(&ar->mutex);
 	/* recycle the garbage back to mac80211... one by one. */
 	while ((skb = skb_dequeue(&ar->global_tx_status_waste))) {
 #ifdef AR9170_QUEUE_DEBUG
@@ -395,8 +350,6 @@ static void ar9170_tx_status_janitor(struct work_struct *work)
 					AR9170_TX_STATUS_FAILED);
 	}
 
-
-
 	while ((skb = skb_dequeue(&ar->global_tx_status))) {
 #ifdef AR9170_QUEUE_DEBUG
 		printk(KERN_DEBUG "%s: moving frame into waste queue =>\n",
@@ -411,6 +364,8 @@ static void ar9170_tx_status_janitor(struct work_struct *work)
 	if (skb_queue_len(&ar->global_tx_status_waste) > 0)
 		queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor,
 				   msecs_to_jiffies(100));
+
+	mutex_unlock(&ar->mutex);
 }
 
 static void ar9170_handle_command_response(struct ar9170 *ar,
@@ -1012,7 +967,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
 		if (info->control.sta) {
 			sta_info = (void *) info->control.sta->drv_priv;
-			skb_queue_tail(&sta_info->tx_status, skb);
+			skb_queue_tail(&sta_info->tx_status[queue], skb);
 		} else {
 			skb_queue_tail(&ar->global_tx_status, skb);
 
@@ -1025,7 +980,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	err = ar->tx(ar, skb, tx_status, 0);
 	if (unlikely(tx_status && err)) {
 		if (info->control.sta)
-			skb_unlink(skb, &sta_info->tx_status);
+			skb_unlink(skb, &sta_info->tx_status[queue]);
 		else
 			skb_unlink(skb, &ar->global_tx_status);
 	}
@@ -1479,55 +1434,35 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
 	struct ar9170 *ar = hw->priv;
 	struct ar9170_sta_info *info = (void *) sta->drv_priv;
 	struct sk_buff *skb;
+	unsigned int i;
 
 	switch (cmd) {
 	case STA_NOTIFY_ADD:
-		skb_queue_head_init(&info->tx_status);
-
-		/*
-		 * do we already have a frame that needs tx_status
-		 * from this station in our queue?
-		 * If so then transfer them to the new station queue.
-		 */
-
-		/* preserve the correct order - check the waste bin first */
-		while ((skb = ar9170_find_skb_in_queue_by_mac(ar, sta->addr,
-				&ar->global_tx_status_waste)))
-			skb_queue_tail(&info->tx_status, skb);
-
-		/* now the still pending frames */
-		while ((skb = ar9170_find_skb_in_queue_by_mac(ar, sta->addr,
-				&ar->global_tx_status)))
-			skb_queue_tail(&info->tx_status, skb);
-
-#ifdef AR9170_QUEUE_DEBUG
-		printk(KERN_DEBUG "%s: STA[%pM] has %d queued frames =>\n",
-		       wiphy_name(ar->hw->wiphy), sta->addr,
-		       skb_queue_len(&info->tx_status));
-
-		ar9170_dump_station_tx_status_queue(ar, &info->tx_status);
-#endif /* AR9170_QUEUE_DEBUG */
-
-
+		for (i = 0; i < ar->hw->queues; i++)
+			skb_queue_head_init(&info->tx_status[i]);
 		break;
 
 	case STA_NOTIFY_REMOVE:
 
 		/*
 		 * transfer all outstanding frames that need a tx_status
-		 * reports to the fallback queue
+		 * reports to the global tx_status queue
 		 */
 
-		while ((skb = skb_dequeue(&ar->global_tx_status))) {
+		for (i = 0; i < ar->hw->queues; i++) {
+			while ((skb = skb_dequeue(&info->tx_status[i]))) {
 #ifdef AR9170_QUEUE_DEBUG
-			printk(KERN_DEBUG "%s: queueing frame in global "
-					  "tx_status queue =>\n",
-			       wiphy_name(ar->hw->wiphy));
+				printk(KERN_DEBUG "%s: queueing frame in "
+					  "global tx_status queue =>\n",
+				       wiphy_name(ar->hw->wiphy));
 
-			ar9170_print_txheader(ar, skb);
+				ar9170_print_txheader(ar, skb);
 #endif /* AR9170_QUEUE_DEBUG */
-			skb_queue_tail(&ar->global_tx_status_waste, skb);
+				skb_queue_tail(&ar->global_tx_status, skb);
+			}
 		}
+		queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor,
+				   msecs_to_jiffies(100));
 		break;
 
 	default:
@@ -1571,7 +1506,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
 	int ret;
 
 	mutex_lock(&ar->mutex);
-	if ((param) && !(queue > 4)) {
+	if ((param) && !(queue > ar->hw->queues)) {
 		memcpy(&ar->edcf[ar9170_qos_hwmap[queue]],
 		       param, sizeof(*param));
 
@@ -1635,7 +1570,7 @@ void *ar9170_alloc(size_t priv_size)
 			 IEEE80211_HW_SIGNAL_DBM |
 			 IEEE80211_HW_NOISE_DBM;
 
-	ar->hw->queues = 4;
+	ar->hw->queues = __AR9170_NUM_TXQ;
 	ar->hw->extra_tx_headroom = 8;
 	ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
 
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux