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

Michael Frey michael.frey at canonical.com
Tue Oct 6 18:46:42 UTC 2009



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 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.
>   
ACK




More information about the kernel-team mailing list