drivers/net/ethernet/mscc/ocelot_fdma.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/mscc/ocelot_fdma.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mscc/ocelot_fdma.c
Extension
.c
Size
22794 bytes
Lines
893
Domain
Driver Families
Bucket
drivers/net
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 (unlikely(!rxb->page)) {
			if (unlikely(!ocelot_fdma_rx_alloc_page(ocelot, rxb))) {
				dev_err_ratelimited(ocelot->dev,
						    "Failed to allocate rx\n");
				ret = -ENOMEM;
				break;
			}
		}

		dcb = &rx_ring->dcbs[idx];
		dma_addr = rxb->dma_addr + rxb->page_offset;
		ocelot_fdma_dcb_set_data(dcb, dma_addr, OCELOT_FDMA_RXB_SIZE);

		idx = ocelot_fdma_idx_next(idx, OCELOT_FDMA_RX_RING_SIZE);
		/* Chain the DCB to the next one */
		dcb->llp = ocelot_fdma_idx_dma(rx_ring->dcbs_dma, idx);
	}

	rx_ring->next_to_use = idx;
	rx_ring->next_to_alloc = idx;

	return ret;
}

static bool ocelot_fdma_tx_dcb_set_skb(struct ocelot *ocelot,
				       struct ocelot_fdma_tx_buf *tx_buf,
				       struct ocelot_fdma_dcb *dcb,
				       struct sk_buff *skb)
{
	dma_addr_t mapping;

	mapping = dma_map_single(ocelot->dev, skb->data, skb->len,
				 DMA_TO_DEVICE);
	if (unlikely(dma_mapping_error(ocelot->dev, mapping)))
		return false;

	dma_unmap_addr_set(tx_buf, dma_addr, mapping);

	ocelot_fdma_dcb_set_data(dcb, mapping, OCELOT_FDMA_RX_SIZE);
	tx_buf->skb = skb;
	dcb->stat |= MSCC_FDMA_DCB_STAT_BLOCKL(skb->len);
	dcb->stat |= MSCC_FDMA_DCB_STAT_SOF | MSCC_FDMA_DCB_STAT_EOF;

	return true;
}

static bool ocelot_fdma_check_stop_rx(struct ocelot *ocelot)
{
	u32 llp;

	/* Check if the FDMA hits the DCB with LLP == NULL */
	llp = ocelot_fdma_readl(ocelot, MSCC_FDMA_DCB_LLP(MSCC_FDMA_XTR_CHAN));
	if (unlikely(llp))
		return false;

	ocelot_fdma_writel(ocelot, MSCC_FDMA_CH_DISABLE,
			   BIT(MSCC_FDMA_XTR_CHAN));

	return true;
}

static void ocelot_fdma_rx_set_llp(struct ocelot_fdma_rx_ring *rx_ring)
{
	struct ocelot_fdma_dcb *dcb;
	unsigned int idx;

	idx = ocelot_fdma_idx_prev(rx_ring->next_to_use,
				   OCELOT_FDMA_RX_RING_SIZE);
	dcb = &rx_ring->dcbs[idx];
	dcb->llp = 0;
}

static void ocelot_fdma_rx_restart(struct ocelot *ocelot)
{
	struct ocelot_fdma *fdma = ocelot->fdma;
	struct ocelot_fdma_rx_ring *rx_ring;
	const u8 chan = MSCC_FDMA_XTR_CHAN;
	dma_addr_t new_llp, dma_base;
	unsigned int idx;
	u32 llp_prev;
	int ret;

	rx_ring = &fdma->rx_ring;
	ret = ocelot_fdma_wait_chan_safe(ocelot, chan);
	if (ret) {
		dev_err_ratelimited(ocelot->dev,
				    "Unable to stop RX channel\n");
		return;
	}

Annotation

Implementation Notes