diff mbox

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

Message ID 1254835462-9866-1-git-send-email-ike.pan@canonical.com
State Accepted
Headers show

Commit Message

Ike Panhc Oct. 6, 2009, 1:24 p.m. UTC
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@canonical.com>
Signed-off-by: Ike Panhc <ike.pan@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(-)

Comments

Michael Frey Oct. 6, 2009, 6:46 p.m. UTC | #1
Ike Panhc wrote:
> 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@canonical.com>
> Signed-off-by: Ike Panhc <ike.pan@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.
>   
ACK
diff mbox

Patch

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.