[PATCH 2/2] UBUNTU: Report TX retry and fail count to mac80211 in rt73usb

Ike Panhc ike.pan at canonical.com
Tue Oct 6 13:24:22 UTC 2009


BugLink: https://bugs.launchpad.net/bugs/444377

mac80211 needs driver to report the TX retry/fail count for bitrate control.
It is the hardware mac to re-transmit frames, so we need to collect the count
after the transmission has done.

Signed-off-by: Colin Ian King <colin.king at canonical.com>
Signed-off-by: Ike Panhc <ike.pan at canonical.com>
---
 .../drivers/net/wireless/rt2x00/rt2x00.h           |    7 ++
 .../drivers/net/wireless/rt2x00/rt2x00usb.c        |   31 ++++++---
 .../drivers/net/wireless/rt2x00/rt73usb.c          |   66 ++++++++++++++++++++
 .../drivers/net/wireless/rt2x00/rt73usb.h          |    4 +-
 4 files changed, 95 insertions(+), 13 deletions(-)

diff --git a/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt2x00.h b/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt2x00.h
index 427d01e..311b8d0 100644
--- a/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt2x00.h
@@ -525,6 +525,8 @@ struct rt2x00lib_ops {
 				struct sk_buff *skb);
 	void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
 			       const enum data_queue_qid queue);
+	void (*get_tx_status) (struct rt2x00_dev *rt2x00dev,
+			       struct txdone_entry_desc *txdesc);
 
 	/*
 	 * RX control handlers
@@ -809,6 +811,11 @@ struct rt2x00_dev {
 	 * Firmware image.
 	 */
 	const struct firmware *fw;
+
+	/*
+	 * Cached TX stats, rt73usb
+	 */
+	int tx_retry_count;
 };
 
 /*
diff --git a/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt2x00usb.c b/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt2x00usb.c
index 83862e7..7a08f8b 100644
--- a/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -135,6 +135,8 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
 	    !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
 		return;
 
+	memset(&txdesc, 0, sizeof(struct txdone_entry_desc));
+
 	/*
 	 * Remove the descriptor data from the buffer.
 	 */
@@ -142,18 +144,25 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
 
 	/*
 	 * Obtain the status about this packet.
-	 * Note that when the status is 0 it does not mean the
-	 * frame was send out correctly. It only means the frame
-	 * was succesfully pushed to the hardware, we have no
-	 * way to determine the transmission status right now.
-	 * (Only indirectly by looking at the failed TX counters
-	 * in the register).
 	 */
-	if (!urb->status)
-		__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
-	else
-		__set_bit(TXDONE_FAILURE, &txdesc.flags);
-	txdesc.retry = 0;
+	if (rt2x00dev->ops->lib->get_tx_status) {
+		rt2x00dev->ops->lib->get_tx_status(rt2x00dev, &txdesc);
+	} else {
+		/*
+		 * Note that when the status is 0 it does not mean the
+		 * frame was send out correctly. It only means the frame
+		 * was succesfully pushed to the hardware, we have no
+		 * way to determine the transmission status right now.
+		 * (Only indirectly by looking at the failed TX counters
+		 * in the register).
+		 */
+		if (!urb->status)
+			__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
+		else
+			__set_bit(TXDONE_FAILURE, &txdesc.flags);
+
+		txdesc.retry = 0;
+	}
 
 	rt2x00lib_txdone(entry, &txdesc);
 }
diff --git a/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt73usb.c b/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt73usb.c
index 2521a08..3dde950 100644
--- a/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt73usb.c
@@ -36,6 +36,13 @@
 #include "rt2x00usb.h"
 #include "rt73usb.h"
 
+struct rt73_work_info {
+	struct work_struct work;
+	struct rt2x00_dev *rt2x00dev;
+};
+
+struct rt73_work_info rt73_work;
+
 /*
  * Register access.
  * All access to the CSR registers will go through the methods
@@ -1437,6 +1444,62 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 	}
 }
 
+static void rt73usb_tx_status_work(struct work_struct *work)
+{
+	u32 reg4;
+	u32 reg5;
+	int retry_fails;
+	struct rt73_work_info *rt73_work_item =
+		container_of(work, struct rt73_work_info, work);
+	struct rt2x00_dev *rt2x00dev = rt73_work_item->rt2x00dev;
+
+	rt73usb_register_read(rt2x00dev, STA_CSR4, &reg4);
+	rt73usb_register_read(rt2x00dev, STA_CSR5, &reg5);
+
+	retry_fails = rt2x00_get_field32(reg5, STA_CSR5_TX_RETRY_FAIL_COUNT);
+
+	if (retry_fails > 0)
+		/* -ve retry count indicates a failure */
+		rt2x00dev->tx_retry_count = -retry_fails;
+	else
+		if (rt2x00_get_field32(reg4, STA_CSR4_TX_NO_RETRY_COUNT) > 0)
+			rt2x00dev->tx_retry_count = 0;	/* Success */
+		else if (rt2x00_get_field32(reg4, STA_CSR4_TX_ONE_RETRY_COUNT) > 0)
+			rt2x00dev->tx_retry_count = 1;	/* Single retry */
+		else {
+			int retries = rt2x00_get_field32(reg5, STA_CSR5_TX_MULTI_RETRY_COUNT);
+			if (retries > 0)
+				rt2x00dev->tx_retry_count = retries;
+			else
+				rt2x00dev->tx_retry_count = 0;	/* Unknown */
+		}
+}
+
+static void rt73usb_get_tx_status(struct rt2x00_dev *rt2x00dev,
+				  struct txdone_entry_desc *txdesc)
+{
+	rt73_work.rt2x00dev = rt2x00dev;
+
+	/*
+	 * Caution: This is being called from withing an interrupt context.
+	 * We cannot gather statistics on the current transmitted packets
+	 * inside the interrupt context because we need to do USB register
+	 * reads. Instead, we shedule it to be run on a work queue to gather
+	 * statistics for the next packet. It's not 100% perfect solution
+	 * but it does at least supply some information back up the stack
+	 * to allow bitrate control to work.
+	 */
+	schedule_work(&rt73_work.work);
+
+	if (rt2x00dev->tx_retry_count < 0) {
+		__set_bit(TXDONE_FAILURE, &txdesc->flags);
+		txdesc->retry = 0;
+	} else {
+		__set_bit(TXDONE_SUCCESS, &txdesc->flags);
+		txdesc->retry = rt2x00dev->tx_retry_count;
+	}
+}
+
 /*
  * RX control handlers
  */
@@ -1938,6 +2001,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 {
 	int retval;
 
+	INIT_WORK(&rt73_work.work, rt73usb_tx_status_work);
+
 	/*
 	 * Allocate eeprom data.
 	 */
@@ -2044,6 +2109,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
 	.write_beacon		= rt73usb_write_beacon,
 	.get_tx_data_len	= rt73usb_get_tx_data_len,
 	.kick_tx_queue		= rt73usb_kick_tx_queue,
+	.get_tx_status		= rt73usb_get_tx_status,
 	.fill_rxdone		= rt73usb_fill_rxdone,
 	.config_filter		= rt73usb_config_filter,
 	.config_intf		= rt73usb_config_intf,
diff --git a/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt73usb.h b/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt73usb.h
index 1484935..60f98be 100644
--- a/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/updates/compat-wireless-2.6/drivers/net/wireless/rt2x00/rt73usb.h
@@ -619,8 +619,8 @@ struct hw_pairwise_ta_entry {
  * STA_CSR5: TX Retry count.
  */
 #define STA_CSR5			0x30d4
-#define STA_CSR4_TX_MULTI_RETRY_COUNT	FIELD32(0x0000ffff)
-#define STA_CSR4_TX_RETRY_FAIL_COUNT	FIELD32(0xffff0000)
+#define STA_CSR5_TX_MULTI_RETRY_COUNT	FIELD32(0x0000ffff)
+#define STA_CSR5_TX_RETRY_FAIL_COUNT	FIELD32(0xffff0000)
 
 /*
  * QOS control registers.
-- 
1.6.0.4





More information about the kernel-team mailing list