Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2f47690e authored by Larry Finger's avatar Larry Finger Committed by John W. Linville
Browse files

rtl8187: Fix driver to return TX retry info for RTL8187L



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: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Tested-by: default avatarHerton Ronaldo Krzesinski <herton@mandriva.com.br>
Tested-by: default avatarMartín Ernesto Barreyro <barreyromartin@gmail.com>
Acked-by: default avatarHin-Tak Leung <htl10@users.sourceforge.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2a57cf3e
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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);
+55 −18
Original line number Diff line number Diff line
@@ -177,9 +177,8 @@ 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) {
	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 */
@@ -192,10 +191,19 @@ static void rtl8187_tx_cb(struct urb *urb)
				old_skb = skb_dequeue(&priv->b_tx_status.queue);
				ieee80211_tx_status_irqsafe(hw, old_skb);
			}
			return;
		} else {
		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !urb->status)
			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);
	}
}

@@ -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);
@@ -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);
@@ -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;
@@ -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 |
@@ -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;
@@ -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);
}