Skip to content

Commit

Permalink
rtl8187: Fix driver to return TX retry info for RTL8187L
Browse files Browse the repository at this point in the history
Current code for the RTL8187 is not returning valid retry information, thus the
rate-setting mechanism is not functioning. As a further complication, this info
is only obtained by reading a register, which cannot be read while in interrupt
context.

This patch implements the TX status return to mac80211 through the use of a
work queue.

One additional problem is that the driver currently enables the rate fallback
mechanism of the device, which conflicts with the mac80211 rate-setting
algorithm. This version of the patch disables rate fallback.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Tested-by: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
Tested-by: Martín Ernesto Barreyro <barreyromartin@gmail.com>
Acked-by: Hin-Tak Leung <htl10@users.sourceforge.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Larry Finger authored and John W. Linville committed Jan 29, 2009
1 parent 2a57cf3 commit 2f47690
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 19 deletions.
4 changes: 3 additions & 1 deletion drivers/net/wireless/rtl818x/rtl8187.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ struct rtl8187_priv {
struct usb_device *udev;
u32 rx_conf;
struct usb_anchor anchored;
struct delayed_work work;
struct ieee80211_hw *dev;
u16 txpwr_base;
u8 asic_rev;
u8 is_rtl8187b;
Expand All @@ -117,7 +119,7 @@ struct rtl8187_priv {
struct {
__le64 buf;
struct sk_buff_head queue;
} b_tx_status;
} b_tx_status; /* This queue is used by both -b and non-b devices */
};

void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
Expand Down
73 changes: 55 additions & 18 deletions drivers/net/wireless/rtl818x/rtl8187_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,25 +177,33 @@ static void rtl8187_tx_cb(struct urb *urb)
sizeof(struct rtl8187_tx_hdr));
ieee80211_tx_info_clear_status(info);

if (!urb->status &&
!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
priv->is_rtl8187b) {
skb_queue_tail(&priv->b_tx_status.queue, skb);
if (!(urb->status) && !(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
if (priv->is_rtl8187b) {
skb_queue_tail(&priv->b_tx_status.queue, skb);

/* queue is "full", discard last items */
while (skb_queue_len(&priv->b_tx_status.queue) > 5) {
struct sk_buff *old_skb;
/* queue is "full", discard last items */
while (skb_queue_len(&priv->b_tx_status.queue) > 5) {
struct sk_buff *old_skb;

dev_dbg(&priv->udev->dev,
"transmit status queue full\n");
dev_dbg(&priv->udev->dev,
"transmit status queue full\n");

old_skb = skb_dequeue(&priv->b_tx_status.queue);
ieee80211_tx_status_irqsafe(hw, old_skb);
}
} else {
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !urb->status)
old_skb = skb_dequeue(&priv->b_tx_status.queue);
ieee80211_tx_status_irqsafe(hw, old_skb);
}
return;
} else {
info->flags |= IEEE80211_TX_STAT_ACK;
}
}
if (priv->is_rtl8187b)
ieee80211_tx_status_irqsafe(hw, skb);
else {
/* Retry information for the RTI8187 is only available by
* reading a register in the device. We are in interrupt mode
* here, thus queue the skb and finish on a work queue. */
skb_queue_tail(&priv->b_tx_status.queue, skb);
queue_delayed_work(hw->workqueue, &priv->work, 0);
}
}

Expand Down Expand Up @@ -645,7 +653,7 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)

rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0);
rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0);
rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81);
rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0);

// TODO: set RESP_RATE and BRSR properly
rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0);
Expand Down Expand Up @@ -765,9 +773,6 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);

rtl818x_iowrite16_idx(priv, (__le16 *)0xFFE0, 0x0FFF, 1);
reg = rtl818x_ioread8(priv, &priv->map->RATE_FALLBACK);
reg |= RTL818X_RATE_FALLBACK_ENABLE;
rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, reg);

rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2);
Expand Down Expand Up @@ -855,6 +860,34 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
return 0;
}

static void rtl8187_work(struct work_struct *work)
{
/* The RTL8187 returns the retry count through register 0xFFFA. In
* addition, it appears to be a cumulative retry count, not the
* value for the current TX packet. When multiple TX entries are
* queued, the retry count will be valid for the last one in the queue.
* The "error" should not matter for purposes of rate setting. */
struct rtl8187_priv *priv = container_of(work, struct rtl8187_priv,
work.work);
struct ieee80211_tx_info *info;
struct ieee80211_hw *dev = priv->dev;
static u16 retry;
u16 tmp;

mutex_lock(&priv->conf_mutex);
tmp = rtl818x_ioread16(priv, (__le16 *)0xFFFA);
while (skb_queue_len(&priv->b_tx_status.queue) > 0) {
struct sk_buff *old_skb;

old_skb = skb_dequeue(&priv->b_tx_status.queue);
info = IEEE80211_SKB_CB(old_skb);
info->status.rates[0].count = tmp - retry + 1;
ieee80211_tx_status_irqsafe(dev, old_skb);
}
retry = tmp;
mutex_unlock(&priv->conf_mutex);
}

static int rtl8187_start(struct ieee80211_hw *dev)
{
struct rtl8187_priv *priv = dev->priv;
Expand All @@ -869,6 +902,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
mutex_lock(&priv->conf_mutex);

init_usb_anchor(&priv->anchored);
priv->dev = dev;

if (priv->is_rtl8187b) {
reg = RTL818X_RX_CONF_MGMT |
Expand Down Expand Up @@ -936,6 +970,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
reg |= RTL818X_CMD_TX_ENABLE;
reg |= RTL818X_CMD_RX_ENABLE;
rtl818x_iowrite8(priv, &priv->map->CMD, reg);
INIT_DELAYED_WORK(&priv->work, rtl8187_work);
mutex_unlock(&priv->conf_mutex);

return 0;
Expand Down Expand Up @@ -966,6 +1001,8 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
dev_kfree_skb_any(skb);

usb_kill_anchored_urbs(&priv->anchored);
if (!priv->is_rtl8187b)
cancel_delayed_work_sync(&priv->work);
mutex_unlock(&priv->conf_mutex);
}

Expand Down

0 comments on commit 2f47690

Please sign in to comment.