drivers/usb/host/xhci-mem.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/host/xhci-mem.c
Extension
.c
Size
72891 bytes
Lines
2515
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 (!seg->bounce_buf) {
			dma_pool_free(xhci->segment_pool, seg->trbs, dma);
			kfree(seg);
			return NULL;
		}
	}
	seg->num = num;
	seg->dma = dma;
	seg->next = NULL;

	return seg;
}

static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
{
	if (seg->trbs) {
		dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma);
		seg->trbs = NULL;
	}
	kfree(seg->bounce_buf);
	kfree(seg);
}

static void xhci_ring_segments_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
{
	struct xhci_segment *seg, *next;

	ring->last_seg->next = NULL;
	seg = ring->first_seg;

	while (seg) {
		next = seg->next;
		xhci_segment_free(xhci, seg);
		seg = next;
	}
}

/*
 * Only for transfer and command rings where driver is the producer, not for
 * event rings.
 *
 * Change the last TRB in the segment to be a Link TRB which points to the
 * DMA address of the next segment.  The caller needs to set any Link TRB
 * related flags, such as End TRB, Toggle Cycle, and no snoop.
 */
static void xhci_set_link_trb(struct xhci_segment *seg, bool chain_links)
{
	union xhci_trb *trb;
	u32 val;

	if (!seg || !seg->next)
		return;

	trb = &seg->trbs[TRBS_PER_SEGMENT - 1];

	/* Set the last TRB in the segment to have a TRB type ID of Link TRB */
	val = le32_to_cpu(trb->link.control);
	val &= ~TRB_TYPE_BITMASK;
	val |= TRB_TYPE(TRB_LINK);
	if (chain_links)
		val |= TRB_CHAIN;
	trb->link.control = cpu_to_le32(val);
	trb->link.segment_ptr = cpu_to_le64(seg->next->dma);
}

static void xhci_initialize_ring_segments(struct xhci_hcd *xhci, struct xhci_ring *ring)
{
	struct xhci_segment *seg;
	bool chain_links;

	if (ring->type == TYPE_EVENT)
		return;

	chain_links = xhci_link_chain_quirk(xhci, ring->type);
	xhci_for_each_ring_seg(ring->first_seg, seg)
		xhci_set_link_trb(seg, chain_links);

	/* See section 4.9.2.1 and 6.4.4.1 */
	ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |= cpu_to_le32(LINK_TOGGLE);
}

void xhci_ring_init(struct xhci_hcd *xhci, struct xhci_ring *ring)
{
	xhci_initialize_ring_segments(xhci, ring);
	xhci_initialize_ring_info(ring);
	trace_xhci_ring_alloc(ring);
}

/*
 * Link the src ring segments to the dst ring.

Annotation

Implementation Notes