Commit ae44fa99 authored by Marc Kleine-Budde's avatar Marc Kleine-Budde
Browse files

Merge patch series "can: mcp251xfd: workaround for erratum DS80000789E 6 of mcp2518fd"

Marc Kleine-Budde <mkl@pengutronix.de> says:

This patch series tries to work around erratum DS80000789E 6 of the
mcp2518fd, found by Stefan Althöfer, the other variants of the chip
family (mcp2517fd and mcp251863) are probably also affected.

Erratum DS80000789E 6 says "reading of the FIFOCI bits in the FIFOSTA
register for an RX FIFO may be corrupted". However observation shows
that this problem is not limited to RX FIFOs but also effects the TEF
FIFO.

In the bad case, the driver reads a too large head index. In the
original code, the driver always trusted the read value.

For the RX FIDO this caused old, already processed CAN frames or new,
incompletely written CAN frames to be (re-)processed.

To work around this issue, keep a per FIFO timestamp of the last valid
received CAN frame and compare against the timestamp of every received
CAN frame.

Further tests showed that this workaround can recognize old CAN
frames, but a small time window remains in which partially written CAN
frames are not recognized but then processed. These CAN frames have
the correct data and time stamps, but the DLC has not yet been
updated.

For the TEF FIFO the original driver already detects the error, update
the error handling with the knowledge that it is causes by this erratum.

Link: https://lore.kernel.org/all/20240628-mcp251xfd-workaround-erratum-6-v4-0-53586f168524@pengutronix.de


Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parents 69e2326a 3a0a88fc
Loading
Loading
Loading
Loading
+43 −39
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
//
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
//
// Copyright (c) 2019, 2020, 2021 Pengutronix,
// Copyright (c) 2019, 2020, 2021, 2023 Pengutronix,
//               Marc Kleine-Budde <kernel@pengutronix.de>
//
// Based on:
@@ -744,6 +744,7 @@ static void mcp251xfd_chip_stop(struct mcp251xfd_priv *priv,

	mcp251xfd_chip_interrupts_disable(priv);
	mcp251xfd_chip_rx_int_disable(priv);
	mcp251xfd_timestamp_stop(priv);
	mcp251xfd_chip_sleep(priv);
}

@@ -763,6 +764,8 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv)
	if (err)
		goto out_chip_stop;

	mcp251xfd_timestamp_start(priv);

	err = mcp251xfd_set_bittiming(priv);
	if (err)
		goto out_chip_stop;
@@ -867,18 +870,18 @@ static int mcp251xfd_get_berr_counter(const struct net_device *ndev,

static struct sk_buff *
mcp251xfd_alloc_can_err_skb(struct mcp251xfd_priv *priv,
			    struct can_frame **cf, u32 *timestamp)
			    struct can_frame **cf, u32 *ts_raw)
{
	struct sk_buff *skb;
	int err;

	err = mcp251xfd_get_timestamp(priv, timestamp);
	err = mcp251xfd_get_timestamp_raw(priv, ts_raw);
	if (err)
		return NULL;

	skb = alloc_can_err_skb(priv->ndev, cf);
	if (skb)
		mcp251xfd_skb_set_timestamp(priv, skb, *timestamp);
		mcp251xfd_skb_set_timestamp_raw(priv, skb, *ts_raw);

	return skb;
}
@@ -889,7 +892,7 @@ static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv)
	struct mcp251xfd_rx_ring *ring;
	struct sk_buff *skb;
	struct can_frame *cf;
	u32 timestamp, rxovif;
	u32 ts_raw, rxovif;
	int err, i;

	stats->rx_over_errors++;
@@ -924,14 +927,14 @@ static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv)
			return err;
	}

	skb = mcp251xfd_alloc_can_err_skb(priv, &cf, &timestamp);
	skb = mcp251xfd_alloc_can_err_skb(priv, &cf, &ts_raw);
	if (!skb)
		return 0;

	cf->can_id |= CAN_ERR_CRTL;
	cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;

	err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
	err = can_rx_offload_queue_timestamp(&priv->offload, skb, ts_raw);
	if (err)
		stats->rx_fifo_errors++;

@@ -948,12 +951,12 @@ static int mcp251xfd_handle_txatif(struct mcp251xfd_priv *priv)
static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv)
{
	struct net_device_stats *stats = &priv->ndev->stats;
	u32 bdiag1, timestamp;
	u32 bdiag1, ts_raw;
	struct sk_buff *skb;
	struct can_frame *cf = NULL;
	int err;

	err = mcp251xfd_get_timestamp(priv, &timestamp);
	err = mcp251xfd_get_timestamp_raw(priv, &ts_raw);
	if (err)
		return err;

@@ -1035,8 +1038,8 @@ static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv)
	if (!cf)
		return 0;

	mcp251xfd_skb_set_timestamp(priv, skb, timestamp);
	err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
	mcp251xfd_skb_set_timestamp_raw(priv, skb, ts_raw);
	err = can_rx_offload_queue_timestamp(&priv->offload, skb, ts_raw);
	if (err)
		stats->rx_fifo_errors++;

@@ -1049,7 +1052,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv)
	struct sk_buff *skb;
	struct can_frame *cf = NULL;
	enum can_state new_state, rx_state, tx_state;
	u32 trec, timestamp;
	u32 trec, ts_raw;
	int err;

	err = regmap_read(priv->map_reg, MCP251XFD_REG_TREC, &trec);
@@ -1079,7 +1082,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv)
	/* The skb allocation might fail, but can_change_state()
	 * handles cf == NULL.
	 */
	skb = mcp251xfd_alloc_can_err_skb(priv, &cf, &timestamp);
	skb = mcp251xfd_alloc_can_err_skb(priv, &cf, &ts_raw);
	can_change_state(priv->ndev, cf, tx_state, rx_state);

	if (new_state == CAN_STATE_BUS_OFF) {
@@ -1110,7 +1113,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv)
		cf->data[7] = bec.rxerr;
	}

	err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
	err = can_rx_offload_queue_timestamp(&priv->offload, skb, ts_raw);
	if (err)
		stats->rx_fifo_errors++;

@@ -1135,7 +1138,7 @@ mcp251xfd_handle_modif(const struct mcp251xfd_priv *priv, bool *set_normal_mode)
		return 0;
	}

	/* According to MCP2517FD errata DS80000792B 1., during a TX
	/* According to MCP2517FD errata DS80000792C 1., during a TX
	 * MAB underflow, the controller will transition to Restricted
	 * Operation Mode or Listen Only Mode (depending on SERR2LOM).
	 *
@@ -1180,7 +1183,7 @@ static int mcp251xfd_handle_serrif(struct mcp251xfd_priv *priv)

	/* TX MAB underflow
	 *
	 * According to MCP2517FD Errata DS80000792B 1. a TX MAB
	 * According to MCP2517FD Errata DS80000792C 1. a TX MAB
	 * underflow is indicated by SERRIF and MODIF.
	 *
	 * In addition to the effects mentioned in the Errata, there
@@ -1224,7 +1227,7 @@ static int mcp251xfd_handle_serrif(struct mcp251xfd_priv *priv)

	/* RX MAB overflow
	 *
	 * According to MCP2517FD Errata DS80000792B 1. a RX MAB
	 * According to MCP2517FD Errata DS80000792C 1. a RX MAB
	 * overflow is indicated by SERRIF.
	 *
	 * In addition to the effects mentioned in the Errata, (most
@@ -1331,7 +1334,8 @@ mcp251xfd_handle_eccif(struct mcp251xfd_priv *priv, bool set_normal_mode)
		return err;

	/* Errata Reference:
	 * mcp2517fd: DS80000789B, mcp2518fd: DS80000792C 2.
	 * mcp2517fd: DS80000789C 3., mcp2518fd: DS80000792E 2.,
	 * mcp251863: DS80000984A 2.
	 *
	 * ECC single error correction does not work in all cases:
	 *
@@ -1610,11 +1614,12 @@ static int mcp251xfd_open(struct net_device *ndev)
	if (err)
		goto out_mcp251xfd_ring_free;

	mcp251xfd_timestamp_init(priv);

	err = mcp251xfd_chip_start(priv);
	if (err)
		goto out_transceiver_disable;

	mcp251xfd_timestamp_init(priv);
	clear_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
	can_rx_offload_enable(&priv->offload);

@@ -1648,7 +1653,6 @@ static int mcp251xfd_open(struct net_device *ndev)
out_can_rx_offload_disable:
	can_rx_offload_disable(&priv->offload);
	set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
	mcp251xfd_timestamp_stop(priv);
out_transceiver_disable:
	mcp251xfd_transceiver_disable(priv);
out_mcp251xfd_ring_free:
@@ -1674,7 +1678,6 @@ static int mcp251xfd_stop(struct net_device *ndev)
	free_irq(ndev->irq, priv);
	destroy_workqueue(priv->wq);
	can_rx_offload_disable(&priv->offload);
	mcp251xfd_timestamp_stop(priv);
	mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
	mcp251xfd_transceiver_disable(priv);
	mcp251xfd_ring_free(priv);
@@ -2095,7 +2098,8 @@ static int mcp251xfd_probe(struct spi_device *spi)
	priv->devtype_data = *(struct mcp251xfd_devtype_data *)spi_get_device_match_data(spi);

	/* Errata Reference:
	 * mcp2517fd: DS80000792C 5., mcp2518fd: DS80000789C 4.
	 * mcp2517fd: DS80000792C 5., mcp2518fd: DS80000789E 4.,
	 * mcp251863: DS80000984A 4.
	 *
	 * The SPI can write corrupted data to the RAM at fast SPI
	 * speeds:
+5 −0
Original line number Diff line number Diff line
@@ -206,6 +206,7 @@ mcp251xfd_ring_init_rx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr)
	int i, j;

	mcp251xfd_for_each_rx_ring(priv, rx_ring, i) {
		rx_ring->last_valid = timecounter_read(&priv->tc);
		rx_ring->head = 0;
		rx_ring->tail = 0;
		rx_ring->base = *base;
@@ -485,6 +486,8 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
		clear_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags);
	}

	tx_ring->obj_num_shift_to_u8 = BITS_PER_TYPE(tx_ring->obj_num) -
		ilog2(tx_ring->obj_num);
	tx_ring->obj_size = tx_obj_size;

	rem = priv->rx_obj_num;
@@ -507,6 +510,8 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
		}

		rx_ring->obj_num = rx_obj_num;
		rx_ring->obj_num_shift_to_u8 = BITS_PER_TYPE(rx_ring->obj_num_shift_to_u8) -
			ilog2(rx_obj_num);
		rx_ring->obj_size = rx_obj_size;
		priv->rx[i] = rx_ring;
	}
+111 −54
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
//
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
//
// Copyright (c) 2019, 2020, 2021 Pengutronix,
// Copyright (c) 2019, 2020, 2021, 2023 Pengutronix,
//               Marc Kleine-Budde <kernel@pengutronix.de>
//
// Based on:
@@ -16,23 +16,14 @@

#include "mcp251xfd.h"

static inline int
mcp251xfd_rx_head_get_from_chip(const struct mcp251xfd_priv *priv,
				const struct mcp251xfd_rx_ring *ring,
				u8 *rx_head, bool *fifo_empty)
static inline bool mcp251xfd_rx_fifo_sta_empty(const u32 fifo_sta)
{
	u32 fifo_sta;
	int err;

	err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(ring->fifo_nr),
			  &fifo_sta);
	if (err)
		return err;

	*rx_head = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);
	*fifo_empty = !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
	return !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
}

	return 0;
static inline bool mcp251xfd_rx_fifo_sta_full(const u32 fifo_sta)
{
	return fifo_sta & MCP251XFD_REG_FIFOSTA_TFERFFIF;
}

static inline int
@@ -80,29 +71,49 @@ mcp251xfd_check_rx_tail(const struct mcp251xfd_priv *priv,
}

static int
mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv,
			 struct mcp251xfd_rx_ring *ring)
mcp251xfd_get_rx_len(const struct mcp251xfd_priv *priv,
		     const struct mcp251xfd_rx_ring *ring,
		     u8 *len_p)
{
	u32 new_head;
	u8 chip_rx_head;
	bool fifo_empty;
	const u8 shift = ring->obj_num_shift_to_u8;
	u8 chip_head, tail, len;
	u32 fifo_sta;
	int err;

	err = mcp251xfd_rx_head_get_from_chip(priv, ring, &chip_rx_head,
					      &fifo_empty);
	if (err || fifo_empty)
	err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(ring->fifo_nr),
			  &fifo_sta);
	if (err)
		return err;

	if (mcp251xfd_rx_fifo_sta_empty(fifo_sta)) {
		*len_p = 0;
		return 0;
	}

	if (mcp251xfd_rx_fifo_sta_full(fifo_sta)) {
		*len_p = ring->obj_num;
		return 0;
	}

	chip_head = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);

	err =  mcp251xfd_check_rx_tail(priv, ring);
	if (err)
		return err;
	tail = mcp251xfd_get_rx_tail(ring);

	/* chip_rx_head, is the next RX-Object filled by the HW.
	 * The new RX head must be >= the old head.
	/* 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.
	 */
	new_head = round_down(ring->head, ring->obj_num) + chip_rx_head;
	if (new_head <= ring->head)
		new_head += ring->obj_num;
	BUILD_BUG_ON(sizeof(ring->obj_num) != sizeof(chip_head));
	BUILD_BUG_ON(sizeof(ring->obj_num) != sizeof(tail));
	BUILD_BUG_ON(sizeof(ring->obj_num) != sizeof(len));

	ring->head = new_head;
	len = (chip_head << shift) - (tail << shift);
	*len_p = len >> shift;

	return mcp251xfd_check_rx_tail(priv, ring);
	return 0;
}

static void
@@ -148,8 +159,6 @@ mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv,

	if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR))
		memcpy(cfd->data, hw_rx_obj->data, cfd->len);

	mcp251xfd_skb_set_timestamp(priv, skb, hw_rx_obj->ts);
}

static int
@@ -160,8 +169,26 @@ mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
	struct net_device_stats *stats = &priv->ndev->stats;
	struct sk_buff *skb;
	struct canfd_frame *cfd;
	u64 timestamp;
	int err;

	/* According to mcp2518fd erratum DS80000789E 6. the FIFOCI
	 * bits of a FIFOSTA register, here the RX FIFO head index
	 * might be corrupted and we might process past the RX FIFO's
	 * head into old CAN frames.
	 *
	 * Compare the timestamp of currently processed CAN frame with
	 * last valid frame received. Abort with -EBADMSG if an old
	 * CAN frame is detected.
	 */
	timestamp = timecounter_cyc2time(&priv->tc, hw_rx_obj->ts);
	if (timestamp <= ring->last_valid) {
		stats->rx_fifo_errors++;

		return -EBADMSG;
	}
	ring->last_valid = timestamp;

	if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF)
		skb = alloc_canfd_skb(priv->ndev, &cfd);
	else
@@ -172,6 +199,7 @@ mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
		return 0;
	}

	mcp251xfd_skb_set_timestamp(skb, timestamp);
	mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb);
	err = can_rx_offload_queue_timestamp(&priv->offload, skb, hw_rx_obj->ts);
	if (err)
@@ -197,52 +225,81 @@ mcp251xfd_rx_obj_read(const struct mcp251xfd_priv *priv,
	return err;
}

static int
mcp251xfd_handle_rxif_ring_uinc(const struct mcp251xfd_priv *priv,
				struct mcp251xfd_rx_ring *ring,
				u8 len)
{
	int offset;
	int err;

	if (!len)
		return 0;

	ring->head += len;

	/* Increment the RX FIFO tail pointer 'len' times in a
	 * single SPI message.
	 *
	 * Note:
	 * Calculate offset, so that the SPI transfer ends on
	 * the last message of the uinc_xfer array, which has
	 * "cs_change == 0", to properly deactivate the chip
	 * select.
	 */
	offset = ARRAY_SIZE(ring->uinc_xfer) - len;
	err = spi_sync_transfer(priv->spi,
				ring->uinc_xfer + offset, len);
	if (err)
		return err;

	ring->tail += len;

	return 0;
}

static int
mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
			   struct mcp251xfd_rx_ring *ring)
{
	struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj = ring->obj;
	u8 rx_tail, len;
	u8 rx_tail, len, l;
	int err, i;

	err = mcp251xfd_rx_ring_update(priv, ring);
	err = mcp251xfd_get_rx_len(priv, ring, &len);
	if (err)
		return err;

	while ((len = mcp251xfd_get_rx_linear_len(ring))) {
		int offset;

	while ((l = mcp251xfd_get_rx_linear_len(ring, len))) {
		rx_tail = mcp251xfd_get_rx_tail(ring);

		err = mcp251xfd_rx_obj_read(priv, ring, hw_rx_obj,
					    rx_tail, len);
					    rx_tail, l);
		if (err)
			return err;

		for (i = 0; i < len; i++) {
		for (i = 0; i < l; i++) {
			err = mcp251xfd_handle_rxif_one(priv, ring,
							(void *)hw_rx_obj +
							i * ring->obj_size);
			if (err)

			/* -EBADMSG means we're affected by mcp2518fd
			 * erratum DS80000789E 6., i.e. the timestamp
			 * in the RX object is older that the last
			 * valid received CAN frame. Don't process any
			 * further and mark processed frames as good.
			 */
			if (err == -EBADMSG)
				return mcp251xfd_handle_rxif_ring_uinc(priv, ring, i);
			else if (err)
				return err;
		}

		/* Increment the RX FIFO tail pointer 'len' times in a
		 * single SPI message.
		 *
		 * Note:
		 * Calculate offset, so that the SPI transfer ends on
		 * the last message of the uinc_xfer array, which has
		 * "cs_change == 0", to properly deactivate the chip
		 * select.
		 */
		offset = ARRAY_SIZE(ring->uinc_xfer) - len;
		err = spi_sync_transfer(priv->spi,
					ring->uinc_xfer + offset, len);
		err = mcp251xfd_handle_rxif_ring_uinc(priv, ring, l);
		if (err)
			return err;

		ring->tail += len;
		len -= l;
	}

	return 0;
+67 −62
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
//
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
//
// Copyright (c) 2019, 2020, 2021 Pengutronix,
// Copyright (c) 2019, 2020, 2021, 2023 Pengutronix,
//               Marc Kleine-Budde <kernel@pengutronix.de>
//
// Based on:
@@ -16,6 +16,11 @@

#include "mcp251xfd.h"

static inline bool mcp251xfd_tx_fifo_sta_full(u32 fifo_sta)
{
	return !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
}

static inline int
mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv,
				 u8 *tef_tail)
@@ -55,61 +60,44 @@ static int mcp251xfd_check_tef_tail(const struct mcp251xfd_priv *priv)
	return 0;
}

static int
mcp251xfd_handle_tefif_recover(const struct mcp251xfd_priv *priv, const u32 seq)
{
	const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
	u32 tef_sta;
	int err;

	err = regmap_read(priv->map_reg, MCP251XFD_REG_TEFSTA, &tef_sta);
	if (err)
		return err;

	if (tef_sta & MCP251XFD_REG_TEFSTA_TEFOVIF) {
		netdev_err(priv->ndev,
			   "Transmit Event FIFO buffer overflow.\n");
		return -ENOBUFS;
	}

	netdev_info(priv->ndev,
		    "Transmit Event FIFO buffer %s. (seq=0x%08x, tef_tail=0x%08x, tef_head=0x%08x, tx_head=0x%08x).\n",
		    tef_sta & MCP251XFD_REG_TEFSTA_TEFFIF ?
		    "full" : tef_sta & MCP251XFD_REG_TEFSTA_TEFNEIF ?
		    "not empty" : "empty",
		    seq, priv->tef->tail, priv->tef->head, tx_ring->head);

	/* The Sequence Number in the TEF doesn't match our tef_tail. */
	return -EAGAIN;
}

static int
mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
			   const struct mcp251xfd_hw_tef_obj *hw_tef_obj,
			   unsigned int *frame_len_ptr)
{
	struct net_device_stats *stats = &priv->ndev->stats;
	u32 seq, tef_tail_masked, tef_tail;
	struct sk_buff *skb;
	u32 seq, seq_masked, tef_tail_masked, tef_tail;

	seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK,
			hw_tef_obj->flags);

	 /* Use the MCP2517FD mask on the MCP2518FD, too. We only
	 * compare 7 bits, this should be enough to detect
	 * net-yet-completed, i.e. old TEF objects.
	  * compare 7 bits, this is enough to detect old TEF objects.
	  */
	seq_masked = seq &
		field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK);
	seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK,
			hw_tef_obj->flags);
	tef_tail_masked = priv->tef->tail &
		field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK);
	if (seq_masked != tef_tail_masked)
		return mcp251xfd_handle_tefif_recover(priv, seq);

	/* According to mcp2518fd erratum DS80000789E 6. the FIFOCI
	 * bits of a FIFOSTA register, here the TX FIFO tail index
	 * might be corrupted and we might process past the TEF FIFO's
	 * head into old CAN frames.
	 *
	 * Compare the sequence number of the currently processed CAN
	 * frame with the expected sequence number. Abort with
	 * -EBADMSG if an old CAN frame is detected.
	 */
	if (seq != tef_tail_masked) {
		netdev_dbg(priv->ndev, "%s: chip=0x%02x ring=0x%02x\n", __func__,
			   seq, tef_tail_masked);
		stats->tx_fifo_errors++;

		return -EBADMSG;
	}

	tef_tail = mcp251xfd_get_tef_tail(priv);
	skb = priv->can.echo_skb[tef_tail];
	if (skb)
		mcp251xfd_skb_set_timestamp(priv, skb, hw_tef_obj->ts);
		mcp251xfd_skb_set_timestamp_raw(priv, skb, hw_tef_obj->ts);
	stats->tx_bytes +=
		can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload,
							    tef_tail, hw_tef_obj->ts,
@@ -120,28 +108,44 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
	return 0;
}

static int mcp251xfd_tef_ring_update(struct mcp251xfd_priv *priv)
static int
mcp251xfd_get_tef_len(struct mcp251xfd_priv *priv, u8 *len_p)
{
	const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
	unsigned int new_head;
	u8 chip_tx_tail;
	const u8 shift = tx_ring->obj_num_shift_to_u8;
	u8 chip_tx_tail, tail, len;
	u32 fifo_sta;
	int err;

	err = mcp251xfd_tx_tail_get_from_chip(priv, &chip_tx_tail);
	err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(priv->tx->fifo_nr),
			  &fifo_sta);
	if (err)
		return err;

	if (mcp251xfd_tx_fifo_sta_full(fifo_sta)) {
		*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);

	/* chip_tx_tail, is the next TX-Object send by the HW.
	 * The new TEF head must be >= the old head, ...
	/* 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.
	 */
	new_head = round_down(priv->tef->head, tx_ring->obj_num) + chip_tx_tail;
	if (new_head <= priv->tef->head)
		new_head += tx_ring->obj_num;
	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));

	/* ... but it cannot exceed the TX head. */
	priv->tef->head = min(new_head, tx_ring->head);
	len = (chip_tx_tail << shift) - (tail << shift);
	*len_p = len >> shift;

	return mcp251xfd_check_tef_tail(priv);
	return 0;
}

static inline int
@@ -182,13 +186,12 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
	u8 tef_tail, len, l;
	int err, i;

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

	tef_tail = mcp251xfd_get_tef_tail(priv);
	len = mcp251xfd_get_tef_len(priv);
	l = mcp251xfd_get_tef_linear_len(priv);
	l = mcp251xfd_get_tef_linear_len(priv, len);
	err = mcp251xfd_tef_obj_read(priv, hw_tef_obj, tef_tail, l);
	if (err)
		return err;
@@ -203,12 +206,12 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
		unsigned int frame_len = 0;

		err = mcp251xfd_handle_tefif_one(priv, &hw_tef_obj[i], &frame_len);
		/* -EAGAIN means the Sequence Number in the TEF
		 * doesn't match our tef_tail. This can happen if we
		 * read the TEF objects too early. Leave loop let the
		 * interrupt handler call us again.
		/* -EBADMSG means we're affected by mcp2518fd erratum
		 * DS80000789E 6., i.e. the Sequence Number in the TEF
		 * doesn't match our tef_tail. Don't process any
		 * further and mark processed frames as good.
		 */
		if (err == -EAGAIN)
		if (err == -EBADMSG)
			goto out_netif_wake_queue;
		if (err)
			return err;
@@ -223,6 +226,8 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
		struct mcp251xfd_tx_ring *tx_ring = priv->tx;
		int offset;

		ring->head += len;

		/* Increment the TEF FIFO tail pointer 'len' times in
		 * a single SPI message.
		 *
+11 −18
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
//
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
//
// Copyright (c) 2021 Pengutronix,
// Copyright (c) 2021, 2023 Pengutronix,
//               Marc Kleine-Budde <kernel@pengutronix.de>
//

@@ -11,20 +11,20 @@

#include "mcp251xfd.h"

static u64 mcp251xfd_timestamp_read(const struct cyclecounter *cc)
static u64 mcp251xfd_timestamp_raw_read(const struct cyclecounter *cc)
{
	const struct mcp251xfd_priv *priv;
	u32 timestamp = 0;
	u32 ts_raw = 0;
	int err;

	priv = container_of(cc, struct mcp251xfd_priv, cc);
	err = mcp251xfd_get_timestamp(priv, &timestamp);
	err = mcp251xfd_get_timestamp_raw(priv, &ts_raw);
	if (err)
		netdev_err(priv->ndev,
			   "Error %d while reading timestamp. HW timestamps may be inaccurate.",
			   err);

	return timestamp;
	return ts_raw;
}

static void mcp251xfd_timestamp_work(struct work_struct *work)
@@ -39,28 +39,21 @@ static void mcp251xfd_timestamp_work(struct work_struct *work)
			      MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ);
}

void mcp251xfd_skb_set_timestamp(const struct mcp251xfd_priv *priv,
				 struct sk_buff *skb, u32 timestamp)
{
	struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
	u64 ns;

	ns = timecounter_cyc2time(&priv->tc, timestamp);
	hwtstamps->hwtstamp = ns_to_ktime(ns);
}

void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv)
{
	struct cyclecounter *cc = &priv->cc;

	cc->read = mcp251xfd_timestamp_read;
	cc->read = mcp251xfd_timestamp_raw_read;
	cc->mask = CYCLECOUNTER_MASK(32);
	cc->shift = 1;
	cc->mult = clocksource_hz2mult(priv->can.clock.freq, cc->shift);

	timecounter_init(&priv->tc, &priv->cc, ktime_get_real_ns());

	INIT_DELAYED_WORK(&priv->timestamp, mcp251xfd_timestamp_work);
}

void mcp251xfd_timestamp_start(struct mcp251xfd_priv *priv)
{
	timecounter_init(&priv->tc, &priv->cc, ktime_get_real_ns());
	schedule_delayed_work(&priv->timestamp,
			      MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ);
}
Loading