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.
*
/* 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);
}
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.
*
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)
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);