Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[safe/jmp/linux-2.6] / drivers / net / wireless / rtl818x / rtl8187_dev.c
index f4747a1..fd81884 100644 (file)
@@ -189,25 +189,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);
        }
 }
 
@@ -403,7 +411,7 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev)
        struct rtl8187_rx_info *info;
        int ret = 0;
 
-       while (skb_queue_len(&priv->rx_queue) < 8) {
+       while (skb_queue_len(&priv->rx_queue) < 16) {
                skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL);
                if (!skb) {
                        ret = -ENOMEM;
@@ -657,7 +665,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);
@@ -777,9 +785,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);
@@ -867,6 +872,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;
@@ -881,6 +914,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 |
@@ -948,6 +982,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;
@@ -978,6 +1013,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);
 }
 
@@ -986,19 +1023,21 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
 {
        struct rtl8187_priv *priv = dev->priv;
        int i;
+       int ret = -EOPNOTSUPP;
 
+       mutex_lock(&priv->conf_mutex);
        if (priv->mode != NL80211_IFTYPE_MONITOR)
-               return -EOPNOTSUPP;
+               goto exit;
 
        switch (conf->type) {
        case NL80211_IFTYPE_STATION:
                priv->mode = conf->type;
                break;
        default:
-               return -EOPNOTSUPP;
+               goto exit;
        }
 
-       mutex_lock(&priv->conf_mutex);
+       ret = 0;
        priv->vif = conf->vif;
 
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
@@ -1007,8 +1046,9 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
                                 ((u8 *)conf->mac_addr)[i]);
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
+exit:
        mutex_unlock(&priv->conf_mutex);
-       return 0;
+       return ret;
 }
 
 static void rtl8187_remove_interface(struct ieee80211_hw *dev,