drivers/usb/host/xhci-ring.c

Source file repositories/reference/linux-study-clean/drivers/usb/host/xhci-ring.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/host/xhci-ring.c
Extension
.c
Size
136585 bytes
Lines
4488
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (in_range(dma, seg->dma, TRB_SEGMENT_SIZE)) {
			if (match_seg)
				*match_seg = seg;
			return &seg->trbs[(dma - seg->dma) / sizeof(union xhci_trb)];
		}
	}

	return NULL;
}

static bool trb_is_noop(union xhci_trb *trb)
{
	return TRB_TYPE_NOOP_LE32(trb->generic.field[3]);
}

static bool trb_is_link(union xhci_trb *trb)
{
	return TRB_TYPE_LINK_LE32(trb->link.control);
}

static bool last_trb_on_seg(struct xhci_segment *seg, union xhci_trb *trb)
{
	return trb == &seg->trbs[TRBS_PER_SEGMENT - 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);
}

static bool link_trb_toggles_cycle(union xhci_trb *trb)
{
	return le32_to_cpu(trb->link.control) & LINK_TOGGLE;
}

static bool last_td_in_urb(struct xhci_td *td)
{
	struct urb_priv *urb_priv = td->urb->hcpriv;

	return urb_priv->num_tds_done == urb_priv->num_tds;
}

static bool unhandled_event_trb(struct xhci_ring *ring)
{
	return ((le32_to_cpu(ring->dequeue->event_cmd.flags) & TRB_CYCLE) ==
		ring->cycle_state);
}

static void inc_td_cnt(struct urb *urb)
{
	struct urb_priv *urb_priv = urb->hcpriv;

	urb_priv->num_tds_done++;
}

static void trb_to_noop(union xhci_trb *trb, u32 noop_type, bool unchain_links)
{
	if (trb_is_link(trb)) {
		if (unchain_links)
			trb->link.control &= cpu_to_le32(~TRB_CHAIN);
	} else {
		trb->generic.field[0] = 0;
		trb->generic.field[1] = 0;
		trb->generic.field[2] = 0;
		/* Preserve only the cycle bit of this TRB */
		trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE);
		trb->generic.field[3] |= cpu_to_le32(TRB_TYPE(noop_type));
	}
}

static unsigned int trb_to_pos(struct xhci_segment *seg, union xhci_trb *trb)
{
	return seg->num * TRBS_PER_SEGMENT + (trb - seg->trbs);
}

/* Updates trb to point to the next TRB in the ring, and updates seg if the next
 * TRB is in a new segment.  This does not skip over link TRBs, and it does not
 * effect the ring dequeue or enqueue pointers.
 */
static void next_trb(struct xhci_segment **seg,
			union xhci_trb **trb)
{
	if (trb_is_link(*trb) || last_trb_on_seg(*seg, *trb)) {
		*seg = (*seg)->next;
		*trb = ((*seg)->trbs);
	} else {
		(*trb)++;
	}
}

Annotation

Implementation Notes