summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAndiry Xu <andiry.xu@amd.com>2012-03-05 17:49:35 +0800
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2012-03-13 09:30:05 -0700
commit70d43601773b9f270b62867a51495846d746b5d4 (patch)
tree70bb6e4da4c0b5fa559049b85ea2429fd498209d /drivers/usb/host
parentb008df60c6369ba0290fa7daa177375407a12e07 (diff)
downloadblackbird-op-linux-70d43601773b9f270b62867a51495846d746b5d4.tar.gz
blackbird-op-linux-70d43601773b9f270b62867a51495846d746b5d4.zip
xHCI: factor out segments allocation and free function
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@amd.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Tested-by: Paul Zimmerman <Paul.Zimmerman@synopsys.com>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/xhci-mem.c89
1 files changed, 55 insertions, 34 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 212012c97df3..47b762994ae9 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -65,6 +65,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.
*
@@ -101,22 +115,12 @@ 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;
- 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;
- }
+
+ if (ring->first_seg)
+ xhci_free_segments_for_ring(xhci, ring->first_seg);
+
kfree(ring);
}
@@ -143,6 +147,38 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring)
ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
}
+/* 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, enum xhci_ring_type type, 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, type);
+
+ prev = next;
+ num_segs--;
+ }
+ xhci_link_segments(xhci, prev, *first, type);
+ *last = prev;
+
+ return 0;
+}
+
/**
* Create a new ring with zero or more segments.
*
@@ -154,7 +190,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
unsigned int num_segs, enum xhci_ring_type type, gfp_t flags)
{
struct xhci_ring *ring;
- struct xhci_segment *prev;
+ int ret;
ring = kzalloc(sizeof *(ring), flags);
if (!ring)
@@ -166,30 +202,15 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
if (num_segs == 0)
return ring;
- 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, type, 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, type);
-
- prev = next;
- num_segs--;
- }
- xhci_link_segments(xhci, prev, ring->first_seg, type);
- ring->last_seg = prev;
/* Only event ring does not use link TRB */
if (type != TYPE_EVENT) {
/* 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_initialize_ring_info(ring);
OpenPOWER on IntegriCloud