ChangeSet 1.1557.49.23, 2004/02/18 13:17:29-08:00, david-b@pacbell.net

[PATCH] USB: ehci-hcd, fullspeed iso data structures (2/3)

[USB] ehci, rename some iso data structures

Rename some data and functions used by EHCI to manage ISO transactions,
since they currently assume only high speed transfers.  Much of the same
infrastructure will be used for full speed ISO, with split transactions.


 drivers/usb/host/ehci-sched.c |  136 +++++++++++++++++++++---------------------
 drivers/usb/host/ehci.h       |   25 ++++---
 2 files changed, 84 insertions(+), 77 deletions(-)


diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
--- a/drivers/usb/host/ehci-sched.c	Thu Feb 19 17:21:12 2004
+++ b/drivers/usb/host/ehci-sched.c	Thu Feb 19 17:21:12 2004
@@ -491,7 +491,9 @@
 
 /*-------------------------------------------------------------------------*/
 
-static inline struct ehci_iso_stream *
+/* ehci_iso_stream ops work with both ITD and SITD */
+
+static struct ehci_iso_stream *
 iso_stream_alloc (int mem_flags)
 {
 	struct ehci_iso_stream *stream;
@@ -499,15 +501,15 @@
 	stream = kmalloc(sizeof *stream, mem_flags);
 	if (likely (stream != 0)) {
 		memset (stream, 0, sizeof(*stream));
-		INIT_LIST_HEAD(&stream->itd_list);
-		INIT_LIST_HEAD(&stream->free_itd_list);
+		INIT_LIST_HEAD(&stream->td_list);
+		INIT_LIST_HEAD(&stream->free_list);
 		stream->next_uframe = -1;
 		stream->refcount = 1;
 	}
 	return stream;
 }
 
-static inline void
+static void
 iso_stream_init (
 	struct ehci_iso_stream	*stream,
 	struct usb_device	*dev,
@@ -534,12 +536,14 @@
 		buf1 = 0;
 	}
 
+	stream->highspeed = 1;
+
 	multi = hb_mult(maxp);
 	maxp = max_packet(maxp);
 	buf1 |= maxp;
 	maxp *= multi;
 
-	stream->dev = (struct hcd_dev *)dev->hcpriv;
+	stream->udev = dev;
 
 	stream->bEndpointAddress = is_input | epnum;
 	stream->interval = interval;
@@ -567,14 +571,15 @@
 	 * not like a QH -- no persistent state (toggle, halt)
 	 */
 	if (stream->refcount == 1) {
-		int is_in;
+		int		is_in;
+		struct hcd_dev	*dev = stream->udev->hcpriv;
 
-		// BUG_ON (!list_empty(&stream->itd_list));
+		// BUG_ON (!list_empty(&stream->td_list));
 
-		while (!list_empty (&stream->free_itd_list)) {
+		while (!list_empty (&stream->free_list)) {
 			struct ehci_itd	*itd;
 
-			itd = list_entry (stream->free_itd_list.next,
+			itd = list_entry (stream->free_list.next,
 				struct ehci_itd, itd_list);
 			list_del (&itd->itd_list);
 			dma_pool_free (ehci->itd_pool, itd, itd->itd_dma);
@@ -582,7 +587,7 @@
 
 		is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0;
 		stream->bEndpointAddress &= 0x0f;
-		stream->dev->ep [is_in + stream->bEndpointAddress] = 0;
+		dev->ep [is_in + stream->bEndpointAddress] = 0;
 
 		if (stream->rescheduled) {
 			ehci_info (ehci, "ep%d%s-iso rescheduled "
@@ -648,24 +653,26 @@
 
 /*-------------------------------------------------------------------------*/
 
-static inline struct ehci_itd_sched *
-itd_sched_alloc (unsigned packets, int mem_flags)
+/* ehci_iso_sched ops can be shared, ITD-only, or SITD-only */
+
+static struct ehci_iso_sched *
+iso_sched_alloc (unsigned packets, int mem_flags)
 {
-	struct ehci_itd_sched	*itd_sched;
-	int			size = sizeof *itd_sched;
+	struct ehci_iso_sched	*iso_sched;
+	int			size = sizeof *iso_sched;
 
-	size += packets * sizeof (struct ehci_iso_uframe);
-	itd_sched = kmalloc (size, mem_flags);
-	if (likely (itd_sched != 0)) {
-		memset(itd_sched, 0, size);
-		INIT_LIST_HEAD (&itd_sched->itd_list);
+	size += packets * sizeof (struct ehci_iso_packet);
+	iso_sched = kmalloc (size, mem_flags);
+	if (likely (iso_sched != 0)) {
+		memset(iso_sched, 0, size);
+		INIT_LIST_HEAD (&iso_sched->td_list);
 	}
-	return itd_sched;
+	return iso_sched;
 }
 
-static int
+static inline void
 itd_sched_init (
-	struct ehci_itd_sched	*itd_sched,
+	struct ehci_iso_sched	*iso_sched,
 	struct ehci_iso_stream	*stream,
 	struct urb		*urb
 )
@@ -674,13 +681,13 @@
 	dma_addr_t	dma = urb->transfer_dma;
 
 	/* how many uframes are needed for these transfers */
-	itd_sched->span = urb->number_of_packets * stream->interval;
+	iso_sched->span = urb->number_of_packets * stream->interval;
 
 	/* figure out per-uframe itd fields that we'll need later
 	 * when we fit new itds into the schedule.
 	 */
 	for (i = 0; i < urb->number_of_packets; i++) {
-		struct ehci_iso_uframe	*uframe = &itd_sched->packet [i];
+		struct ehci_iso_packet	*uframe = &iso_sched->packet [i];
 		unsigned		length;
 		dma_addr_t		buf;
 		u32			trans;
@@ -702,17 +709,19 @@
 		if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff))))
 			uframe->cross = 1;
 	}
-	return 0;
 }
 
 static void
-itd_sched_free (
+iso_sched_free (
 	struct ehci_iso_stream	*stream,
-	struct ehci_itd_sched	*itd_sched
+	struct ehci_iso_sched	*iso_sched
 )
 {
-	list_splice (&itd_sched->itd_list, &stream->free_itd_list);
-	kfree (itd_sched);
+	if (!iso_sched)
+		return;
+	// caller must hold ehci->lock!
+	list_splice (&iso_sched->td_list, &stream->free_list);
+	kfree (iso_sched);
 }
 
 static int
@@ -724,37 +733,32 @@
 )
 {
 	struct ehci_itd		*itd;
-	int			status;
 	dma_addr_t		itd_dma;
 	int			i;
 	unsigned		num_itds;
-	struct ehci_itd_sched	*itd_sched;
+	struct ehci_iso_sched	*sched;
 
-	itd_sched = itd_sched_alloc (urb->number_of_packets, mem_flags);
-	if (unlikely (itd_sched == 0))
+	sched = iso_sched_alloc (urb->number_of_packets, mem_flags);
+	if (unlikely (sched == 0))
 		return -ENOMEM;
 
-	status = itd_sched_init (itd_sched, stream, urb);
-	if (unlikely (status != 0))  {
-		itd_sched_free (stream, itd_sched);
-		return status;
-	}
+	itd_sched_init (sched, stream, urb);
 
 	if (urb->interval < 8)
-		num_itds = 1 + (itd_sched->span + 7) / 8;
+		num_itds = 1 + (sched->span + 7) / 8;
 	else
 		num_itds = urb->number_of_packets;
 
 	/* allocate/init ITDs */
 	for (i = 0; i < num_itds; i++) {
 
-		/* free_itd_list.next might be cache-hot ... but maybe
+		/* free_list.next might be cache-hot ... but maybe
 		 * the HC caches it too. avoid that issue for now.
 		 */
 
 		/* prefer previously-allocated itds */
-		if (likely (!list_empty(&stream->free_itd_list))) {
-			itd = list_entry (stream->free_itd_list.prev,
+		if (likely (!list_empty(&stream->free_list))) {
+			itd = list_entry (stream->free_list.prev,
 					 struct ehci_itd, itd_list);
 			list_del (&itd->itd_list);
 			itd_dma = itd->itd_dma;
@@ -763,16 +767,16 @@
 					&itd_dma);
 
 		if (unlikely (0 == itd)) {
-			itd_sched_free (stream, itd_sched);
+			iso_sched_free (stream, sched);
 			return -ENOMEM;
 		}
 		memset (itd, 0, sizeof *itd);
 		itd->itd_dma = itd_dma;
-		list_add (&itd->itd_list, &itd_sched->itd_list);
+		list_add (&itd->itd_list, &sched->td_list);
 	}
 
 	/* temporarily store schedule info in hcpriv */
-	urb->hcpriv = itd_sched;
+	urb->hcpriv = sched;
 	urb->error_count = 0;
 	return 0;
 }
@@ -800,9 +804,9 @@
 	u32			now, start, end, max;
 	int			status;
 	unsigned		mod = ehci->periodic_size << 3;
-	struct ehci_itd_sched	*itd_sched = urb->hcpriv;
+	struct ehci_iso_sched	*sched = urb->hcpriv;
 
-	if (unlikely (itd_sched->span > (mod - 8 * SCHEDULE_SLOP))) {
+	if (unlikely (sched->span > (mod - 8 * SCHEDULE_SLOP))) {
 		ehci_dbg (ehci, "iso request %p too long\n", urb);
 		status = -EFBIG;
 		goto fail;
@@ -812,13 +816,13 @@
 
 	/* when's the last uframe this urb could start? */
 	max = now + mod;
-	max -= itd_sched->span;
+	max -= sched->span;
 	max -= 8 * SCHEDULE_SLOP;
 
 	/* typical case: reuse current schedule. stream is still active,
 	 * and no gaps from host falling behind (irq delays etc)
 	 */
-	if (likely (!list_empty (&stream->itd_list))) {
+	if (likely (!list_empty (&stream->td_list))) {
 
 		start = stream->next_uframe;
 		if (start < now)
@@ -852,7 +856,7 @@
 		max = start + urb->interval;
 
 	/* hack:  account for itds already scheduled to this endpoint */
-	if (unlikely (list_empty (&stream->itd_list)))
+	if (unlikely (list_empty (&stream->td_list)))
 		end = max;
 
 	/* within [start..max] find a uframe slot with enough bandwidth */
@@ -880,7 +884,7 @@
 		/* (re)schedule it here if there's enough bandwidth */
 		if (enough_space) {
 			start %= mod;
-			if (unlikely (!list_empty (&stream->itd_list))) {
+			if (unlikely (!list_empty (&stream->td_list))) {
 				/* host fell behind ... maybe irq latencies
 				 * delayed this request queue for too long.
 				 */
@@ -902,12 +906,12 @@
 
 	/* no room in the schedule */
 	ehci_dbg (ehci, "iso %ssched full %p (now %d end %d max %d)\n",
-		list_empty (&stream->itd_list) ? "" : "re",
+		list_empty (&stream->td_list) ? "" : "re",
 		urb, now, end, max);
 	status = -ENOSPC;
 
 fail:
-	itd_sched_free (stream, itd_sched);
+	iso_sched_free (stream, sched);
 	urb->hcpriv = 0;
 	return status;
 
@@ -937,13 +941,13 @@
 static inline void
 itd_patch (
 	struct ehci_itd		*itd,
-	struct ehci_itd_sched	*itd_sched,
+	struct ehci_iso_sched	*iso_sched,
 	unsigned		index,
 	u16			uframe,
 	int			first
 )
 {
-	struct ehci_iso_uframe	*uf = &itd_sched->packet [index];
+	struct ehci_iso_packet	*uf = &iso_sched->packet [index];
 	unsigned		pg = itd->pg;
 
 	// BUG_ON (pg == 6 && uf->cross);
@@ -988,12 +992,12 @@
 {
 	int			packet, first = 1;
 	unsigned		next_uframe, uframe, frame;
-	struct ehci_itd_sched	*itd_sched = urb->hcpriv;
+	struct ehci_iso_sched	*iso_sched = urb->hcpriv;
 	struct ehci_itd		*itd;
 
 	next_uframe = stream->next_uframe % mod;
 
-	if (unlikely (list_empty(&stream->itd_list))) {
+	if (unlikely (list_empty(&stream->td_list))) {
 		hcd_to_bus (&ehci->hcd)->bandwidth_allocated
 				+= stream->bandwidth;
 		ehci_vdbg (ehci,
@@ -1010,13 +1014,13 @@
 	for (packet = 0, itd = 0; packet < urb->number_of_packets; ) {
 		if (itd == 0) {
 			/* ASSERT:  we have all necessary itds */
-			// BUG_ON (list_empty (&itd_sched->itd_list));
+			// BUG_ON (list_empty (&iso_sched->td_list));
 
 			/* ASSERT:  no itds for this endpoint in this uframe */
 
-			itd = list_entry (itd_sched->itd_list.next,
+			itd = list_entry (iso_sched->td_list.next,
 					struct ehci_itd, itd_list);
-			list_move_tail (&itd->itd_list, &stream->itd_list);
+			list_move_tail (&itd->itd_list, &stream->td_list);
 			itd->stream = iso_stream_get (stream);
 			itd->urb = usb_get_urb (urb);
 			first = 1;
@@ -1027,7 +1031,7 @@
 		frame = next_uframe >> 3;
 
 		itd->usecs [uframe] = stream->usecs;
-		itd_patch (itd, itd_sched, packet, uframe, first);
+		itd_patch (itd, iso_sched, packet, uframe, first);
 		first = 0;
 
 		next_uframe += stream->interval;
@@ -1044,7 +1048,7 @@
 	stream->next_uframe = next_uframe;
 
 	/* don't need that schedule data any more */
-	itd_sched_free (stream, itd_sched);
+	iso_sched_free (stream, iso_sched);
 	urb->hcpriv = 0;
 
 	if (unlikely (!ehci->periodic_sched++))
@@ -1102,7 +1106,7 @@
 	usb_put_urb (urb);
 	itd->urb = 0;
 	itd->stream = 0;
-	list_move (&itd->itd_list, &stream->free_itd_list);
+	list_move (&itd->itd_list, &stream->free_list);
 	iso_stream_put (ehci, stream);
 
 	/* handle completion now? */
@@ -1110,7 +1114,7 @@
 		return 0;
 
 	/* ASSERT: it's really the last itd for this urb
-	list_for_each_entry (itd, &stream->itd_list, itd_list)
+	list_for_each_entry (itd, &stream->td_list, itd_list)
 		BUG_ON (itd->urb == urb);
 	 */
 
@@ -1125,7 +1129,7 @@
 		(void) disable_periodic (ehci);
 	hcd_to_bus (&ehci->hcd)->bandwidth_isoc_reqs--;
 
-	if (unlikely (list_empty (&stream->itd_list))) {
+	if (unlikely (list_empty (&stream->td_list))) {
 		hcd_to_bus (&ehci->hcd)->bandwidth_allocated
 				-= stream->bandwidth;
 		ehci_vdbg (ehci,
@@ -1278,7 +1282,7 @@
 				rmb ();
 				for (uf = uframes; uf < 8; uf++) {
 					if (0 == (q.itd->hw_transaction [uf]
-							& ISO_ACTIVE))
+							& ITD_ACTIVE))
 						continue;
 					q_p = &q.itd->itd_next;
 					hw_p = &q.itd->hw_next;
diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h	Thu Feb 19 17:21:12 2004
+++ b/drivers/usb/host/ehci.h	Thu Feb 19 17:21:12 2004
@@ -386,22 +386,24 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* description of one iso highspeed transaction (up to 3 KB data) */
-struct ehci_iso_uframe {
+/* description of one iso transaction (up to 3 KB data if highspeed) */
+struct ehci_iso_packet {
 	/* These will be copied to iTD when scheduling */
 	u64			bufp;		/* itd->hw_bufp{,_hi}[pg] |= */
 	u32			transaction;	/* itd->hw_transaction[i] |= */
 	u8			cross;		/* buf crosses pages */
+	/* for full speed OUT splits */
+	u16			buf1;
 };
 
-/* temporary schedule data for highspeed packets from iso urbs
- * each packet is one uframe's usb transactions, in some itd,
+/* temporary schedule data for packets from iso urbs (both speeds)
+ * each packet is one logical usb transaction to the device (not TT),
  * beginning at stream->next_uframe
  */
-struct ehci_itd_sched {
-	struct list_head	itd_list;
+struct ehci_iso_sched {
+	struct list_head	td_list;
 	unsigned		span;
-	struct ehci_iso_uframe	packet [0];
+	struct ehci_iso_packet	packet [0];
 };
 
 /*
@@ -415,9 +417,10 @@
 
 	u32			refcount;
 	u8			bEndpointAddress;
-	struct list_head	itd_list;	/* queued itds */
-	struct list_head	free_itd_list;	/* list of unused itds */
-	struct hcd_dev		*dev;
+	u8			highspeed;
+	struct list_head	td_list;	/* queued itds/sitds */
+	struct list_head	free_list;	/* list of unused itds/sitds */
+	struct usb_device	*udev;
 
 	/* output of (re)scheduling */
 	unsigned long		start;		/* jiffies */
@@ -460,7 +463,7 @@
 #define	EHCI_ITD_LENGTH(tok)	(((tok)>>16) & 0x0fff)
 #define	EHCI_ITD_IOC		(1 << 15)	/* interrupt on complete */
 
-#define ISO_ACTIVE	__constant_cpu_to_le32(EHCI_ISOC_ACTIVE)
+#define ITD_ACTIVE	__constant_cpu_to_le32(EHCI_ISOC_ACTIVE)
 
 	u32			hw_bufp [7];	/* see EHCI 3.3.3 */ 
 	u32			hw_bufp_hi [7];	/* Appendix B */
