usb/isp1760: Clean up urb enqueueing
authorArvid Brodin <arvid.brodin@enea.com>
Tue, 26 Apr 2011 19:47:37 +0000 (21:47 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 3 May 2011 00:02:54 +0000 (17:02 -0700)
This collects urb enqueue code that was spread out all over the place
into a couple of more readable functions.

Signed-off-by: Arvid Brodin <arvid.brodin@enea.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/host/isp1760-hcd.c

index ff3b3165d19d5094cc82129d58ef5d703f87963b..6b2bf4684f45436caa95d7c16afe49fbeb2a6ff8 100644 (file)
@@ -272,7 +272,7 @@ static void init_memory(struct isp1760_hcd *priv)
                payload_addr += priv->memory_pool[curr + i].size;
        }
 
-       BUG_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE);
+       WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE);
 }
 
 static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
@@ -280,7 +280,7 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
        struct isp1760_hcd *priv = hcd_to_priv(hcd);
        int i;
 
-       BUG_ON(qtd->payload_addr);
+       WARN_ON(qtd->payload_addr);
 
        if (!qtd->length)
                return;
@@ -318,7 +318,7 @@ static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
 
        for (i = 0; i < BLOCKS; i++) {
                if (priv->memory_pool[i].start == qtd->payload_addr) {
-                       BUG_ON(priv->memory_pool[i].free);
+                       WARN_ON(priv->memory_pool[i].free);
                        priv->memory_pool[i].free = 1;
                        qtd->payload_addr = 0;
                        return;
@@ -379,7 +379,7 @@ static int ehci_reset(struct usb_hcd *hcd)
 
 static void qh_destroy(struct isp1760_qh *qh)
 {
-       BUG_ON(!list_empty(&qh->qtd_list));
+       WARN_ON(!list_empty(&qh->qtd_list));
        kmem_cache_free(qh_cachep, qh);
 }
 
@@ -738,23 +738,6 @@ static void transform_into_int(struct isp1760_qh *qh,
        transform_add_int(qh, qtd, ptd);
 }
 
-static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len,
-               u32 token)
-{
-       int count;
-
-       qtd->data_buffer = databuffer;
-       qtd->packet_type = GET_QTD_TOKEN_TYPE(token);
-
-       if (len > MAX_PAYLOAD_SIZE)
-               count = MAX_PAYLOAD_SIZE;
-       else
-               count = len;
-
-       qtd->length = count;
-       return count;
-}
-
 static int check_error(struct usb_hcd *hcd, struct ptd *ptd)
 {
        int error = 0;
@@ -948,9 +931,25 @@ __acquires(priv->lock)
        spin_lock(&priv->lock);
 }
 
-static void isp1760_qtd_free(struct isp1760_qtd *qtd)
+static struct isp1760_qtd *qtd_alloc(gfp_t flags, struct urb *urb,
+                                                               u8 packet_type)
+{
+       struct isp1760_qtd *qtd;
+
+       qtd = kmem_cache_zalloc(qtd_cachep, flags);
+       if (!qtd)
+               return NULL;
+
+       INIT_LIST_HEAD(&qtd->qtd_list);
+       qtd->urb = urb;
+       qtd->packet_type = packet_type;
+
+       return qtd;
+}
+
+static void qtd_free(struct isp1760_qtd *qtd)
 {
-       BUG_ON(qtd->payload_addr);
+       WARN_ON(qtd->payload_addr);
        kmem_cache_free(qtd_cachep, qtd);
 }
 
@@ -965,7 +964,7 @@ static struct isp1760_qtd *clean_this_qtd(struct isp1760_qtd *qtd,
                tmp_qtd = list_entry(qtd->qtd_list.next, struct isp1760_qtd,
                                                                qtd_list);
        list_del(&qtd->qtd_list);
-       isp1760_qtd_free(qtd);
+       qtd_free(qtd);
        return tmp_qtd;
 }
 
@@ -1294,210 +1293,95 @@ static void do_intl_int(struct usb_hcd *hcd)
        }
 }
 
-static struct isp1760_qh *qh_make(struct usb_hcd *hcd, struct urb *urb,
-               gfp_t flags)
-{
-       struct isp1760_qh *qh;
-       int is_input, type;
-
-       qh = isp1760_qh_alloc(flags);
-       if (!qh)
-               return qh;
-
-       /*
-        * init endpoint/device data for this QH
-        */
-       is_input = usb_pipein(urb->pipe);
-       type = usb_pipetype(urb->pipe);
-
-       if (!usb_pipecontrol(urb->pipe))
-               usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input,
-                               1);
-       return qh;
-}
-
-/*
- * For control/bulk/interrupt, return QH with these TDs appended.
- * Allocates and initializes the QH if necessary.
- * Returns null if it can't allocate a QH it needs to.
- * If the QH has TDs (urbs) already, that's great.
- */
-static struct isp1760_qh *qh_append_tds(struct usb_hcd *hcd,
-               struct urb *urb, struct list_head *qtd_list, int epnum,
-               void **ptr)
+static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
 {
-       struct isp1760_qh *qh;
-
-       qh = (struct isp1760_qh *)*ptr;
-       if (!qh) {
-               /* can't sleep here, we have priv->lock... */
-               qh = qh_make(hcd, urb, GFP_ATOMIC);
-               if (!qh)
-                       return qh;
-               *ptr = qh;
-       }
+       qtd->data_buffer = databuffer;
 
-       list_splice(qtd_list, qh->qtd_list.prev);
+       if (len > MAX_PAYLOAD_SIZE)
+               len = MAX_PAYLOAD_SIZE;
+       qtd->length = len;
 
-       return qh;
+       return qtd->length;
 }
 
-static void qtd_list_free(struct urb *urb, struct list_head *qtd_list)
+static void qtd_list_free(struct list_head *qtd_list)
 {
-       struct list_head *entry, *temp;
+       struct isp1760_qtd *qtd, *qtd_next;
 
-       list_for_each_safe(entry, temp, qtd_list) {
-               struct isp1760_qtd      *qtd;
-
-               qtd = list_entry(entry, struct isp1760_qtd, qtd_list);
+       list_for_each_entry_safe(qtd, qtd_next, qtd_list, qtd_list) {
                list_del(&qtd->qtd_list);
-               isp1760_qtd_free(qtd);
+               qtd_free(qtd);
        }
 }
 
-static int isp1760_prepare_enqueue(struct usb_hcd *hcd, struct urb *urb,
-               struct list_head *qtd_list, gfp_t mem_flags, packet_enqueue *p)
-{
-       struct isp1760_hcd *priv = hcd_to_priv(hcd);
-       struct isp1760_qtd         *qtd;
-       int                     epnum;
-       unsigned long           flags;
-       struct isp1760_qh          *qh = NULL;
-       int                     rc;
-       int qh_busy;
-
-       qtd = list_entry(qtd_list->next, struct isp1760_qtd, qtd_list);
-       epnum = urb->ep->desc.bEndpointAddress;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       if (!HCD_HW_ACCESSIBLE(hcd)) {
-               rc = -ESHUTDOWN;
-               goto done;
-       }
-       rc = usb_hcd_link_urb_to_ep(hcd, urb);
-       if (rc)
-               goto done;
-
-       qh = urb->ep->hcpriv;
-       if (qh)
-               qh_busy = !list_empty(&qh->qtd_list);
-       else
-               qh_busy = 0;
-
-       qh = qh_append_tds(hcd, urb, qtd_list, epnum, &urb->ep->hcpriv);
-       if (!qh) {
-               usb_hcd_unlink_urb_from_ep(hcd, urb);
-               rc = -ENOMEM;
-               goto done;
-       }
-
-       if (!qh_busy)
-               p(hcd, qh, qtd);
-
-done:
-       spin_unlock_irqrestore(&priv->lock, flags);
-       if (!qh)
-               qtd_list_free(urb, qtd_list);
-       return rc;
-}
-
-static struct isp1760_qtd *isp1760_qtd_alloc(gfp_t flags)
-{
-       struct isp1760_qtd *qtd;
-
-       qtd = kmem_cache_zalloc(qtd_cachep, flags);
-       if (qtd)
-               INIT_LIST_HEAD(&qtd->qtd_list);
-
-       return qtd;
-}
-
 /*
- * create a list of filled qtds for this URB; won't link into qh.
+ * Packetize urb->transfer_buffer into list of packets of size wMaxPacketSize.
+ * Also calculate the PID type (SETUP/IN/OUT) for each packet.
  */
 #define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
-static struct list_head *qh_urb_transaction(struct usb_hcd *hcd,
+static void packetize_urb(struct usb_hcd *hcd,
                struct urb *urb, struct list_head *head, gfp_t flags)
 {
        struct isp1760_qtd *qtd;
        void *buf;
-       int len, maxpacket;
-       int is_input;
-       u32 token;
+       int len, maxpacketsize;
+       u8 packet_type;
 
        /*
         * URBs map to sequences of QTDs:  one logical transaction
         */
-       qtd = isp1760_qtd_alloc(flags);
-       if (!qtd)
-               return NULL;
 
-       list_add_tail(&qtd->qtd_list, head);
-       qtd->urb = urb;
-       urb->status = -EINPROGRESS;
+       if (!urb->transfer_buffer && urb->transfer_buffer_length) {
+               /* XXX This looks like usb storage / SCSI bug */
+               dev_err(hcd->self.controller,
+                               "buf is null, dma is %08lx len is %d\n",
+                               (long unsigned)urb->transfer_dma,
+                               urb->transfer_buffer_length);
+               WARN_ON(1);
+       }
 
-       token = 0;
-       /* for split transactions, SplitXState initialized to zero */
+       if (usb_pipein(urb->pipe))
+               packet_type = IN_PID;
+       else
+               packet_type = OUT_PID;
 
-       len = urb->transfer_buffer_length;
-       is_input = usb_pipein(urb->pipe);
        if (usb_pipecontrol(urb->pipe)) {
-               /* SETUP pid */
-               qtd_fill(qtd, urb->setup_packet,
-                               sizeof(struct usb_ctrlrequest),
-                               token | SETUP_PID);
-
-               /* ... and always at least one more pid */
-               qtd = isp1760_qtd_alloc(flags);
+               qtd = qtd_alloc(flags, urb, SETUP_PID);
                if (!qtd)
                        goto cleanup;
-               qtd->urb = urb;
+               qtd_fill(qtd, urb->setup_packet, sizeof(struct usb_ctrlrequest));
                list_add_tail(&qtd->qtd_list, head);
 
                /* for zero length DATA stages, STATUS is always IN */
-               if (len == 0)
-                       token |= IN_PID;
+               if (urb->transfer_buffer_length == 0)
+                       packet_type = IN_PID;
        }
 
-       /*
-        * data transfer stage:  buffer setup
-        */
-       buf = urb->transfer_buffer;
-
-       if (is_input)
-               token |= IN_PID;
-       else
-               token |= OUT_PID;
-
-       maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
+       maxpacketsize = max_packet(usb_maxpacket(urb->dev, urb->pipe,
+                                               usb_pipeout(urb->pipe)));
 
        /*
         * buffer gets wrapped in one or more qtds;
         * last one may be "short" (including zero len)
         * and may serve as a control status ack
         */
+       buf = urb->transfer_buffer;
+       len = urb->transfer_buffer_length;
+
        for (;;) {
                int this_qtd_len;
 
-               if (!buf && len) {
-                       /* XXX This looks like usb storage / SCSI bug */
-                       dev_err(hcd->self.controller, "buf is null, dma is %08lx len is %d\n",
-                                       (long unsigned)urb->transfer_dma, len);
-                       WARN_ON(1);
-               }
+               qtd = qtd_alloc(flags, urb, packet_type);
+               if (!qtd)
+                       goto cleanup;
+               this_qtd_len = qtd_fill(qtd, buf, len);
+               list_add_tail(&qtd->qtd_list, head);
 
-               this_qtd_len = qtd_fill(qtd, buf, len, token);
                len -= this_qtd_len;
                buf += this_qtd_len;
 
                if (len <= 0)
                        break;
-
-               qtd = isp1760_qtd_alloc(flags);
-               if (!qtd)
-                       goto cleanup;
-               qtd->urb = urb;
-               list_add_tail(&qtd->qtd_list, head);
        }
 
        /*
@@ -1509,31 +1393,78 @@ static struct list_head *qh_urb_transaction(struct usb_hcd *hcd,
 
                if (usb_pipecontrol(urb->pipe)) {
                        one_more = 1;
-                       /* "in" <--> "out"  */
-                       token ^= IN_PID;
+                       if (packet_type == IN_PID)
+                               packet_type = OUT_PID;
+                       else
+                               packet_type = IN_PID;
                } else if (usb_pipebulk(urb->pipe)
                                && (urb->transfer_flags & URB_ZERO_PACKET)
-                               && !(urb->transfer_buffer_length % maxpacket)) {
+                               && !(urb->transfer_buffer_length %
+                                                       maxpacketsize)) {
                        one_more = 1;
                }
                if (one_more) {
-                       qtd = isp1760_qtd_alloc(flags);
+                       qtd = qtd_alloc(flags, urb, packet_type);
                        if (!qtd)
                                goto cleanup;
-                       qtd->urb = urb;
-                       list_add_tail(&qtd->qtd_list, head);
 
                        /* never any data in such packets */
-                       qtd_fill(qtd, NULL, 0, token);
+                       qtd_fill(qtd, NULL, 0);
+                       list_add_tail(&qtd->qtd_list, head);
                }
        }
 
-       qtd->status = 0;
-       return head;
+       return;
 
 cleanup:
-       qtd_list_free(urb, head);
-       return NULL;
+       qtd_list_free(head);
+}
+
+static int enqueue_qtdlist(struct usb_hcd *hcd, struct urb *urb,
+               struct list_head *qtd_list, gfp_t mem_flags, packet_enqueue *p)
+{
+       struct isp1760_hcd *priv = hcd_to_priv(hcd);
+       struct isp1760_qtd *qtd;
+       struct isp1760_qh *qh = NULL;
+       unsigned long flags;
+       int qh_empty;
+       int rc;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (!HCD_HW_ACCESSIBLE(hcd)) {
+               rc = -ESHUTDOWN;
+               goto done;
+       }
+       rc = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (rc)
+               goto done;
+
+       qh = urb->ep->hcpriv;
+       if (!qh) {
+               qh = isp1760_qh_alloc(GFP_ATOMIC);
+               if (!qh) {
+                       usb_hcd_unlink_urb_from_ep(hcd, urb);
+                       rc = -ENOMEM;
+                       goto done;
+               }
+               if (!usb_pipecontrol(urb->pipe))
+                       usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                                               !usb_pipein(urb->pipe), 1);
+               urb->ep->hcpriv = qh;
+       }
+
+       qh_empty = list_empty(&qh->qtd_list);
+       list_splice_tail(qtd_list, &qh->qtd_list);
+       if (qh_empty) {
+               qtd = list_entry(qtd_list->next, struct isp1760_qtd, qtd_list);
+               p(hcd, qh, qtd);
+       }
+
+done:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       if (!qh)
+               qtd_list_free(qtd_list);
+       return rc;
 }
 
 static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
@@ -1547,14 +1478,10 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
        switch (usb_pipetype(urb->pipe)) {
        case PIPE_CONTROL:
        case PIPE_BULK:
-               if (!qh_urb_transaction(hcd, urb, &qtd_list, mem_flags))
-                       return -ENOMEM;
-               pe =  enqueue_an_ATL_packet;
+               pe = enqueue_an_ATL_packet;
                break;
 
        case PIPE_INTERRUPT:
-               if (!qh_urb_transaction(hcd, urb, &qtd_list, mem_flags))
-                       return -ENOMEM;
                pe = enqueue_an_INT_packet;
                break;
 
@@ -1564,7 +1491,11 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                return -EPIPE;
        }
 
-       return isp1760_prepare_enqueue(hcd, urb, &qtd_list, mem_flags, pe);
+       packetize_urb(hcd, urb, &qtd_list, mem_flags);
+       if (list_empty(&qtd_list))
+               return -ENOMEM;
+
+       return enqueue_qtdlist(hcd, urb, &qtd_list, mem_flags, pe);
 }
 
 static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
@@ -1605,7 +1536,7 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
        for (i = 0; i < 32; i++) {
                if (!ints[i].qh)
                        continue;
-               BUG_ON(!ints[i].qtd);
+               WARN_ON(!ints[i].qtd);
 
                if (ints[i].qtd->urb == urb) {
                        u32 skip_map;