[RFC v2 3/7] xHCI: factor out segments allocation and free function

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

 



Factor out the segments allocation and free part from ring allocation
and free routines since driver may call them directly when try to expand
a ring.

Signed-off-by: Andiry Xu <andiry.xu@xxxxxxx>
---
 drivers/usb/host/xhci-mem.c |   92 ++++++++++++++++++++++++++-----------------
 1 files changed, 56 insertions(+), 36 deletions(-)

diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 98338a7..e0d593e 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -71,6 +71,20 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
 	kfree(seg);
 }
 
+static void xhci_free_segments_for_ring(struct xhci_hcd *xhci,
+				struct xhci_segment *first)
+{
+	struct xhci_segment *seg;
+
+	seg = first->next;
+	while (seg != first) {
+		struct xhci_segment *next = seg->next;
+		xhci_segment_free(xhci, seg);
+		seg = next;
+	}
+	xhci_segment_free(xhci, first);
+}
+
 /*
  * Make the prev segment point to the next segment.
  *
@@ -109,23 +123,11 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
 /* XXX: Do we need the hcd structure in all these functions? */
 void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
 {
-	struct xhci_segment *seg;
-	struct xhci_segment *first_seg;
-
 	if (!ring)
 		return;
-	if (ring->first_seg) {
-		first_seg = ring->first_seg;
-		seg = first_seg->next;
-		xhci_dbg(xhci, "Freeing ring at %p\n", ring);
-		while (seg != first_seg) {
-			struct xhci_segment *next = seg->next;
-			xhci_segment_free(xhci, seg);
-			seg = next;
-		}
-		xhci_segment_free(xhci, first_seg);
-		ring->first_seg = NULL;
-	}
+	xhci_dbg(xhci, "Freeing ring at %p\n", ring);
+	if (ring->first_seg)
+		xhci_free_segments_for_ring(xhci, ring->first_seg);
 	kfree(ring);
 }
 
@@ -146,6 +148,38 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring)
 	ring->deq_updates = 0;
 }
 
+/* Allocate segments and link them for a ring */
+static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
+		struct xhci_segment **first, struct xhci_segment **last,
+		unsigned int num_segs, bool link_trbs, bool isoc, gfp_t flags)
+{
+	struct xhci_segment *prev;
+
+	prev = xhci_segment_alloc(xhci, flags);
+	if (!prev)
+		return -ENOMEM;
+	num_segs--;
+
+	*first = prev;
+	while (num_segs > 0) {
+		struct xhci_segment	*next;
+
+		next = xhci_segment_alloc(xhci, flags);
+		if (!next) {
+			xhci_free_segments_for_ring(xhci, *first);
+			return -ENOMEM;
+		}
+		xhci_link_segments(xhci, prev, next, link_trbs, isoc);
+
+		prev = next;
+		num_segs--;
+	}
+	xhci_link_segments(xhci, prev, *first, link_trbs, isoc);
+	*last = prev;
+
+	return 0;
+}
+
 /**
  * Create a new ring with zero or more segments.
  *
@@ -157,7 +191,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
 		unsigned int num_segs, bool link_trbs, bool isoc, gfp_t flags)
 {
 	struct xhci_ring	*ring;
-	struct xhci_segment	*prev;
+	int ret;
 
 	ring = kzalloc(sizeof *(ring), flags);
 	xhci_dbg(xhci, "Allocating ring at %p\n", ring);
@@ -175,33 +209,19 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
 
 	ring->num_trbs_free = num_segs * (TRBS_PER_SEGMENT - 1) - 1;
 
-	ring->first_seg = xhci_segment_alloc(xhci, flags);
-	if (!ring->first_seg)
+	ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg,
+			&ring->last_seg, num_segs, link_trbs, isoc, flags);
+	if (ret)
 		goto fail;
-	num_segs--;
-
-	prev = ring->first_seg;
-	while (num_segs > 0) {
-		struct xhci_segment	*next;
-
-		next = xhci_segment_alloc(xhci, flags);
-		if (!next)
-			goto fail;
-		xhci_link_segments(xhci, prev, next, link_trbs, isoc);
-
-		prev = next;
-		num_segs--;
-	}
-	xhci_link_segments(xhci, prev, ring->first_seg, link_trbs, isoc);
-	ring->last_seg = prev;
 
 	if (link_trbs) {
 		/* See section 4.9.2.1 and 6.4.4.1 */
-		prev->trbs[TRBS_PER_SEGMENT-1].link.control |=
+		ring->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control |=
 			cpu_to_le32(LINK_TOGGLE);
 		xhci_dbg(xhci, "Wrote link toggle flag to"
 				" segment %p (virtual), 0x%llx (DMA)\n",
-				prev, (unsigned long long)prev->dma);
+				ring->last_seg,
+				(unsigned long long)ring->last_seg->dma);
 	}
 	xhci_initialize_ring_info(ring);
 	return ring;
-- 
1.7.4.1


--
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