]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/net/wireless/rtl818x/rtl8187_dev.c
rtl8187: Increase receive queue depth
[net-next-2.6.git] / drivers / net / wireless / rtl818x / rtl8187_dev.c
index 69ea5222f1637175507951b07613f3e632d99b1e..db7318d1d401147192f0f638f646fb3e3056e1f5 100644 (file)
@@ -99,7 +99,6 @@ static const struct ieee80211_channel rtl818x_channels[] = {
 static void rtl8187_iowrite_async_cb(struct urb *urb)
 {
        kfree(urb->context);
-       usb_free_urb(urb);
 }
 
 static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr,
@@ -136,11 +135,13 @@ static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr,
        usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0),
                             (unsigned char *)dr, buf, len,
                             rtl8187_iowrite_async_cb, buf);
+       usb_anchor_urb(urb, &priv->anchored);
        rc = usb_submit_urb(urb, GFP_ATOMIC);
        if (rc < 0) {
                kfree(buf);
-               usb_free_urb(urb);
+               usb_unanchor_urb(urb);
        }
+       usb_free_urb(urb);
 }
 
 static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv,
@@ -172,7 +173,6 @@ static void rtl8187_tx_cb(struct urb *urb)
        struct ieee80211_hw *hw = info->rate_driver_data[0];
        struct rtl8187_priv *priv = hw->priv;
 
-       usb_free_urb(info->rate_driver_data[1]);
        skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
                                          sizeof(struct rtl8187_tx_hdr));
        ieee80211_tx_info_clear_status(info);
@@ -213,7 +213,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!urb) {
                kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        flags = skb->len;
@@ -238,7 +238,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
                hdr->flags = cpu_to_le32(flags);
                hdr->len = 0;
                hdr->rts_duration = rts_dur;
-               hdr->retry = cpu_to_le32(info->control.rates[0].count << 8);
+               hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
                buf = hdr;
 
                ep = 2;
@@ -256,7 +256,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
                memset(hdr, 0, sizeof(*hdr));
                hdr->flags = cpu_to_le32(flags);
                hdr->rts_duration = rts_dur;
-               hdr->retry = cpu_to_le32(info->control.rates[0].count << 8);
+               hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
                hdr->tx_duration =
                        ieee80211_generic_frame_duration(dev, priv->vif,
                                                         skb->len, txrate);
@@ -273,13 +273,16 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 
        usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep),
                          buf, skb->len, rtl8187_tx_cb, skb);
+       urb->transfer_flags |= URB_ZERO_PACKET;
+       usb_anchor_urb(urb, &priv->anchored);
        rc = usb_submit_urb(urb, GFP_ATOMIC);
        if (rc < 0) {
-               usb_free_urb(urb);
+               usb_unanchor_urb(urb);
                kfree_skb(skb);
        }
+       usb_free_urb(urb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void rtl8187_rx_cb(struct urb *urb)
@@ -292,50 +295,35 @@ static void rtl8187_rx_cb(struct urb *urb)
        int rate, signal;
        u32 flags;
        u32 quality;
+       unsigned long f;
 
-       spin_lock(&priv->rx_queue.lock);
+       spin_lock_irqsave(&priv->rx_queue.lock, f);
        if (skb->next)
                __skb_unlink(skb, &priv->rx_queue);
        else {
-               spin_unlock(&priv->rx_queue.lock);
+               spin_unlock_irqrestore(&priv->rx_queue.lock, f);
                return;
        }
-       spin_unlock(&priv->rx_queue.lock);
+       spin_unlock_irqrestore(&priv->rx_queue.lock, f);
+       skb_put(skb, urb->actual_length);
 
        if (unlikely(urb->status)) {
-               usb_free_urb(urb);
                dev_kfree_skb_irq(skb);
                return;
        }
 
-       skb_put(skb, urb->actual_length);
        if (!priv->is_rtl8187b) {
                struct rtl8187_rx_hdr *hdr =
                        (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
                flags = le32_to_cpu(hdr->flags);
-               signal = hdr->signal & 0x7f;
+               /* As with the RTL8187B below, the AGC is used to calculate
+                * signal strength and quality. In this case, the scaling
+                * constants are derived from the output of p54usb.
+                */
+               quality = 130 - ((41 * hdr->agc) >> 6);
+               signal = -4 - ((27 * hdr->agc) >> 6);
                rx_status.antenna = (hdr->signal >> 7) & 1;
-               rx_status.noise = hdr->noise;
                rx_status.mactime = le64_to_cpu(hdr->mac_time);
-               priv->quality = signal;
-               rx_status.qual = priv->quality;
-               priv->noise = hdr->noise;
-               rate = (flags >> 20) & 0xF;
-               if (rate > 3) { /* OFDM rate */
-                       if (signal > 90)
-                               signal = 90;
-                       else if (signal < 25)
-                               signal = 25;
-                       signal = 90 - signal;
-               } else {        /* CCK rate */
-                       if (signal > 95)
-                               signal = 95;
-                       else if (signal < 30)
-                               signal = 30;
-                       signal = 95 - signal;
-               }
-               rx_status.signal = signal;
-               priv->signal = signal;
        } else {
                struct rtl8187b_rx_hdr *hdr =
                        (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
@@ -353,18 +341,18 @@ static void rtl8187_rx_cb(struct urb *urb)
                 */
                flags = le32_to_cpu(hdr->flags);
                quality = 170 - hdr->agc;
-               if (quality > 100)
-                       quality = 100;
                signal = 14 - hdr->agc / 2;
-               rx_status.qual = quality;
-               priv->quality = quality;
-               rx_status.signal = signal;
-               priv->signal = signal;
                rx_status.antenna = (hdr->rssi >> 7) & 1;
                rx_status.mactime = le64_to_cpu(hdr->mac_time);
-               rate = (flags >> 20) & 0xF;
        }
 
+       if (quality > 100)
+               quality = 100;
+       rx_status.qual = quality;
+       priv->quality = quality;
+       rx_status.signal = signal;
+       priv->signal = signal;
+       rate = (flags >> 20) & 0xF;
        skb_trim(skb, flags & 0x0FFF);
        rx_status.rate_idx = rate;
        rx_status.freq = dev->conf.channel->center_freq;
@@ -376,7 +364,6 @@ static void rtl8187_rx_cb(struct urb *urb)
 
        skb = dev_alloc_skb(RTL8187_MAX_RX);
        if (unlikely(!skb)) {
-               usb_free_urb(urb);
                /* TODO check rx queue length and refill *somewhere* */
                return;
        }
@@ -388,24 +375,32 @@ static void rtl8187_rx_cb(struct urb *urb)
        urb->context = skb;
        skb_queue_tail(&priv->rx_queue, skb);
 
-       usb_submit_urb(urb, GFP_ATOMIC);
+       usb_anchor_urb(urb, &priv->anchored);
+       if (usb_submit_urb(urb, GFP_ATOMIC)) {
+               usb_unanchor_urb(urb);
+               skb_unlink(skb, &priv->rx_queue);
+               dev_kfree_skb_irq(skb);
+       }
 }
 
 static int rtl8187_init_urbs(struct ieee80211_hw *dev)
 {
        struct rtl8187_priv *priv = dev->priv;
-       struct urb *entry;
+       struct urb *entry = NULL;
        struct sk_buff *skb;
        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)
-                       break;
+               if (!skb) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
                entry = usb_alloc_urb(0, GFP_KERNEL);
                if (!entry) {
-                       kfree_skb(skb);
-                       break;
+                       ret = -ENOMEM;
+                       goto err;
                }
                usb_fill_bulk_urb(entry, priv->udev,
                                  usb_rcvbulkpipe(priv->udev,
@@ -416,10 +411,22 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev)
                info->urb = entry;
                info->dev = dev;
                skb_queue_tail(&priv->rx_queue, skb);
-               usb_submit_urb(entry, GFP_KERNEL);
+               usb_anchor_urb(entry, &priv->anchored);
+               ret = usb_submit_urb(entry, GFP_KERNEL);
+               if (ret) {
+                       skb_unlink(skb, &priv->rx_queue);
+                       usb_unanchor_urb(entry);
+                       goto err;
+               }
+               usb_free_urb(entry);
        }
+       return ret;
 
-       return 0;
+err:
+       usb_free_urb(entry);
+       kfree_skb(skb);
+       usb_kill_anchored_urbs(&priv->anchored);
+       return ret;
 }
 
 static void rtl8187b_status_cb(struct urb *urb)
@@ -429,10 +436,8 @@ static void rtl8187b_status_cb(struct urb *urb)
        u64 val;
        unsigned int cmd_type;
 
-       if (unlikely(urb->status)) {
-               usb_free_urb(urb);
+       if (unlikely(urb->status))
                return;
-       }
 
        /*
         * Read from status buffer:
@@ -503,26 +508,32 @@ static void rtl8187b_status_cb(struct urb *urb)
                spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags);
        }
 
-       usb_submit_urb(urb, GFP_ATOMIC);
+       usb_anchor_urb(urb, &priv->anchored);
+       if (usb_submit_urb(urb, GFP_ATOMIC))
+               usb_unanchor_urb(urb);
 }
 
 static int rtl8187b_init_status_urb(struct ieee80211_hw *dev)
 {
        struct rtl8187_priv *priv = dev->priv;
        struct urb *entry;
+       int ret = 0;
 
        entry = usb_alloc_urb(0, GFP_KERNEL);
        if (!entry)
                return -ENOMEM;
-       priv->b_tx_status.urb = entry;
 
        usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, 9),
                          &priv->b_tx_status.buf, sizeof(priv->b_tx_status.buf),
                          rtl8187b_status_cb, dev);
 
-       usb_submit_urb(entry, GFP_KERNEL);
+       usb_anchor_urb(entry, &priv->anchored);
+       ret = usb_submit_urb(entry, GFP_KERNEL);
+       if (ret)
+               usb_unanchor_urb(entry);
+       usb_free_urb(entry);
 
-       return 0;
+       return ret;
 }
 
 static int rtl8187_cmd_reset(struct ieee80211_hw *dev)
@@ -856,6 +867,9 @@ static int rtl8187_start(struct ieee80211_hw *dev)
                return ret;
 
        mutex_lock(&priv->conf_mutex);
+
+       init_usb_anchor(&priv->anchored);
+
        if (priv->is_rtl8187b) {
                reg = RTL818X_RX_CONF_MGMT |
                      RTL818X_RX_CONF_DATA |
@@ -930,7 +944,6 @@ static int rtl8187_start(struct ieee80211_hw *dev)
 static void rtl8187_stop(struct ieee80211_hw *dev)
 {
        struct rtl8187_priv *priv = dev->priv;
-       struct rtl8187_rx_info *info;
        struct sk_buff *skb;
        u32 reg;
 
@@ -949,14 +962,10 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
        rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
-       while ((skb = skb_dequeue(&priv->rx_queue))) {
-               info = (struct rtl8187_rx_info *)skb->cb;
-               usb_kill_urb(info->urb);
-               kfree_skb(skb);
-       }
        while ((skb = skb_dequeue(&priv->b_tx_status.queue)))
                dev_kfree_skb_any(skb);
-       usb_kill_urb(priv->b_tx_status.urb);
+
+       usb_kill_anchored_urbs(&priv->anchored);
        mutex_unlock(&priv->conf_mutex);
 }
 
@@ -965,19 +974,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);
@@ -986,8 +997,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,
@@ -1293,6 +1305,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
 
        priv->mode = NL80211_IFTYPE_MONITOR;
        dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+                    IEEE80211_HW_SIGNAL_DBM |
                     IEEE80211_HW_RX_INCLUDES_FCS;
 
        eeprom.data = dev;
@@ -1408,13 +1421,8 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
                (*channel++).hw_value = txpwr >> 8;
        }
 
-       if (priv->is_rtl8187b) {
+       if (priv->is_rtl8187b)
                printk(KERN_WARNING "rtl8187: 8187B chip detected.\n");
-               dev->flags |= IEEE80211_HW_SIGNAL_DBM;
-       } else {
-               dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
-               dev->max_signal = 65;
-       }
 
        /*
         * XXX: Once this driver supports anything that requires
@@ -1467,6 +1475,7 @@ static void __devexit rtl8187_disconnect(struct usb_interface *intf)
        ieee80211_unregister_hw(dev);
 
        priv = dev->priv;
+       usb_reset_device(priv->udev);
        usb_put_dev(interface_to_usbdev(intf));
        ieee80211_free_hw(dev);
 }