patch isp116x-hcd-prepare-for-urb-status.patch added to gregkh-2.6 tree

<[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
This is a note to let you know that I've just added the patch titled

     Subject: [PATCH] isp116x-hcd: prepare for urb->status

to my gregkh-2.6 tree.  Its filename is

     isp116x-hcd-prepare-for-urb-status.patch

This tree can be found at 
    http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/


>From [email protected] Thu Jul 12 14:03:07 2007
From: Alan Stern <[email protected]>
Date: Thu, 12 Jul 2007 17:03:01 -0400 (EDT)
Subject: [PATCH] isp116x-hcd: prepare for urb->status
To: Greg KH <[email protected]>
Cc: Olav Kongas <[email protected]>,  USB development list <[email protected]>
Message-ID: <[email protected]>


This patch (as931b), adapted from a patch by Olav Kongas, makes a small
set of conservative changes to the isp116x-hcd driver in preparation
for the removal of urb->status.

	finish_request() is moved up in the source and is called
	as soon as the URB is known to have completed, rather than
	after all the active endpoints have been scanned.

	The status of a completed URB is kept in a local variable
	and copied to urb->status only when the URB is about to be
	given back.

	-EREMOTEIO error status for control transfers is set after
	the status stage rather than when the short packet arrives.

	Some unnecessary uses of urb->lock are removed.

Signed-off-by: Alan Stern <[email protected]>
Cc: Olav Kongas <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>


---
 drivers/usb/host/isp116x-hcd.c |  187 ++++++++++++++++++-----------------------
 1 file changed, 86 insertions(+), 101 deletions(-)

--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -228,7 +228,6 @@ static void preproc_atl_queue(struct isp
 				   struct urb, urb_list);
 		ptd = &ep->ptd;
 		len = ep->length;
-		spin_lock(&urb->lock);
 		ep->data = (unsigned char *)urb->transfer_buffer
 		    + urb->actual_length;
 
@@ -264,7 +263,6 @@ static void preproc_atl_queue(struct isp
 		    | PTD_EP(ep->epnum);
 		ptd->len = PTD_LEN(len) | PTD_DIR(dir);
 		ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe));
-		spin_unlock(&urb->lock);
 		if (!ep->active) {
 			ptd->mps |= PTD_LAST_MSK;
 			isp116x->atl_last_dir = dir;
@@ -275,6 +273,61 @@ static void preproc_atl_queue(struct isp
 }
 
 /*
+  Take done or failed requests out of schedule. Give back
+  processed urbs.
+*/
+static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
+			   struct urb *urb)
+__releases(isp116x->lock) __acquires(isp116x->lock)
+{
+	unsigned i;
+
+	urb->hcpriv = NULL;
+	ep->error_count = 0;
+
+	if (usb_pipecontrol(urb->pipe))
+		ep->nextpid = USB_PID_SETUP;
+
+	urb_dbg(urb, "Finish");
+
+	spin_unlock(&isp116x->lock);
+	usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
+	spin_lock(&isp116x->lock);
+
+	/* take idle endpoints out of the schedule */
+	if (!list_empty(&ep->hep->urb_list))
+		return;
+
+	/* async deschedule */
+	if (!list_empty(&ep->schedule)) {
+		list_del_init(&ep->schedule);
+		return;
+	}
+
+	/* periodic deschedule */
+	DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+	for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+		struct isp116x_ep *temp;
+		struct isp116x_ep **prev = &isp116x->periodic[i];
+
+		while (*prev && ((temp = *prev) != ep))
+			prev = &temp->next;
+		if (*prev)
+			*prev = ep->next;
+		isp116x->load[i] -= ep->load;
+	}
+	ep->branch = PERIODIC_SIZE;
+	isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
+	    ep->load / ep->period;
+
+	/* switch irq type? */
+	if (!--isp116x->periodic_count) {
+		isp116x->irqenb &= ~HCuPINT_SOF;
+		isp116x->irqenb |= HCuPINT_ATL;
+	}
+}
+
+/*
   Analyze transfer results, handle partial transfers and errors
 */
 static void postproc_atl_queue(struct isp116x *isp116x)
@@ -284,6 +337,7 @@ static void postproc_atl_queue(struct is
 	struct usb_device *udev;
 	struct ptd *ptd;
 	int short_not_ok;
+	int status;
 	u8 cc;
 
 	for (ep = isp116x->atl_active; ep; ep = ep->active) {
@@ -294,7 +348,7 @@ static void postproc_atl_queue(struct is
 		ptd = &ep->ptd;
 		cc = PTD_GET_CC(ptd);
 		short_not_ok = 1;
-		spin_lock(&urb->lock);
+		status = -EINPROGRESS;
 
 		/* Data underrun is special. For allowed underrun
 		   we clear the error and continue as normal. For
@@ -302,47 +356,36 @@ static void postproc_atl_queue(struct is
 		   immediately while for control transfer,
 		   we do a STATUS stage. */
 		if (cc == TD_DATAUNDERRUN) {
-			if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) {
-				DBG("Allowed data underrun\n");
+			if (!(urb->transfer_flags & URB_SHORT_NOT_OK) ||
+					usb_pipecontrol(urb->pipe)) {
+				DBG("Allowed or control data underrun\n");
 				cc = TD_CC_NOERROR;
 				short_not_ok = 0;
 			} else {
 				ep->error_count = 1;
-				if (usb_pipecontrol(urb->pipe))
-					ep->nextpid = USB_PID_ACK;
-				else
-					usb_settoggle(udev, ep->epnum,
-						      ep->nextpid ==
-						      USB_PID_OUT,
-						      PTD_GET_TOGGLE(ptd));
+				usb_settoggle(udev, ep->epnum,
+					      ep->nextpid == USB_PID_OUT,
+					      PTD_GET_TOGGLE(ptd));
 				urb->actual_length += PTD_GET_COUNT(ptd);
-				urb->status = cc_to_error[TD_DATAUNDERRUN];
-				spin_unlock(&urb->lock);
-				continue;
+				status = cc_to_error[TD_DATAUNDERRUN];
+				goto done;
 			}
 		}
-		/* Keep underrun error through the STATUS stage */
-		if (urb->status == cc_to_error[TD_DATAUNDERRUN])
-			cc = TD_DATAUNDERRUN;
 
 		if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED
 		    && (++ep->error_count >= 3 || cc == TD_CC_STALL
 			|| cc == TD_DATAOVERRUN)) {
-			if (urb->status == -EINPROGRESS)
-				urb->status = cc_to_error[cc];
+			status = cc_to_error[cc];
 			if (ep->nextpid == USB_PID_ACK)
 				ep->nextpid = 0;
-			spin_unlock(&urb->lock);
-			continue;
+			goto done;
 		}
 		/* According to usb spec, zero-length Int transfer signals
 		   finishing of the urb. Hey, does this apply only
 		   for IN endpoints? */
 		if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {
-			if (urb->status == -EINPROGRESS)
-				urb->status = 0;
-			spin_unlock(&urb->lock);
-			continue;
+			status = 0;
+			goto done;
 		}
 
 		/* Relax after previously failed, but later succeeded
@@ -381,8 +424,8 @@ static void postproc_atl_queue(struct is
 			/* All data for this URB is transferred, let's finish */
 			if (usb_pipecontrol(urb->pipe))
 				ep->nextpid = USB_PID_ACK;
-			else if (urb->status == -EINPROGRESS)
-				urb->status = 0;
+			else
+				status = 0;
 			break;
 		case USB_PID_SETUP:
 			if (PTD_GET_ACTIVE(ptd)
@@ -402,69 +445,27 @@ static void postproc_atl_queue(struct is
 			if (PTD_GET_ACTIVE(ptd)
 			    || (cc != TD_CC_NOERROR && cc < 0x0E))
 				break;
-			if (urb->status == -EINPROGRESS)
-				urb->status = 0;
+			if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+					urb->actual_length <
+						urb->transfer_buffer_length)
+				status = -EREMOTEIO;
+			else
+				status = 0;
 			ep->nextpid = 0;
 			break;
 		default:
 			BUG();
 		}
-		spin_unlock(&urb->lock);
-	}
-}
-
-/*
-  Take done or failed requests out of schedule. Give back
-  processed urbs.
-*/
-static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
-			   struct urb *urb)
-__releases(isp116x->lock) __acquires(isp116x->lock)
-{
-	unsigned i;
-
-	urb->hcpriv = NULL;
-	ep->error_count = 0;
-
-	if (usb_pipecontrol(urb->pipe))
-		ep->nextpid = USB_PID_SETUP;
-
-	urb_dbg(urb, "Finish");
-
-	spin_unlock(&isp116x->lock);
-	usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
-	spin_lock(&isp116x->lock);
-
-	/* take idle endpoints out of the schedule */
-	if (!list_empty(&ep->hep->urb_list))
-		return;
-
-	/* async deschedule */
-	if (!list_empty(&ep->schedule)) {
-		list_del_init(&ep->schedule);
-		return;
-	}
 
-	/* periodic deschedule */
-	DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
-	for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
-		struct isp116x_ep *temp;
-		struct isp116x_ep **prev = &isp116x->periodic[i];
-
-		while (*prev && ((temp = *prev) != ep))
-			prev = &temp->next;
-		if (*prev)
-			*prev = ep->next;
-		isp116x->load[i] -= ep->load;
-	}
-	ep->branch = PERIODIC_SIZE;
-	isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
-	    ep->load / ep->period;
-
-	/* switch irq type? */
-	if (!--isp116x->periodic_count) {
-		isp116x->irqenb &= ~HCuPINT_SOF;
-		isp116x->irqenb |= HCuPINT_ATL;
+ done:
+		if (status != -EINPROGRESS) {
+			spin_lock(&urb->lock);
+			if (urb->status == -EINPROGRESS)
+				urb->status = status;
+			spin_unlock(&urb->lock);
+		}
+		if (urb->status != -EINPROGRESS)
+			finish_request(isp116x, ep, urb);
 	}
 }
 
@@ -570,9 +571,6 @@ static void start_atl_transfers(struct i
 */
 static void finish_atl_transfers(struct isp116x *isp116x)
 {
-	struct isp116x_ep *ep;
-	struct urb *urb;
-
 	if (!isp116x->atl_active)
 		return;
 	/* Fifo not ready? */
@@ -582,16 +580,6 @@ static void finish_atl_transfers(struct 
 	atomic_inc(&isp116x->atl_finishing);
 	unpack_fifo(isp116x);
 	postproc_atl_queue(isp116x);
-	for (ep = isp116x->atl_active; ep; ep = ep->active) {
-		urb =
-		    container_of(ep->hep->urb_list.next, struct urb, urb_list);
-		/* USB_PID_ACK check here avoids finishing of
-		   control transfers, for which TD_DATAUNDERRUN
-		   occured, while URB_SHORT_NOT_OK was set */
-		if (urb && urb->status != -EINPROGRESS
-		    && ep->nextpid != USB_PID_ACK)
-			finish_request(isp116x, ep, urb);
-	}
 	atomic_dec(&isp116x->atl_finishing);
 }
 
@@ -821,15 +809,12 @@ static int isp116x_urb_enqueue(struct us
 	}
 
 	/* in case of unlink-during-submit */
-	spin_lock(&urb->lock);
 	if (urb->status != -EINPROGRESS) {
-		spin_unlock(&urb->lock);
 		finish_request(isp116x, ep, urb);
 		ret = 0;
 		goto fail;
 	}
 	urb->hcpriv = hep;
-	spin_unlock(&urb->lock);
 	start_atl_transfers(isp116x);
 
       fail:


Patches currently in gregkh-2.6 which might be from [email protected] are

driver/pm-remove-deprecated-sysfs-files.patch
driver/pm-remove-deprecated-dpm_runtime_-routines.patch
usb/usb-add-descriptors-binary-sysfs-attribute.patch
usb/usb-documentation-update-for-usb_unlink_urb.patch
usb/usb-fix-warning-caused-by-autosuspend-counter-going-negative.patch
usb/uhci-short-control-urbs-get-a-status-stage.patch
usb/isp116x-hcd-prepare-for-urb-status.patch

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.