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

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.deSigned-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parents 69e2326a 3a0a88fc
......@@ -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;
......@@ -791,7 +794,7 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv)
return 0;
out_chip_stop:
out_chip_stop:
mcp251xfd_dump(priv);
mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
......@@ -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:
*
......@@ -1576,7 +1580,7 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
handled = IRQ_HANDLED;
} while (1);
out_fail:
out_fail:
can_rx_offload_threaded_irq_finish(&priv->offload);
netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n",
......@@ -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);
......@@ -1641,22 +1646,21 @@ static int mcp251xfd_open(struct net_device *ndev)
return 0;
out_free_irq:
out_free_irq:
free_irq(spi->irq, priv);
out_destroy_workqueue:
out_destroy_workqueue:
destroy_workqueue(priv->wq);
out_can_rx_offload_disable:
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:
out_transceiver_disable:
mcp251xfd_transceiver_disable(priv);
out_mcp251xfd_ring_free:
out_mcp251xfd_ring_free:
mcp251xfd_ring_free(priv);
out_pm_runtime_put:
out_pm_runtime_put:
mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
pm_runtime_put(ndev->dev.parent);
out_close_candev:
out_close_candev:
close_candev(ndev);
return err;
......@@ -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);
......@@ -1820,9 +1823,9 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id,
*effective_speed_hz_slow = xfer[0].effective_speed_hz;
*effective_speed_hz_fast = xfer[1].effective_speed_hz;
out_kfree_buf_tx:
out_kfree_buf_tx:
kfree(buf_tx);
out_kfree_buf_rx:
out_kfree_buf_rx:
kfree(buf_rx);
return err;
......@@ -1936,13 +1939,13 @@ static int mcp251xfd_register(struct mcp251xfd_priv *priv)
return 0;
out_unregister_candev:
out_unregister_candev:
unregister_candev(ndev);
out_chip_sleep:
out_chip_sleep:
mcp251xfd_chip_sleep(priv);
out_runtime_disable:
out_runtime_disable:
pm_runtime_disable(ndev->dev.parent);
out_runtime_put_noidle:
out_runtime_put_noidle:
pm_runtime_put_noidle(ndev->dev.parent);
mcp251xfd_clks_and_vdd_disable(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:
......@@ -2155,9 +2159,9 @@ static int mcp251xfd_probe(struct spi_device *spi)
return 0;
out_can_rx_offload_del:
out_can_rx_offload_del:
can_rx_offload_del(&priv->offload);
out_free_candev:
out_free_candev:
spi->max_speed_hz = priv->spi_max_speed_hz_orig;
free_candev(ndev);
......
......@@ -94,7 +94,7 @@ static void mcp251xfd_dump_registers(const struct mcp251xfd_priv *priv,
kfree(buf);
}
out:
out:
mcp251xfd_dump_header(iter, MCP251XFD_DUMP_OBJECT_TYPE_REG, reg);
}
......
......@@ -397,7 +397,7 @@ mcp251xfd_regmap_crc_read(void *context,
return err;
}
out:
out:
memcpy(val_buf, buf_rx->data, val_len);
return 0;
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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,
/* Use the MCP2517FD mask on the MCP2518FD, too. We only
* compare 7 bits, this is enough to detect old TEF objects.
*/
seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_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.
*/
seq_masked = seq &
field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK);
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;
/* chip_tx_tail, is the next TX-Object send by the HW.
* The new TEF head must be >= the old head, ...
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);
/* 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;
......@@ -216,13 +219,15 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
total_frame_len += frame_len;
}
out_netif_wake_queue:
out_netif_wake_queue:
len = i; /* number of handled goods TEFs */
if (len) {
struct mcp251xfd_tef_ring *ring = priv->tef;
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.
*
......
......@@ -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);
}
......
......@@ -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>
* Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
*/
......@@ -524,6 +524,7 @@ struct mcp251xfd_tef_ring {
/* u8 obj_num equals tx_ring->obj_num */
/* u8 obj_size equals sizeof(struct mcp251xfd_hw_tef_obj) */
/* u8 obj_num_shift_to_u8 equals tx_ring->obj_num_shift_to_u8 */
union mcp251xfd_write_reg_buf irq_enable_buf;
struct spi_transfer irq_enable_xfer;
......@@ -542,6 +543,7 @@ struct mcp251xfd_tx_ring {
u8 nr;
u8 fifo_nr;
u8 obj_num;
u8 obj_num_shift_to_u8;
u8 obj_size;
struct mcp251xfd_tx_obj obj[MCP251XFD_TX_OBJ_NUM_MAX];
......@@ -552,10 +554,14 @@ struct mcp251xfd_rx_ring {
unsigned int head;
unsigned int tail;
/* timestamp of the last valid received CAN frame */
u64 last_valid;
u16 base;
u8 nr;
u8 fifo_nr;
u8 obj_num;
u8 obj_num_shift_to_u8;
u8 obj_size;
union mcp251xfd_write_reg_buf irq_enable_buf;
......@@ -809,10 +815,27 @@ mcp251xfd_spi_cmd_write(const struct mcp251xfd_priv *priv,
return data;
}
static inline int mcp251xfd_get_timestamp(const struct mcp251xfd_priv *priv,
u32 *timestamp)
static inline int mcp251xfd_get_timestamp_raw(const struct mcp251xfd_priv *priv,
u32 *ts_raw)
{
return regmap_read(priv->map_reg, MCP251XFD_REG_TBC, ts_raw);
}
static inline void mcp251xfd_skb_set_timestamp(struct sk_buff *skb, u64 ns)
{
return regmap_read(priv->map_reg, MCP251XFD_REG_TBC, timestamp);
struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
hwtstamps->hwtstamp = ns_to_ktime(ns);
}
static inline
void mcp251xfd_skb_set_timestamp_raw(const struct mcp251xfd_priv *priv,
struct sk_buff *skb, u32 ts_raw)
{
u64 ns;
ns = timecounter_cyc2time(&priv->tc, ts_raw);
mcp251xfd_skb_set_timestamp(skb, ns);
}
static inline u16 mcp251xfd_get_tef_obj_addr(u8 n)
......@@ -861,17 +884,8 @@ static inline u8 mcp251xfd_get_tef_tail(const struct mcp251xfd_priv *priv)
return priv->tef->tail & (priv->tx->obj_num - 1);
}
static inline u8 mcp251xfd_get_tef_len(const struct mcp251xfd_priv *priv)
static inline u8 mcp251xfd_get_tef_linear_len(const struct mcp251xfd_priv *priv, u8 len)
{
return priv->tef->head - priv->tef->tail;
}
static inline u8 mcp251xfd_get_tef_linear_len(const struct mcp251xfd_priv *priv)
{
u8 len;
len = mcp251xfd_get_tef_len(priv);
return min_t(u8, len, priv->tx->obj_num - mcp251xfd_get_tef_tail(priv));
}
......@@ -914,18 +928,9 @@ static inline u8 mcp251xfd_get_rx_tail(const struct mcp251xfd_rx_ring *ring)
return ring->tail & (ring->obj_num - 1);
}
static inline u8 mcp251xfd_get_rx_len(const struct mcp251xfd_rx_ring *ring)
{
return ring->head - ring->tail;
}
static inline u8
mcp251xfd_get_rx_linear_len(const struct mcp251xfd_rx_ring *ring)
mcp251xfd_get_rx_linear_len(const struct mcp251xfd_rx_ring *ring, u8 len)
{
u8 len;
len = mcp251xfd_get_rx_len(ring);
return min_t(u8, len, ring->obj_num - mcp251xfd_get_rx_tail(ring));
}
......@@ -951,9 +956,8 @@ void mcp251xfd_ring_free(struct mcp251xfd_priv *priv);
int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv);
int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv);
int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv);
void mcp251xfd_skb_set_timestamp(const struct mcp251xfd_priv *priv,
struct sk_buff *skb, u32 timestamp);
void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv);
void mcp251xfd_timestamp_start(struct mcp251xfd_priv *priv);
void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv);
void mcp251xfd_tx_obj_write_sync(struct work_struct *work);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment