drivers/usb/host/xhci-dbgcap.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/host/xhci-dbgcap.c
Extension
.c
Size
36132 bytes
Lines
1561
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: implementation source
Status
source 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 (r->trb_dma == event->trans_event.buffer) {
			req = r;
			break;
		}
		if (r->status == -COMP_STALL_ERROR) {
			dev_warn(dbc->dev, "Give back stale stalled req\n");
			ring->num_trbs_free++;
			xhci_dbc_giveback(r, 0);
		}
	}

	if (!req) {
		dev_warn(dbc->dev, "no matched request\n");
		return;
	}

	trace_xhci_dbc_handle_transfer(ring, &req->trb->generic, req->trb_dma);

	switch (comp_code) {
	case COMP_SUCCESS:
		remain_length = 0;
		fallthrough;
	case COMP_SHORT_PACKET:
		status = 0;
		break;
	case COMP_TRB_ERROR:
	case COMP_BABBLE_DETECTED_ERROR:
	case COMP_USB_TRANSACTION_ERROR:
		dev_warn(dbc->dev, "tx error %d detected\n", comp_code);
		status = -comp_code;
		break;
	case COMP_STALL_ERROR:
		dev_warn(dbc->dev, "Stall error at bulk TRB %llx, remaining %zu, ep deq %llx\n",
			 event->trans_event.buffer, remain_length, ep_ctx->deq);
		status = 0;
		dep->halted = 1;

		/*
		 * xHC DbC may trigger a STALL bulk xfer event when host sends a
		 * ClearFeature(ENDPOINT_HALT) request even if there wasn't an
		 * active bulk transfer.
		 *
		 * Don't give back this transfer request as hardware will later
		 * start processing TRBs starting from this 'STALLED' TRB,
		 * causing TRBs and requests to be out of sync.
		 *
		 * If STALL event shows some bytes were transferred then assume
		 * it's an actual transfer issue and give back the request.
		 * In this case mark the TRB as No-Op to avoid hw from using the
		 * TRB again.
		 */

		if ((ep_ctx->deq & ~TRB_CYCLE) == event->trans_event.buffer) {
			dev_dbg(dbc->dev, "Ep stopped on Stalled TRB\n");
			if (remain_length == req->length) {
				dev_dbg(dbc->dev, "Spurious stall event, keep req\n");
				req->status = -COMP_STALL_ERROR;
				req->actual = 0;
				return;
			}
			dev_dbg(dbc->dev, "Give back stalled req, but turn TRB to No-op\n");
			trb_to_noop(req->trb);
		}
		break;

	default:
		dev_err(dbc->dev, "unknown tx error %d\n", comp_code);
		status = -comp_code;
		break;
	}

	ring->num_trbs_free++;
	req->actual = req->length - remain_length;
	xhci_dbc_giveback(req, status);
}

static void inc_evt_deq(struct xhci_ring *ring)
{
	/* If on the last TRB of the segment go back to the beginning */
	if (ring->dequeue == &ring->deq_seg->trbs[TRBS_PER_SEGMENT - 1]) {
		ring->cycle_state ^= 1;
		ring->dequeue = ring->deq_seg->trbs;
		return;
	}
	ring->dequeue++;
}

static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
{
	dma_addr_t		deq;

Annotation

Implementation Notes