xref: /linux/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c (revision b8e0ddd36ce9536ad7478dd27df06c9ae92370ba)
11e846c7aSMarc Kleine-Budde // SPDX-License-Identifier: GPL-2.0
21e846c7aSMarc Kleine-Budde //
31e846c7aSMarc Kleine-Budde // mcp251xfd - Microchip MCP251xFD Family CAN controller driver
41e846c7aSMarc Kleine-Budde //
5*b8e0ddd3SMarc Kleine-Budde // Copyright (c) 2019, 2020, 2021, 2023 Pengutronix,
61e846c7aSMarc Kleine-Budde //               Marc Kleine-Budde <kernel@pengutronix.de>
71e846c7aSMarc Kleine-Budde //
81e846c7aSMarc Kleine-Budde // Based on:
91e846c7aSMarc Kleine-Budde //
101e846c7aSMarc Kleine-Budde // CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
111e846c7aSMarc Kleine-Budde //
121e846c7aSMarc Kleine-Budde // Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
131e846c7aSMarc Kleine-Budde //
141e846c7aSMarc Kleine-Budde 
151e846c7aSMarc Kleine-Budde #include <linux/bitfield.h>
161e846c7aSMarc Kleine-Budde 
171e846c7aSMarc Kleine-Budde #include "mcp251xfd.h"
181e846c7aSMarc Kleine-Budde 
19*b8e0ddd3SMarc Kleine-Budde static inline bool mcp251xfd_tx_fifo_sta_full(u32 fifo_sta)
20*b8e0ddd3SMarc Kleine-Budde {
21*b8e0ddd3SMarc Kleine-Budde 	return !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
22*b8e0ddd3SMarc Kleine-Budde }
23*b8e0ddd3SMarc Kleine-Budde 
241e846c7aSMarc Kleine-Budde static inline int
251e846c7aSMarc Kleine-Budde mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv,
261e846c7aSMarc Kleine-Budde 				 u8 *tef_tail)
271e846c7aSMarc Kleine-Budde {
281e846c7aSMarc Kleine-Budde 	u32 tef_ua;
291e846c7aSMarc Kleine-Budde 	int err;
301e846c7aSMarc Kleine-Budde 
311e846c7aSMarc Kleine-Budde 	err = regmap_read(priv->map_reg, MCP251XFD_REG_TEFUA, &tef_ua);
321e846c7aSMarc Kleine-Budde 	if (err)
331e846c7aSMarc Kleine-Budde 		return err;
341e846c7aSMarc Kleine-Budde 
351e846c7aSMarc Kleine-Budde 	*tef_tail = tef_ua / sizeof(struct mcp251xfd_hw_tef_obj);
361e846c7aSMarc Kleine-Budde 
371e846c7aSMarc Kleine-Budde 	return 0;
381e846c7aSMarc Kleine-Budde }
391e846c7aSMarc Kleine-Budde 
401e846c7aSMarc Kleine-Budde static int mcp251xfd_check_tef_tail(const struct mcp251xfd_priv *priv)
411e846c7aSMarc Kleine-Budde {
421e846c7aSMarc Kleine-Budde 	u8 tef_tail_chip, tef_tail;
431e846c7aSMarc Kleine-Budde 	int err;
441e846c7aSMarc Kleine-Budde 
451e846c7aSMarc Kleine-Budde 	if (!IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY))
461e846c7aSMarc Kleine-Budde 		return 0;
471e846c7aSMarc Kleine-Budde 
481e846c7aSMarc Kleine-Budde 	err = mcp251xfd_tef_tail_get_from_chip(priv, &tef_tail_chip);
491e846c7aSMarc Kleine-Budde 	if (err)
501e846c7aSMarc Kleine-Budde 		return err;
511e846c7aSMarc Kleine-Budde 
521e846c7aSMarc Kleine-Budde 	tef_tail = mcp251xfd_get_tef_tail(priv);
531e846c7aSMarc Kleine-Budde 	if (tef_tail_chip != tef_tail) {
541e846c7aSMarc Kleine-Budde 		netdev_err(priv->ndev,
551e846c7aSMarc Kleine-Budde 			   "TEF tail of chip (0x%02x) and ours (0x%08x) inconsistent.\n",
561e846c7aSMarc Kleine-Budde 			   tef_tail_chip, tef_tail);
571e846c7aSMarc Kleine-Budde 		return -EILSEQ;
581e846c7aSMarc Kleine-Budde 	}
591e846c7aSMarc Kleine-Budde 
601e846c7aSMarc Kleine-Budde 	return 0;
611e846c7aSMarc Kleine-Budde }
621e846c7aSMarc Kleine-Budde 
631e846c7aSMarc Kleine-Budde static int
641e846c7aSMarc Kleine-Budde mcp251xfd_handle_tefif_recover(const struct mcp251xfd_priv *priv, const u32 seq)
651e846c7aSMarc Kleine-Budde {
661e846c7aSMarc Kleine-Budde 	const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
671e846c7aSMarc Kleine-Budde 	u32 tef_sta;
681e846c7aSMarc Kleine-Budde 	int err;
691e846c7aSMarc Kleine-Budde 
701e846c7aSMarc Kleine-Budde 	err = regmap_read(priv->map_reg, MCP251XFD_REG_TEFSTA, &tef_sta);
711e846c7aSMarc Kleine-Budde 	if (err)
721e846c7aSMarc Kleine-Budde 		return err;
731e846c7aSMarc Kleine-Budde 
741e846c7aSMarc Kleine-Budde 	if (tef_sta & MCP251XFD_REG_TEFSTA_TEFOVIF) {
751e846c7aSMarc Kleine-Budde 		netdev_err(priv->ndev,
761e846c7aSMarc Kleine-Budde 			   "Transmit Event FIFO buffer overflow.\n");
771e846c7aSMarc Kleine-Budde 		return -ENOBUFS;
781e846c7aSMarc Kleine-Budde 	}
791e846c7aSMarc Kleine-Budde 
801e846c7aSMarc Kleine-Budde 	netdev_info(priv->ndev,
811e846c7aSMarc Kleine-Budde 		    "Transmit Event FIFO buffer %s. (seq=0x%08x, tef_tail=0x%08x, tef_head=0x%08x, tx_head=0x%08x).\n",
821e846c7aSMarc Kleine-Budde 		    tef_sta & MCP251XFD_REG_TEFSTA_TEFFIF ?
831e846c7aSMarc Kleine-Budde 		    "full" : tef_sta & MCP251XFD_REG_TEFSTA_TEFNEIF ?
841e846c7aSMarc Kleine-Budde 		    "not empty" : "empty",
851e846c7aSMarc Kleine-Budde 		    seq, priv->tef->tail, priv->tef->head, tx_ring->head);
861e846c7aSMarc Kleine-Budde 
871e846c7aSMarc Kleine-Budde 	/* The Sequence Number in the TEF doesn't match our tef_tail. */
881e846c7aSMarc Kleine-Budde 	return -EAGAIN;
891e846c7aSMarc Kleine-Budde }
901e846c7aSMarc Kleine-Budde 
911e846c7aSMarc Kleine-Budde static int
921e846c7aSMarc Kleine-Budde mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
931e846c7aSMarc Kleine-Budde 			   const struct mcp251xfd_hw_tef_obj *hw_tef_obj,
941e846c7aSMarc Kleine-Budde 			   unsigned int *frame_len_ptr)
951e846c7aSMarc Kleine-Budde {
961e846c7aSMarc Kleine-Budde 	struct net_device_stats *stats = &priv->ndev->stats;
971e846c7aSMarc Kleine-Budde 	struct sk_buff *skb;
981e846c7aSMarc Kleine-Budde 	u32 seq, seq_masked, tef_tail_masked, tef_tail;
991e846c7aSMarc Kleine-Budde 
1001e846c7aSMarc Kleine-Budde 	seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK,
1011e846c7aSMarc Kleine-Budde 			hw_tef_obj->flags);
1021e846c7aSMarc Kleine-Budde 
1031e846c7aSMarc Kleine-Budde 	/* Use the MCP2517FD mask on the MCP2518FD, too. We only
1041e846c7aSMarc Kleine-Budde 	 * compare 7 bits, this should be enough to detect
1051e846c7aSMarc Kleine-Budde 	 * net-yet-completed, i.e. old TEF objects.
1061e846c7aSMarc Kleine-Budde 	 */
1071e846c7aSMarc Kleine-Budde 	seq_masked = seq &
1081e846c7aSMarc Kleine-Budde 		field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK);
1091e846c7aSMarc Kleine-Budde 	tef_tail_masked = priv->tef->tail &
1101e846c7aSMarc Kleine-Budde 		field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK);
1111e846c7aSMarc Kleine-Budde 	if (seq_masked != tef_tail_masked)
1121e846c7aSMarc Kleine-Budde 		return mcp251xfd_handle_tefif_recover(priv, seq);
1131e846c7aSMarc Kleine-Budde 
1141e846c7aSMarc Kleine-Budde 	tef_tail = mcp251xfd_get_tef_tail(priv);
1151e846c7aSMarc Kleine-Budde 	skb = priv->can.echo_skb[tef_tail];
1161e846c7aSMarc Kleine-Budde 	if (skb)
117e793c724SMarc Kleine-Budde 		mcp251xfd_skb_set_timestamp_raw(priv, skb, hw_tef_obj->ts);
1181e846c7aSMarc Kleine-Budde 	stats->tx_bytes +=
1192e3df4a3SMarc Kleine-Budde 		can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload,
1201e846c7aSMarc Kleine-Budde 							    tef_tail, hw_tef_obj->ts,
1211e846c7aSMarc Kleine-Budde 							    frame_len_ptr);
1221e846c7aSMarc Kleine-Budde 	stats->tx_packets++;
1231e846c7aSMarc Kleine-Budde 	priv->tef->tail++;
1241e846c7aSMarc Kleine-Budde 
1251e846c7aSMarc Kleine-Budde 	return 0;
1261e846c7aSMarc Kleine-Budde }
1271e846c7aSMarc Kleine-Budde 
128*b8e0ddd3SMarc Kleine-Budde static int
129*b8e0ddd3SMarc Kleine-Budde mcp251xfd_get_tef_len(struct mcp251xfd_priv *priv, u8 *len_p)
1301e846c7aSMarc Kleine-Budde {
1311e846c7aSMarc Kleine-Budde 	const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
132*b8e0ddd3SMarc Kleine-Budde 	const u8 shift = tx_ring->obj_num_shift_to_u8;
133*b8e0ddd3SMarc Kleine-Budde 	u8 chip_tx_tail, tail, len;
134*b8e0ddd3SMarc Kleine-Budde 	u32 fifo_sta;
1351e846c7aSMarc Kleine-Budde 	int err;
1361e846c7aSMarc Kleine-Budde 
137*b8e0ddd3SMarc Kleine-Budde 	err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(priv->tx->fifo_nr),
138*b8e0ddd3SMarc Kleine-Budde 			  &fifo_sta);
1391e846c7aSMarc Kleine-Budde 	if (err)
1401e846c7aSMarc Kleine-Budde 		return err;
1411e846c7aSMarc Kleine-Budde 
142*b8e0ddd3SMarc Kleine-Budde 	if (mcp251xfd_tx_fifo_sta_full(fifo_sta)) {
143*b8e0ddd3SMarc Kleine-Budde 		*len_p = tx_ring->obj_num;
144*b8e0ddd3SMarc Kleine-Budde 		return 0;
145*b8e0ddd3SMarc Kleine-Budde 	}
146*b8e0ddd3SMarc Kleine-Budde 
147*b8e0ddd3SMarc Kleine-Budde 	chip_tx_tail = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);
148*b8e0ddd3SMarc Kleine-Budde 
149*b8e0ddd3SMarc Kleine-Budde 	err =  mcp251xfd_check_tef_tail(priv);
150*b8e0ddd3SMarc Kleine-Budde 	if (err)
151*b8e0ddd3SMarc Kleine-Budde 		return err;
152*b8e0ddd3SMarc Kleine-Budde 	tail = mcp251xfd_get_tef_tail(priv);
153*b8e0ddd3SMarc Kleine-Budde 
154*b8e0ddd3SMarc Kleine-Budde 	/* First shift to full u8. The subtraction works on signed
155*b8e0ddd3SMarc Kleine-Budde 	 * values, that keeps the difference steady around the u8
156*b8e0ddd3SMarc Kleine-Budde 	 * overflow. The right shift acts on len, which is an u8.
1571e846c7aSMarc Kleine-Budde 	 */
158*b8e0ddd3SMarc Kleine-Budde 	BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(chip_tx_tail));
159*b8e0ddd3SMarc Kleine-Budde 	BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(tail));
160*b8e0ddd3SMarc Kleine-Budde 	BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(len));
1611e846c7aSMarc Kleine-Budde 
162*b8e0ddd3SMarc Kleine-Budde 	len = (chip_tx_tail << shift) - (tail << shift);
163*b8e0ddd3SMarc Kleine-Budde 	*len_p = len >> shift;
1641e846c7aSMarc Kleine-Budde 
165*b8e0ddd3SMarc Kleine-Budde 	return 0;
1661e846c7aSMarc Kleine-Budde }
1671e846c7aSMarc Kleine-Budde 
1681e846c7aSMarc Kleine-Budde static inline int
1691e846c7aSMarc Kleine-Budde mcp251xfd_tef_obj_read(const struct mcp251xfd_priv *priv,
1701e846c7aSMarc Kleine-Budde 		       struct mcp251xfd_hw_tef_obj *hw_tef_obj,
1711e846c7aSMarc Kleine-Budde 		       const u8 offset, const u8 len)
1721e846c7aSMarc Kleine-Budde {
1731e846c7aSMarc Kleine-Budde 	const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
1741e846c7aSMarc Kleine-Budde 	const int val_bytes = regmap_get_val_bytes(priv->map_rx);
1751e846c7aSMarc Kleine-Budde 
1761e846c7aSMarc Kleine-Budde 	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&
1771e846c7aSMarc Kleine-Budde 	    (offset > tx_ring->obj_num ||
1781e846c7aSMarc Kleine-Budde 	     len > tx_ring->obj_num ||
1791e846c7aSMarc Kleine-Budde 	     offset + len > tx_ring->obj_num)) {
1801e846c7aSMarc Kleine-Budde 		netdev_err(priv->ndev,
1811e846c7aSMarc Kleine-Budde 			   "Trying to read too many TEF objects (max=%d, offset=%d, len=%d).\n",
1821e846c7aSMarc Kleine-Budde 			   tx_ring->obj_num, offset, len);
1831e846c7aSMarc Kleine-Budde 		return -ERANGE;
1841e846c7aSMarc Kleine-Budde 	}
1851e846c7aSMarc Kleine-Budde 
1861e846c7aSMarc Kleine-Budde 	return regmap_bulk_read(priv->map_rx,
1871e846c7aSMarc Kleine-Budde 				mcp251xfd_get_tef_obj_addr(offset),
1881e846c7aSMarc Kleine-Budde 				hw_tef_obj,
1891e846c7aSMarc Kleine-Budde 				sizeof(*hw_tef_obj) / val_bytes * len);
1901e846c7aSMarc Kleine-Budde }
1911e846c7aSMarc Kleine-Budde 
1921e846c7aSMarc Kleine-Budde static inline void mcp251xfd_ecc_tefif_successful(struct mcp251xfd_priv *priv)
1931e846c7aSMarc Kleine-Budde {
1941e846c7aSMarc Kleine-Budde 	struct mcp251xfd_ecc *ecc = &priv->ecc;
1951e846c7aSMarc Kleine-Budde 
1961e846c7aSMarc Kleine-Budde 	ecc->ecc_stat = 0;
1971e846c7aSMarc Kleine-Budde }
1981e846c7aSMarc Kleine-Budde 
1991e846c7aSMarc Kleine-Budde int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
2001e846c7aSMarc Kleine-Budde {
2011e846c7aSMarc Kleine-Budde 	struct mcp251xfd_hw_tef_obj hw_tef_obj[MCP251XFD_TX_OBJ_NUM_MAX];
2021e846c7aSMarc Kleine-Budde 	unsigned int total_frame_len = 0;
2031e846c7aSMarc Kleine-Budde 	u8 tef_tail, len, l;
2041e846c7aSMarc Kleine-Budde 	int err, i;
2051e846c7aSMarc Kleine-Budde 
206*b8e0ddd3SMarc Kleine-Budde 	err = mcp251xfd_get_tef_len(priv, &len);
2071e846c7aSMarc Kleine-Budde 	if (err)
2081e846c7aSMarc Kleine-Budde 		return err;
2091e846c7aSMarc Kleine-Budde 
2101e846c7aSMarc Kleine-Budde 	tef_tail = mcp251xfd_get_tef_tail(priv);
211*b8e0ddd3SMarc Kleine-Budde 	l = mcp251xfd_get_tef_linear_len(priv, len);
2121e846c7aSMarc Kleine-Budde 	err = mcp251xfd_tef_obj_read(priv, hw_tef_obj, tef_tail, l);
2131e846c7aSMarc Kleine-Budde 	if (err)
2141e846c7aSMarc Kleine-Budde 		return err;
2151e846c7aSMarc Kleine-Budde 
2161e846c7aSMarc Kleine-Budde 	if (l < len) {
2171e846c7aSMarc Kleine-Budde 		err = mcp251xfd_tef_obj_read(priv, &hw_tef_obj[l], 0, len - l);
2181e846c7aSMarc Kleine-Budde 		if (err)
2191e846c7aSMarc Kleine-Budde 			return err;
2201e846c7aSMarc Kleine-Budde 	}
2211e846c7aSMarc Kleine-Budde 
2221e846c7aSMarc Kleine-Budde 	for (i = 0; i < len; i++) {
2231e846c7aSMarc Kleine-Budde 		unsigned int frame_len = 0;
2241e846c7aSMarc Kleine-Budde 
2251e846c7aSMarc Kleine-Budde 		err = mcp251xfd_handle_tefif_one(priv, &hw_tef_obj[i], &frame_len);
2261e846c7aSMarc Kleine-Budde 		/* -EAGAIN means the Sequence Number in the TEF
2271e846c7aSMarc Kleine-Budde 		 * doesn't match our tef_tail. This can happen if we
2281e846c7aSMarc Kleine-Budde 		 * read the TEF objects too early. Leave loop let the
2291e846c7aSMarc Kleine-Budde 		 * interrupt handler call us again.
2301e846c7aSMarc Kleine-Budde 		 */
2311e846c7aSMarc Kleine-Budde 		if (err == -EAGAIN)
2321e846c7aSMarc Kleine-Budde 			goto out_netif_wake_queue;
2331e846c7aSMarc Kleine-Budde 		if (err)
2341e846c7aSMarc Kleine-Budde 			return err;
2351e846c7aSMarc Kleine-Budde 
2361e846c7aSMarc Kleine-Budde 		total_frame_len += frame_len;
2371e846c7aSMarc Kleine-Budde 	}
2381e846c7aSMarc Kleine-Budde 
2391e846c7aSMarc Kleine-Budde out_netif_wake_queue:
2401e846c7aSMarc Kleine-Budde 	len = i;	/* number of handled goods TEFs */
2411e846c7aSMarc Kleine-Budde 	if (len) {
2421e846c7aSMarc Kleine-Budde 		struct mcp251xfd_tef_ring *ring = priv->tef;
2431e846c7aSMarc Kleine-Budde 		struct mcp251xfd_tx_ring *tx_ring = priv->tx;
2441e846c7aSMarc Kleine-Budde 		int offset;
2451e846c7aSMarc Kleine-Budde 
246*b8e0ddd3SMarc Kleine-Budde 		ring->head += len;
247*b8e0ddd3SMarc Kleine-Budde 
2481e846c7aSMarc Kleine-Budde 		/* Increment the TEF FIFO tail pointer 'len' times in
2491e846c7aSMarc Kleine-Budde 		 * a single SPI message.
2501e846c7aSMarc Kleine-Budde 		 *
2511e846c7aSMarc Kleine-Budde 		 * Note:
2521e846c7aSMarc Kleine-Budde 		 * Calculate offset, so that the SPI transfer ends on
2531e846c7aSMarc Kleine-Budde 		 * the last message of the uinc_xfer array, which has
2541e846c7aSMarc Kleine-Budde 		 * "cs_change == 0", to properly deactivate the chip
2551e846c7aSMarc Kleine-Budde 		 * select.
2561e846c7aSMarc Kleine-Budde 		 */
2571e846c7aSMarc Kleine-Budde 		offset = ARRAY_SIZE(ring->uinc_xfer) - len;
2581e846c7aSMarc Kleine-Budde 		err = spi_sync_transfer(priv->spi,
2591e846c7aSMarc Kleine-Budde 					ring->uinc_xfer + offset, len);
2601e846c7aSMarc Kleine-Budde 		if (err)
2611e846c7aSMarc Kleine-Budde 			return err;
2621e846c7aSMarc Kleine-Budde 
2631e846c7aSMarc Kleine-Budde 		tx_ring->tail += len;
2641e846c7aSMarc Kleine-Budde 		netdev_completed_queue(priv->ndev, len, total_frame_len);
2651e846c7aSMarc Kleine-Budde 
2661e846c7aSMarc Kleine-Budde 		err = mcp251xfd_check_tef_tail(priv);
2671e846c7aSMarc Kleine-Budde 		if (err)
2681e846c7aSMarc Kleine-Budde 			return err;
2691e846c7aSMarc Kleine-Budde 	}
2701e846c7aSMarc Kleine-Budde 
2711e846c7aSMarc Kleine-Budde 	mcp251xfd_ecc_tefif_successful(priv);
2721e846c7aSMarc Kleine-Budde 
2731e846c7aSMarc Kleine-Budde 	if (mcp251xfd_get_tx_free(priv->tx)) {
2741e846c7aSMarc Kleine-Budde 		/* Make sure that anybody stopping the queue after
2751e846c7aSMarc Kleine-Budde 		 * this sees the new tx_ring->tail.
2761e846c7aSMarc Kleine-Budde 		 */
2771e846c7aSMarc Kleine-Budde 		smp_mb();
2781e846c7aSMarc Kleine-Budde 		netif_wake_queue(priv->ndev);
2791e846c7aSMarc Kleine-Budde 	}
2801e846c7aSMarc Kleine-Budde 
281169d00a2SMarc Kleine-Budde 	if (priv->tx_coalesce_usecs_irq)
282169d00a2SMarc Kleine-Budde 		hrtimer_start(&priv->tx_irq_timer,
283169d00a2SMarc Kleine-Budde 			      ns_to_ktime(priv->tx_coalesce_usecs_irq *
284169d00a2SMarc Kleine-Budde 					  NSEC_PER_USEC),
285169d00a2SMarc Kleine-Budde 			      HRTIMER_MODE_REL);
286169d00a2SMarc Kleine-Budde 
2871e846c7aSMarc Kleine-Budde 	return 0;
2881e846c7aSMarc Kleine-Budde }
289