[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, ®4);
+ rt73usb_register_read(rt2x00dev, STA_CSR5, ®5);
+
+ 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