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