[PATCH 109/205] usb/isp1760: Clean up urb enqueueing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Arvid Brodin <arvid.brodin@xxxxxxxx>

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@xxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxx>
---
 drivers/usb/host/isp1760-hcd.c |  327 ++++++++++++++++------------------------
 1 files changed, 129 insertions(+), 198 deletions(-)

diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index ff3b316..6b2bf46 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -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;
-- 
1.7.4.2

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux