brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · d3ac865 Raw
276 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// mcp251xfd - Microchip MCP251xFD Family CAN controller driver4//5// Copyright (c) 2019, 2020, 2021, 2023 Pengutronix,6//               Marc Kleine-Budde <kernel@pengutronix.de>7//8// Based on:9//10// CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface11//12// Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>13//14 15#include <linux/bitfield.h>16 17#include "mcp251xfd.h"18 19static inline bool mcp251xfd_tx_fifo_sta_empty(u32 fifo_sta)20{21	return fifo_sta & MCP251XFD_REG_FIFOSTA_TFERFFIF;22}23 24static inline int25mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv,26				 u8 *tef_tail)27{28	u32 tef_ua;29	int err;30 31	err = regmap_read(priv->map_reg, MCP251XFD_REG_TEFUA, &tef_ua);32	if (err)33		return err;34 35	*tef_tail = tef_ua / sizeof(struct mcp251xfd_hw_tef_obj);36 37	return 0;38}39 40static int mcp251xfd_check_tef_tail(const struct mcp251xfd_priv *priv)41{42	u8 tef_tail_chip, tef_tail;43	int err;44 45	if (!IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY))46		return 0;47 48	err = mcp251xfd_tef_tail_get_from_chip(priv, &tef_tail_chip);49	if (err)50		return err;51 52	tef_tail = mcp251xfd_get_tef_tail(priv);53	if (tef_tail_chip != tef_tail) {54		netdev_err(priv->ndev,55			   "TEF tail of chip (0x%02x) and ours (0x%08x) inconsistent.\n",56			   tef_tail_chip, tef_tail);57		return -EILSEQ;58	}59 60	return 0;61}62 63static int64mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,65			   const struct mcp251xfd_hw_tef_obj *hw_tef_obj,66			   unsigned int *frame_len_ptr)67{68	struct net_device_stats *stats = &priv->ndev->stats;69	u32 seq, tef_tail_masked, tef_tail;70	struct sk_buff *skb;71 72	 /* Use the MCP2517FD mask on the MCP2518FD, too. We only73	  * compare 7 bits, this is enough to detect old TEF objects.74	  */75	seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK,76			hw_tef_obj->flags);77	tef_tail_masked = priv->tef->tail &78		field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK);79 80	/* According to mcp2518fd erratum DS80000789E 6. the FIFOCI81	 * bits of a FIFOSTA register, here the TX FIFO tail index82	 * might be corrupted and we might process past the TEF FIFO's83	 * head into old CAN frames.84	 *85	 * Compare the sequence number of the currently processed CAN86	 * frame with the expected sequence number. Abort with87	 * -EBADMSG if an old CAN frame is detected.88	 */89	if (seq != tef_tail_masked) {90		netdev_dbg(priv->ndev, "%s: chip=0x%02x ring=0x%02x\n", __func__,91			   seq, tef_tail_masked);92		stats->tx_fifo_errors++;93 94		return -EBADMSG;95	}96 97	tef_tail = mcp251xfd_get_tef_tail(priv);98	skb = priv->can.echo_skb[tef_tail];99	if (skb)100		mcp251xfd_skb_set_timestamp_raw(priv, skb, hw_tef_obj->ts);101	stats->tx_bytes +=102		can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload,103							    tef_tail, hw_tef_obj->ts,104							    frame_len_ptr);105	stats->tx_packets++;106	priv->tef->tail++;107 108	return 0;109}110 111static int112mcp251xfd_get_tef_len(struct mcp251xfd_priv *priv, u8 *len_p)113{114	const struct mcp251xfd_tx_ring *tx_ring = priv->tx;115	const u8 shift = tx_ring->obj_num_shift_to_u8;116	u8 chip_tx_tail, tail, len;117	u32 fifo_sta;118	int err;119 120	err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(priv->tx->fifo_nr),121			  &fifo_sta);122	if (err)123		return err;124 125	/* If the chip says the TX-FIFO is empty, but there are no TX126	 * buffers free in the ring, we assume all have been sent.127	 */128	if (mcp251xfd_tx_fifo_sta_empty(fifo_sta) &&129	    mcp251xfd_get_tx_free(tx_ring) == 0) {130		*len_p = tx_ring->obj_num;131		return 0;132	}133 134	chip_tx_tail = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);135 136	err =  mcp251xfd_check_tef_tail(priv);137	if (err)138		return err;139	tail = mcp251xfd_get_tef_tail(priv);140 141	/* First shift to full u8. The subtraction works on signed142	 * values, that keeps the difference steady around the u8143	 * overflow. The right shift acts on len, which is an u8.144	 */145	BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(chip_tx_tail));146	BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(tail));147	BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(len));148 149	len = (chip_tx_tail << shift) - (tail << shift);150	*len_p = len >> shift;151 152	return 0;153}154 155static inline int156mcp251xfd_tef_obj_read(const struct mcp251xfd_priv *priv,157		       struct mcp251xfd_hw_tef_obj *hw_tef_obj,158		       const u8 offset, const u8 len)159{160	const struct mcp251xfd_tx_ring *tx_ring = priv->tx;161	const int val_bytes = regmap_get_val_bytes(priv->map_rx);162 163	if (IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY) &&164	    (offset > tx_ring->obj_num ||165	     len > tx_ring->obj_num ||166	     offset + len > tx_ring->obj_num)) {167		netdev_err(priv->ndev,168			   "Trying to read too many TEF objects (max=%d, offset=%d, len=%d).\n",169			   tx_ring->obj_num, offset, len);170		return -ERANGE;171	}172 173	return regmap_bulk_read(priv->map_rx,174				mcp251xfd_get_tef_obj_addr(offset),175				hw_tef_obj,176				sizeof(*hw_tef_obj) / val_bytes * len);177}178 179static inline void mcp251xfd_ecc_tefif_successful(struct mcp251xfd_priv *priv)180{181	struct mcp251xfd_ecc *ecc = &priv->ecc;182 183	ecc->ecc_stat = 0;184}185 186int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)187{188	struct mcp251xfd_hw_tef_obj hw_tef_obj[MCP251XFD_TX_OBJ_NUM_MAX];189	unsigned int total_frame_len = 0;190	u8 tef_tail, len, l;191	int err, i;192 193	err = mcp251xfd_get_tef_len(priv, &len);194	if (err)195		return err;196 197	tef_tail = mcp251xfd_get_tef_tail(priv);198	l = mcp251xfd_get_tef_linear_len(priv, len);199	err = mcp251xfd_tef_obj_read(priv, hw_tef_obj, tef_tail, l);200	if (err)201		return err;202 203	if (l < len) {204		err = mcp251xfd_tef_obj_read(priv, &hw_tef_obj[l], 0, len - l);205		if (err)206			return err;207	}208 209	for (i = 0; i < len; i++) {210		unsigned int frame_len = 0;211 212		err = mcp251xfd_handle_tefif_one(priv, &hw_tef_obj[i], &frame_len);213		/* -EBADMSG means we're affected by mcp2518fd erratum214		 * DS80000789E 6., i.e. the Sequence Number in the TEF215		 * doesn't match our tef_tail. Don't process any216		 * further and mark processed frames as good.217		 */218		if (err == -EBADMSG)219			goto out_netif_wake_queue;220		if (err)221			return err;222 223		total_frame_len += frame_len;224	}225 226out_netif_wake_queue:227	len = i;	/* number of handled goods TEFs */228	if (len) {229		struct mcp251xfd_tef_ring *ring = priv->tef;230		struct mcp251xfd_tx_ring *tx_ring = priv->tx;231		int offset;232 233		ring->head += len;234 235		/* Increment the TEF FIFO tail pointer 'len' times in236		 * a single SPI message.237		 *238		 * Note:239		 * Calculate offset, so that the SPI transfer ends on240		 * the last message of the uinc_xfer array, which has241		 * "cs_change == 0", to properly deactivate the chip242		 * select.243		 */244		offset = ARRAY_SIZE(ring->uinc_xfer) - len;245		err = spi_sync_transfer(priv->spi,246					ring->uinc_xfer + offset, len);247		if (err)248			return err;249 250		tx_ring->tail += len;251		netdev_completed_queue(priv->ndev, len, total_frame_len);252 253		err = mcp251xfd_check_tef_tail(priv);254		if (err)255			return err;256	}257 258	mcp251xfd_ecc_tefif_successful(priv);259 260	if (mcp251xfd_get_tx_free(priv->tx)) {261		/* Make sure that anybody stopping the queue after262		 * this sees the new tx_ring->tail.263		 */264		smp_mb();265		netif_wake_queue(priv->ndev);266	}267 268	if (priv->tx_coalesce_usecs_irq)269		hrtimer_start(&priv->tx_irq_timer,270			      ns_to_ktime(priv->tx_coalesce_usecs_irq *271					  NSEC_PER_USEC),272			      HRTIMER_MODE_REL);273 274	return 0;275}276