[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, ®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.
>
ACK
More information about the kernel-team
mailing list