drivers/usb/gadget/udc/cdns2/cdns2-gadget.c

Source file repositories/reference/linux-study-clean/drivers/usb/gadget/udc/cdns2/cdns2-gadget.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/gadget/udc/cdns2/cdns2-gadget.c
Extension
.c
Size
61489 bytes
Lines
2469
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 (doorbell) {
			pep->wa1_cycle_bit = pep->ring.pcs ? TRB_CYCLE : 0;
			pep->wa1_set = 1;
			pep->wa1_trb = trb;
			pep->wa1_trb_index = pep->ring.enqueue;
			trace_cdns2_wa1(pep, "set guard");
			return 0;
		}
	}
	return 1;
}

static void cdns2_wa1_tray_restore_cycle_bit(struct cdns2_device *pdev,
					     struct cdns2_endpoint *pep)
{
	int dma_index;
	u32 doorbell;

	doorbell = !!(readl(&pdev->adma_regs->ep_cmd) & DMA_EP_CMD_DRDY);
	dma_index = cdns2_get_dma_pos(pdev, pep);

	if (!doorbell || dma_index != pep->wa1_trb_index)
		cdns2_wa1_restore_cycle_bit(pep);
}

static int cdns2_prepare_ring(struct cdns2_device *pdev,
			      struct cdns2_endpoint *pep,
			      int num_trbs)
{
	struct cdns2_trb *link_trb = NULL;
	int doorbell, dma_index;
	struct cdns2_ring *ring;
	u32 ch_bit = 0;

	ring = &pep->ring;

	if (num_trbs > ring->free_trbs) {
		pep->ep_state |= EP_RING_FULL;
		trace_cdns2_no_room_on_ring("Ring full\n");
		return -ENOBUFS;
	}

	if ((ring->enqueue + num_trbs)  >= (TRBS_PER_SEGMENT - 1)) {
		doorbell = !!(readl(&pdev->adma_regs->ep_cmd) & DMA_EP_CMD_DRDY);
		dma_index = cdns2_get_dma_pos(pdev, pep);

		/* Driver can't update LINK TRB if it is current processed. */
		if (doorbell && dma_index == TRBS_PER_SEGMENT - 1) {
			pep->ep_state |= EP_DEFERRED_DRDY;
			return -ENOBUFS;
		}

		/* Update C bt in Link TRB before starting DMA. */
		link_trb = ring->trbs + (TRBS_PER_SEGMENT - 1);

		/*
		 * For TRs size equal 2 enabling TRB_CHAIN for epXin causes
		 * that DMA stuck at the LINK TRB.
		 * On the other hand, removing TRB_CHAIN for longer TRs for
		 * epXout cause that DMA stuck after handling LINK TRB.
		 * To eliminate this strange behavioral driver set TRB_CHAIN
		 * bit only for TR size > 2.
		 */
		if (pep->type == USB_ENDPOINT_XFER_ISOC || TRBS_PER_SEGMENT > 2)
			ch_bit = TRB_CHAIN;

		link_trb->control = cpu_to_le32(((ring->pcs) ? TRB_CYCLE : 0) |
				    TRB_TYPE(TRB_LINK) | TRB_TOGGLE | ch_bit);
	}

	return 0;
}

static void cdns2_dbg_request_trbs(struct cdns2_endpoint *pep,
				   struct cdns2_request *preq)
{
	struct cdns2_trb *link_trb = pep->ring.trbs + (TRBS_PER_SEGMENT - 1);
	struct cdns2_trb *trb = preq->trb;
	int num_trbs = preq->num_of_trb;
	int i = 0;

	while (i < num_trbs) {
		trace_cdns2_queue_trb(pep, trb + i);
		if (trb + i == link_trb) {
			trb = pep->ring.trbs;
			num_trbs = num_trbs - i;
			i = 0;
		} else {
			i++;
		}

Annotation

Implementation Notes