drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c

Source file repositories/reference/linux-study-clean/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c

File Facts

System
Linux kernel
Corpus path
drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c
Extension
.c
Size
8105 bytes
Lines
303
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

mcp251xfd_get_tx_free(tx_ring) == 0) {
		*len_p = tx_ring->obj_num;
		return 0;
	}

	chip_tx_tail = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);

	err =  mcp251xfd_check_tef_tail(priv);
	if (err)
		return err;
	tail = mcp251xfd_get_tef_tail(priv);

	/* First shift to full u8. The subtraction works on signed
	 * values, that keeps the difference steady around the u8
	 * overflow. The right shift acts on len, which is an u8.
	 */
	BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(chip_tx_tail));
	BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(tail));
	BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(len));

	len = (chip_tx_tail << shift) - (tail << shift);
	len >>= shift;

	/* According to mcp2518fd erratum DS80000789E 6. the FIFOCI
	 * bits of a FIFOSTA register, here the TX-FIFO tail index
	 * might be corrupted.
	 *
	 * However here it seems the bit indicating that the TX-FIFO
	 * is empty (MCP251XFD_REG_FIFOSTA_TFERFFIF) is not correct
	 * while the TX-FIFO tail index is.
	 *
	 * We assume the TX-FIFO is empty, i.e. all pending CAN frames
	 * haven been send, if:
	 * - Chip's head and tail index are equal (len == 0).
	 * - The TX-FIFO is less than half full.
	 *   (The TX-FIFO empty case has already been checked at the
	 *    beginning of this function.)
	 * - No free buffers in the TX ring.
	 */
	if (len == 0 && mcp251xfd_tx_fifo_sta_less_than_half_full(fifo_sta) &&
	    mcp251xfd_get_tx_free(tx_ring) == 0)
		len = tx_ring->obj_num;

	*len_p = len;

	return 0;
}

static inline int
mcp251xfd_tef_obj_read(const struct mcp251xfd_priv *priv,
		       struct mcp251xfd_hw_tef_obj *hw_tef_obj,
		       const u8 offset, const u8 len)
{
	const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
	const int val_bytes = regmap_get_val_bytes(priv->map_rx);

	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
	    (offset > tx_ring->obj_num ||
	     len > tx_ring->obj_num ||
	     offset + len > tx_ring->obj_num)) {
		netdev_err(priv->ndev,
			   "Trying to read too many TEF objects (max=%d, offset=%d, len=%d).\n",
			   tx_ring->obj_num, offset, len);
		return -ERANGE;
	}

	return regmap_bulk_read(priv->map_rx,
				mcp251xfd_get_tef_obj_addr(offset),
				hw_tef_obj,
				sizeof(*hw_tef_obj) / val_bytes * len);
}

static inline void mcp251xfd_ecc_tefif_successful(struct mcp251xfd_priv *priv)
{
	struct mcp251xfd_ecc *ecc = &priv->ecc;

	ecc->ecc_stat = 0;
}

int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
{
	struct mcp251xfd_hw_tef_obj hw_tef_obj[MCP251XFD_TX_OBJ_NUM_MAX];
	unsigned int total_frame_len = 0;
	u8 tef_tail, len, l;
	int err, i;

	err = mcp251xfd_get_tef_len(priv, &len);
	if (err)
		return err;

Annotation

Implementation Notes