aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAndiry Xu <andiry.xu@amd.com>2012-03-05 04:49:35 -0500
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2012-03-13 12:30:05 -0400
commit70d43601773b9f270b62867a51495846d746b5d4 (patch)
tree70bb6e4da4c0b5fa559049b85ea2429fd498209d /drivers/usb/host
parentb008df60c6369ba0290fa7daa177375407a12e07 (diff)
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)
65 kfree(seg); 65 kfree(seg);
66} 66}
67 67
68static void xhci_free_segments_for_ring(struct xhci_hcd *xhci,
69 struct xhci_segment *first)
70{
71 struct xhci_segment *seg;
72
73 seg = first->next;
74 while (seg != first) {
75 struct xhci_segment *next = seg->next;
76 xhci_segment_free(xhci, seg);
77 seg = next;
78 }
79 xhci_segment_free(xhci, first);
80}
81
68/* 82/*
69 * Make the prev segment point to the next segment. 83 * Make the prev segment point to the next segment.
70 * 84 *
@@ -101,22 +115,12 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
101/* XXX: Do we need the hcd structure in all these functions? */ 115/* XXX: Do we need the hcd structure in all these functions? */
102void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) 116void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
103{ 117{
104 struct xhci_segment *seg;
105 struct xhci_segment *first_seg;
106
107 if (!ring) 118 if (!ring)
108 return; 119 return;
109 if (ring->first_seg) { 120
110 first_seg = ring->first_seg; 121 if (ring->first_seg)
111 seg = first_seg->next; 122 xhci_free_segments_for_ring(xhci, ring->first_seg);
112 while (seg != first_seg) { 123
113 struct xhci_segment *next = seg->next;
114 xhci_segment_free(xhci, seg);
115 seg = next;
116 }
117 xhci_segment_free(xhci, first_seg);
118 ring->first_seg = NULL;
119 }
120 kfree(ring); 124 kfree(ring);
121} 125}
122 126
@@ -143,6 +147,38 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring)
143 ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; 147 ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
144} 148}
145 149
150/* Allocate segments and link them for a ring */
151static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
152 struct xhci_segment **first, struct xhci_segment **last,
153 unsigned int num_segs, enum xhci_ring_type type, gfp_t flags)
154{
155 struct xhci_segment *prev;
156
157 prev = xhci_segment_alloc(xhci, flags);
158 if (!prev)
159 return -ENOMEM;
160 num_segs--;
161
162 *first = prev;
163 while (num_segs > 0) {
164 struct xhci_segment *next;
165
166 next = xhci_segment_alloc(xhci, flags);
167 if (!next) {
168 xhci_free_segments_for_ring(xhci, *first);
169 return -ENOMEM;
170 }
171 xhci_link_segments(xhci, prev, next, type);
172
173 prev = next;
174 num_segs--;
175 }
176 xhci_link_segments(xhci, prev, *first, type);
177 *last = prev;
178
179 return 0;
180}
181
146/** 182/**
147 * Create a new ring with zero or more segments. 183 * Create a new ring with zero or more segments.
148 * 184 *
@@ -154,7 +190,7 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
154 unsigned int num_segs, enum xhci_ring_type type, gfp_t flags) 190 unsigned int num_segs, enum xhci_ring_type type, gfp_t flags)
155{ 191{
156 struct xhci_ring *ring; 192 struct xhci_ring *ring;
157 struct xhci_segment *prev; 193 int ret;
158 194
159 ring = kzalloc(sizeof *(ring), flags); 195 ring = kzalloc(sizeof *(ring), flags);
160 if (!ring) 196 if (!ring)
@@ -166,30 +202,15 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
166 if (num_segs == 0) 202 if (num_segs == 0)
167 return ring; 203 return ring;
168 204
169 ring->first_seg = xhci_segment_alloc(xhci, flags); 205 ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg,
170 if (!ring->first_seg) 206 &ring->last_seg, num_segs, type, flags);
207 if (ret)
171 goto fail; 208 goto fail;
172 num_segs--;
173
174 prev = ring->first_seg;
175 while (num_segs > 0) {
176 struct xhci_segment *next;
177
178 next = xhci_segment_alloc(xhci, flags);
179 if (!next)
180 goto fail;
181 xhci_link_segments(xhci, prev, next, type);
182
183 prev = next;
184 num_segs--;
185 }
186 xhci_link_segments(xhci, prev, ring->first_seg, type);
187 ring->last_seg = prev;
188 209
189 /* Only event ring does not use link TRB */ 210 /* Only event ring does not use link TRB */
190 if (type != TYPE_EVENT) { 211 if (type != TYPE_EVENT) {
191 /* See section 4.9.2.1 and 6.4.4.1 */ 212 /* See section 4.9.2.1 and 6.4.4.1 */
192 prev->trbs[TRBS_PER_SEGMENT-1].link.control |= 213 ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |=
193 cpu_to_le32(LINK_TOGGLE); 214 cpu_to_le32(LINK_TOGGLE);
194 } 215 }
195 xhci_initialize_ring_info(ring); 216 xhci_initialize_ring_info(ring);