rt2x00: Detect USB BULK in/out endpoints
authorIvo van Doorn <ivdoorn@gmail.com>
Thu, 13 Nov 2008 22:07:33 +0000 (23:07 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 25 Nov 2008 21:41:34 +0000 (16:41 -0500)
Instead of hardcoding the used in/out endpoints
we should detect them by walking through all
available endpoints.

rt2800usb will gain the most out of this, because
the legacy drivers indicate that there are multiple
endpoints available.
However this code might benefit at least rt73usb as
well for the MIMO queues, and if we are really lucky
rt2500usb will benefit because for the TX and PRIO
queues.

Even if rt2500usb and rt73usb do not get better performance
after this patch, the endpoint detection still belongs to
rt2x00usb, and it shouldn't hurt to always try to detect
the available endpoints.

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt73usb.c

index 40eb64358821a54bd678cb96122c5ec59df2a5f4..0447e93306ad1d81b5115a919b74b05bfd1aa375 100644 (file)
@@ -1108,7 +1108,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
        struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
        struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
-       int pipe = usb_sndbulkpipe(usb_dev, 1);
+       int pipe = usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint);
        int length;
        u16 reg;
 
@@ -1134,7 +1134,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
         * length of the data to usb_fill_bulk_urb. Pass the skb
         * to the driver to determine what the length should be.
         */
-       length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
+       length = rt2x00dev->ops->lib->get_tx_data_len(entry);
 
        usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
                          entry->skb->data, length, rt2500usb_beacondone,
@@ -1156,8 +1156,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
        usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
 }
 
-static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
-                                    struct sk_buff *skb)
+static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
 {
        int length;
 
@@ -1165,8 +1164,8 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
         * The length _must_ be a multiple of 2,
         * but it must _not_ be a multiple of the USB packet size.
         */
-       length = roundup(skb->len, 2);
-       length += (2 * !(length % rt2x00dev->usb_maxpacket));
+       length = roundup(entry->skb->len, 2);
+       length += (2 * !(length % entry->queue->usb_maxpacket));
 
        return length;
 }
index fee61bee1e7e6b75d1aa2d9905bf57a5b0c65843..780ba7365810cee69b89667ecc34593280477469 100644 (file)
@@ -555,8 +555,7 @@ struct rt2x00lib_ops {
                               struct txentry_desc *txdesc);
        int (*write_tx_data) (struct queue_entry *entry);
        void (*write_beacon) (struct queue_entry *entry);
-       int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
-                               struct sk_buff *skb);
+       int (*get_tx_data_len) (struct queue_entry *entry);
        void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
                               const enum data_queue_qid queue);
 
@@ -798,11 +797,6 @@ struct rt2x00_dev {
         */
        short lna_gain;
 
-       /*
-        * USB Max frame size (for rt2500usb & rt73usb).
-        */
-       u16 usb_maxpacket;
-
        /*
         * Current TX power value.
         */
index 4d3c7246f9aed105892204164e72ac315aa8aa0e..2e99ab53ec652d14a760e55869ee8dbf98bc1c48 100644 (file)
@@ -380,6 +380,8 @@ enum queue_index {
  * @cw_max: The cw max value for outgoing frames (field ignored in RX queue).
  * @data_size: Maximum data size for the frames in this queue.
  * @desc_size: Hardware descriptor size for the data in this queue.
+ * @usb_endpoint: Device endpoint used for communication (USB only)
+ * @usb_maxpacket: Max packet size for given endpoint (USB only)
  */
 struct data_queue {
        struct rt2x00_dev *rt2x00dev;
@@ -401,6 +403,9 @@ struct data_queue {
 
        unsigned short data_size;
        unsigned short desc_size;
+
+       unsigned short usb_endpoint;
+       unsigned short usb_maxpacket;
 };
 
 /**
@@ -443,6 +448,19 @@ struct data_queue_desc {
 #define tx_queue_end(__dev) \
        &(__dev)->tx[(__dev)->ops->tx_queues]
 
+/**
+ * queue_next - Return pointer to next queue in list (HELPER MACRO).
+ * @__queue: Current queue for which we need the next queue
+ *
+ * Using the current queue address we take the address directly
+ * after the queue to take the next queue. Note that this macro
+ * should be used carefully since it does not protect against
+ * moving past the end of the list. (See macros &queue_end and
+ * &tx_queue_end for determining the end of the queue).
+ */
+#define queue_next(__queue) \
+       &(__queue)[1]
+
 /**
  * queue_loop - Loop through the queues within a specific range (HELPER MACRO).
  * @__entry: Pointer where the current queue entry will be stored in.
@@ -453,8 +471,8 @@ struct data_queue_desc {
  */
 #define queue_loop(__entry, __start, __end)                    \
        for ((__entry) = (__start);                             \
-            prefetch(&(__entry)[1]), (__entry) != (__end);     \
-            (__entry) = &(__entry)[1])
+            prefetch(queue_next(__entry)), (__entry) != (__end);\
+            (__entry) = queue_next(__entry))
 
 /**
  * queue_for_each - Loop through all queues
index 2fbf78ff6b183dda145694fcf9f4f7fc2e7de5dd..83df312ac56fe02b3b833022c8f432d674e0215e 100644 (file)
@@ -234,10 +234,10 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry)
         * length of the data to usb_fill_bulk_urb. Pass the skb
         * to the driver to determine what the length should be.
         */
-       length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
+       length = rt2x00dev->ops->lib->get_tx_data_len(entry);
 
        usb_fill_bulk_urb(entry_priv->urb, usb_dev,
-                         usb_sndbulkpipe(usb_dev, 1),
+                         usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),
                          entry->skb->data, length,
                          rt2x00usb_interrupt_txdone, entry);
 
@@ -378,10 +378,11 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
        struct usb_device *usb_dev =
            to_usb_device_intf(entry->queue->rt2x00dev->dev);
        struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+       int pipe;
 
        if (entry->queue->qid == QID_RX) {
-               usb_fill_bulk_urb(entry_priv->urb, usb_dev,
-                               usb_rcvbulkpipe(usb_dev, 1),
+               pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
+               usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
                                entry->skb->data, entry->skb->len,
                                rt2x00usb_interrupt_rxdone, entry);
 
@@ -393,6 +394,76 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
 
+static void rt2x00usb_assign_endpoint(struct data_queue *queue,
+                                     struct usb_endpoint_descriptor *ep_desc)
+{
+       struct usb_device *usb_dev = to_usb_device_intf(queue->rt2x00dev->dev);
+       int pipe;
+
+       queue->usb_endpoint = usb_endpoint_num(ep_desc);
+
+       if (queue->qid == QID_RX) {
+               pipe = usb_rcvbulkpipe(usb_dev, queue->usb_endpoint);
+               queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 0);
+       } else {
+               pipe = usb_sndbulkpipe(usb_dev, queue->usb_endpoint);
+               queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 1);
+       }
+
+       if (!queue->usb_maxpacket)
+               queue->usb_maxpacket = 1;
+}
+
+static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev)
+{
+       struct usb_interface *intf = to_usb_interface(rt2x00dev->dev);
+       struct usb_host_interface *intf_desc = intf->cur_altsetting;
+       struct usb_endpoint_descriptor *ep_desc;
+       struct data_queue *queue = rt2x00dev->tx;
+       struct usb_endpoint_descriptor *tx_ep_desc = NULL;
+       unsigned int i;
+
+       /*
+        * Walk through all available endpoints to search for "bulk in"
+        * and "bulk out" endpoints. When we find such endpoints collect
+        * the information we need from the descriptor and assign it
+        * to the queue.
+        */
+       for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) {
+               ep_desc = &intf_desc->endpoint[i].desc;
+
+               if (usb_endpoint_is_bulk_in(ep_desc)) {
+                       rt2x00usb_assign_endpoint(rt2x00dev->rx, ep_desc);
+               } else if (usb_endpoint_is_bulk_out(ep_desc)) {
+                       rt2x00usb_assign_endpoint(queue, ep_desc);
+
+                       if (queue != queue_end(rt2x00dev))
+                               queue = queue_next(queue);
+                       tx_ep_desc = ep_desc;
+               }
+       }
+
+       /*
+        * At least 1 endpoint for RX and 1 endpoint for TX must be available.
+        */
+       if (!rt2x00dev->rx->usb_endpoint || !rt2x00dev->tx->usb_endpoint) {
+               ERROR(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n");
+               return -EPIPE;
+       }
+
+       /*
+        * It might be possible not all queues have a dedicated endpoint.
+        * Loop through all TX queues and copy the endpoint information
+        * which we have gathered from already assigned endpoints.
+        */
+       txall_queue_for_each(rt2x00dev, queue) {
+               if (!queue->usb_endpoint)
+                       rt2x00usb_assign_endpoint(queue, tx_ep_desc);
+       }
+
+       return 0;
+}
+
 static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
                               struct data_queue *queue)
 {
@@ -463,6 +534,13 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
        struct data_queue *queue;
        int status;
 
+       /*
+        * Find endpoints for each queue
+        */
+       status = rt2x00usb_find_endpoints(rt2x00dev);
+       if (status)
+               goto exit;
+
        /*
         * Allocate DMA
         */
@@ -554,11 +632,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
        rt2x00dev->ops = ops;
        rt2x00dev->hw = hw;
 
-       rt2x00dev->usb_maxpacket =
-           usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1);
-       if (!rt2x00dev->usb_maxpacket)
-               rt2x00dev->usb_maxpacket = 1;
-
        retval = rt2x00usb_alloc_reg(rt2x00dev);
        if (retval)
                goto exit_free_device;
index ee59b4e35cdc2dd066a8d6aa260ea37391eaf8ff..37a782dc8080a18b23eaefeded231f7516c914b1 100644 (file)
@@ -1508,8 +1508,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
        entry->skb = NULL;
 }
 
-static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
-                                  struct sk_buff *skb)
+static int rt73usb_get_tx_data_len(struct queue_entry *entry)
 {
        int length;
 
@@ -1517,8 +1516,8 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
         * The length _must_ be a multiple of 4,
         * but it must _not_ be a multiple of the USB packet size.
         */
-       length = roundup(skb->len, 4);
-       length += (4 * !(length % rt2x00dev->usb_maxpacket));
+       length = roundup(entry->skb->len, 4);
+       length += (4 * !(length % entry->queue->usb_maxpacket));
 
        return length;
 }