*/
static void xhci_link_segments(struct xhci_segment *prev,
struct xhci_segment *next,
+ unsigned int trbs_per_seg,
enum xhci_ring_type type, bool chain_links)
{
u32 val;
return;
prev->next = next;
if (type != TYPE_EVENT) {
- prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr =
+ prev->trbs[trbs_per_seg - 1].link.segment_ptr =
cpu_to_le64(next->dma);
/* Set the last TRB in the segment to have a TRB type ID of Link TRB */
- val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control);
+ val = le32_to_cpu(prev->trbs[trbs_per_seg - 1].link.control);
val &= ~TRB_TYPE_BITMASK;
val |= TRB_TYPE(TRB_LINK);
if (chain_links)
val |= TRB_CHAIN;
- prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
+ prev->trbs[trbs_per_seg - 1].link.control = cpu_to_le32(val);
}
}
(xhci->quirks & XHCI_AMD_0x96_HOST)));
next = ring->enq_seg->next;
- xhci_link_segments(ring->enq_seg, first, ring->type, chain_links);
- xhci_link_segments(last, next, ring->type, chain_links);
+ xhci_link_segments(ring->enq_seg, first, ring->trbs_per_seg,
+ ring->type, chain_links);
+ xhci_link_segments(last, next, ring->trbs_per_seg,
+ ring->type, chain_links);
ring->num_segs += num_segs;
- ring->num_trbs_free += (TRBS_PER_SEGMENT - 1) * num_segs;
+ ring->num_trbs_free += (ring->trbs_per_seg - 1) * num_segs;
if (ring->type != TYPE_EVENT && ring->enq_seg == ring->last_seg) {
- ring->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control
+ ring->last_seg->trbs[ring->trbs_per_seg - 1].link.control
&= ~cpu_to_le32(LINK_TOGGLE);
- last->trbs[TRBS_PER_SEGMENT-1].link.control
+ last->trbs[ring->trbs_per_seg - 1].link.control
|= cpu_to_le32(LINK_TOGGLE);
ring->last_seg = last;
}
* Each segment has a link TRB, and leave an extra TRB for SW
* accounting purpose
*/
- ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
+ ring->num_trbs_free = ring->num_segs * (ring->trbs_per_seg - 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, unsigned int cycle_state,
- enum xhci_ring_type type, unsigned int max_packet, gfp_t flags)
+ unsigned int num_segs, unsigned int trbs_per_seg,
+ unsigned int cycle_state, enum xhci_ring_type type,
+ unsigned int max_packet, gfp_t flags)
{
struct xhci_segment *prev;
bool chain_links;
}
return -ENOMEM;
}
- xhci_link_segments(prev, next, type, chain_links);
+ xhci_link_segments(prev, next, trbs_per_seg, type, chain_links);
prev = next;
num_segs--;
}
- xhci_link_segments(prev, *first, type, chain_links);
+ xhci_link_segments(prev, *first, trbs_per_seg, type, chain_links);
*last = prev;
return 0;
if (num_segs == 0)
return ring;
+ ring->trbs_per_seg = TRBS_PER_SEGMENT;
ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg,
- &ring->last_seg, num_segs, cycle_state, type,
- max_packet, flags);
+ &ring->last_seg, num_segs, ring->trbs_per_seg,
+ cycle_state, type, max_packet, flags);
if (ret)
goto fail;
/* Only event ring does not use link TRB */
if (type != TYPE_EVENT) {
/* See section 4.9.2.1 and 6.4.4.1 */
- ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |=
+ ring->last_seg->trbs[ring->trbs_per_seg - 1].link.control |=
cpu_to_le32(LINK_TOGGLE);
}
xhci_initialize_ring_info(ring, cycle_state);
unsigned int num_segs_needed;
int ret;
- num_segs_needed = (num_trbs + (TRBS_PER_SEGMENT - 1) - 1) /
- (TRBS_PER_SEGMENT - 1);
-
+ num_segs_needed = (num_trbs + (ring->trbs_per_seg - 1) - 1) /
+ (ring->trbs_per_seg - 1);
/* Allocate number of segments we needed, or double the ring size */
num_segs = ring->num_segs > num_segs_needed ?
ring->num_segs : num_segs_needed;
ret = xhci_alloc_segments_for_ring(xhci, &first, &last,
- num_segs, ring->cycle_state, ring->type,
- ring->bounce_buf_len, flags);
+ num_segs, ring->trbs_per_seg, ring->cycle_state,
+ ring->type, ring->bounce_buf_len, flags);
if (ret)
return -ENOMEM;
for (val = 0; val < evt_ring->num_segs; val++) {
entry = &erst->entries[val];
entry->seg_addr = cpu_to_le64(seg->dma);
- entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT);
+ entry->seg_size = cpu_to_le32(evt_ring->trbs_per_seg);
entry->rsvd = 0;
seg = seg->next;
}
return TRB_TYPE_LINK_LE32(trb->link.control);
}
-static bool last_trb_on_seg(struct xhci_segment *seg, union xhci_trb *trb)
+static bool last_trb_on_seg(struct xhci_segment *seg,
+ unsigned int trbs_per_seg, union xhci_trb *trb)
{
- return trb == &seg->trbs[TRBS_PER_SEGMENT - 1];
+ return trb == &seg->trbs[trbs_per_seg - 1];
}
static bool last_trb_on_ring(struct xhci_ring *ring,
struct xhci_segment *seg, union xhci_trb *trb)
{
- return last_trb_on_seg(seg, trb) && (seg->next == ring->first_seg);
+ return last_trb_on_seg(seg, ring->trbs_per_seg, trb) && (seg->next == ring->first_seg);
}
static bool link_trb_toggles_cycle(union xhci_trb *trb)
/* event ring doesn't have link trbs, check for last trb */
if (ring->type == TYPE_EVENT) {
- if (!last_trb_on_seg(ring->deq_seg, ring->dequeue)) {
+ if (!last_trb_on_seg(ring->deq_seg, ring->trbs_per_seg,
+ ring->dequeue)) {
ring->dequeue++;
goto out;
}
/* All other rings have link trbs */
if (!trb_is_link(ring->dequeue)) {
- if (last_trb_on_seg(ring->deq_seg, ring->dequeue)) {
+ if (last_trb_on_seg(ring->deq_seg, ring->trbs_per_seg,
+ ring->dequeue)) {
xhci_warn(xhci, "Missing link TRB at end of segment\n");
} else {
ring->dequeue++;
if (!trb_is_link(ring->enqueue))
ring->num_trbs_free--;
- if (last_trb_on_seg(ring->enq_seg, ring->enqueue)) {
+ if (last_trb_on_seg(ring->enq_seg, ring->trbs_per_seg, ring->enqueue)) {
xhci_err(xhci, "Tried to move enqueue past ring segment\n");
return;
}
* that clears the EHB.
*/
while (xhci_handle_event(xhci) > 0) {
- if (event_loop++ < TRBS_PER_SEGMENT / 2)
+ if (event_loop++ < xhci->event_ring->trbs_per_seg / 2)
continue;
xhci_update_erst_dequeue(xhci, event_ring_deq);
}
}
- if (last_trb_on_seg(ep_ring->enq_seg, ep_ring->enqueue)) {
+ if (last_trb_on_seg(ep_ring->enq_seg, ep_ring->trbs_per_seg,
+ ep_ring->enqueue)) {
xhci_warn(xhci, "Missing link TRB at end of ring segment\n");
return -EINVAL;
}