Commit 1eea11e9 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'linux-can-next-for-6.11-20240629' of...

Merge tag 'linux-can-next-for-6.11-20240629' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next

Marc Kleine-Budde says:

====================
pull-request: can-next 2024-06-29

Geert Uytterhoeven contributes 3 patches with small improvements and
cleanups for the rcar_canfd driver.

A patch by Christophe JAILLET constifies the struct m_can_ops in the
m_can driver to reduce the code size.

The last 9 patches are by me an work around erratum DS80000789E 6 of
mcp2518fd.

* tag 'linux-can-next-for-6.11-20240629' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next:
  can: mcp251xfd: tef: update workaround for erratum DS80000789E 6 of mcp2518fd
  can: mcp251xfd: tef: prepare to workaround broken TEF FIFO tail index erratum
  can: mcp251xfd: rx: add workaround for erratum DS80000789E 6 of mcp2518fd
  can: mcp251xfd: rx: prepare to workaround broken RX FIFO head index erratum
  can: mcp251xfd: mcp251xfd_handle_rxif_ring_uinc(): factor out in separate function
  can: mcp251xfd: clarify the meaning of timestamp
  can: mcp251xfd: move mcp251xfd_timestamp_start()/stop() into mcp251xfd_chip_start/stop()
  can: mcp251xfd: update errata references
  can: mcp251xfd: properly indent labels
  can: gs_usb: add VID/PID for Xylanta SAINT3 product family
  can: m_can: Constify struct m_can_ops
  can: rcar_canfd: Remove superfluous parentheses in address calculations
  can: rcar_canfd: Improve printing of global operational state
  can: rcar_canfd: Simplify clock handling
====================

Link: https://patch.msgid.link/20240629114017.1080160-1-mkl@pengutronix.deSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 74d6529b ae44fa99
...@@ -91,7 +91,7 @@ struct m_can_classdev { ...@@ -91,7 +91,7 @@ struct m_can_classdev {
ktime_t irq_timer_wait; ktime_t irq_timer_wait;
struct m_can_ops *ops; const struct m_can_ops *ops;
int version; int version;
u32 irqstatus; u32 irqstatus;
......
...@@ -77,7 +77,7 @@ static int iomap_write_fifo(struct m_can_classdev *cdev, int offset, ...@@ -77,7 +77,7 @@ static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
return 0; return 0;
} }
static struct m_can_ops m_can_pci_ops = { static const struct m_can_ops m_can_pci_ops = {
.read_reg = iomap_read_reg, .read_reg = iomap_read_reg,
.write_reg = iomap_write_reg, .write_reg = iomap_write_reg,
.write_fifo = iomap_write_fifo, .write_fifo = iomap_write_fifo,
......
...@@ -68,7 +68,7 @@ static int iomap_write_fifo(struct m_can_classdev *cdev, int offset, ...@@ -68,7 +68,7 @@ static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
return 0; return 0;
} }
static struct m_can_ops m_can_plat_ops = { static const struct m_can_ops m_can_plat_ops = {
.read_reg = iomap_read_reg, .read_reg = iomap_read_reg,
.write_reg = iomap_write_reg, .write_reg = iomap_write_reg,
.write_fifo = iomap_write_fifo, .write_fifo = iomap_write_fifo,
......
...@@ -357,7 +357,7 @@ static int tcan4x5x_get_gpios(struct m_can_classdev *cdev, ...@@ -357,7 +357,7 @@ static int tcan4x5x_get_gpios(struct m_can_classdev *cdev,
return 0; return 0;
} }
static struct m_can_ops tcan4x5x_ops = { static const struct m_can_ops tcan4x5x_ops = {
.init = tcan4x5x_init, .init = tcan4x5x_init,
.read_reg = tcan4x5x_read_reg, .read_reg = tcan4x5x_read_reg,
.write_reg = tcan4x5x_write_reg, .write_reg = tcan4x5x_write_reg,
......
...@@ -508,12 +508,6 @@ ...@@ -508,12 +508,6 @@
*/ */
#define RCANFD_CFFIFO_IDX 0 #define RCANFD_CFFIFO_IDX 0
/* fCAN clock select register settings */
enum rcar_canfd_fcanclk {
RCANFD_CANFDCLK = 0, /* CANFD clock */
RCANFD_EXTCLK, /* Externally input clock */
};
struct rcar_canfd_global; struct rcar_canfd_global;
struct rcar_canfd_hw_info { struct rcar_canfd_hw_info {
...@@ -545,8 +539,8 @@ struct rcar_canfd_global { ...@@ -545,8 +539,8 @@ struct rcar_canfd_global {
struct platform_device *pdev; /* Respective platform device */ struct platform_device *pdev; /* Respective platform device */
struct clk *clkp; /* Peripheral clock */ struct clk *clkp; /* Peripheral clock */
struct clk *can_clk; /* fCAN clock */ struct clk *can_clk; /* fCAN clock */
enum rcar_canfd_fcanclk fcan; /* CANFD or Ext clock */
unsigned long channels_mask; /* Enabled channels mask */ unsigned long channels_mask; /* Enabled channels mask */
bool extclk; /* CANFD or Ext clock */
bool fdmode; /* CAN FD or Classical CAN only mode */ bool fdmode; /* CAN FD or Classical CAN only mode */
struct reset_control *rstc1; struct reset_control *rstc1;
struct reset_control *rstc2; struct reset_control *rstc2;
...@@ -633,28 +627,28 @@ static inline void rcar_canfd_update(u32 mask, u32 val, u32 __iomem *reg) ...@@ -633,28 +627,28 @@ static inline void rcar_canfd_update(u32 mask, u32 val, u32 __iomem *reg)
static inline u32 rcar_canfd_read(void __iomem *base, u32 offset) static inline u32 rcar_canfd_read(void __iomem *base, u32 offset)
{ {
return readl(base + (offset)); return readl(base + offset);
} }
static inline void rcar_canfd_write(void __iomem *base, u32 offset, u32 val) static inline void rcar_canfd_write(void __iomem *base, u32 offset, u32 val)
{ {
writel(val, base + (offset)); writel(val, base + offset);
} }
static void rcar_canfd_set_bit(void __iomem *base, u32 reg, u32 val) static void rcar_canfd_set_bit(void __iomem *base, u32 reg, u32 val)
{ {
rcar_canfd_update(val, val, base + (reg)); rcar_canfd_update(val, val, base + reg);
} }
static void rcar_canfd_clear_bit(void __iomem *base, u32 reg, u32 val) static void rcar_canfd_clear_bit(void __iomem *base, u32 reg, u32 val)
{ {
rcar_canfd_update(val, 0, base + (reg)); rcar_canfd_update(val, 0, base + reg);
} }
static void rcar_canfd_update_bit(void __iomem *base, u32 reg, static void rcar_canfd_update_bit(void __iomem *base, u32 reg,
u32 mask, u32 val) u32 mask, u32 val)
{ {
rcar_canfd_update(mask, val, base + (reg)); rcar_canfd_update(mask, val, base + reg);
} }
static void rcar_canfd_get_data(struct rcar_canfd_channel *priv, static void rcar_canfd_get_data(struct rcar_canfd_channel *priv,
...@@ -665,7 +659,7 @@ static void rcar_canfd_get_data(struct rcar_canfd_channel *priv, ...@@ -665,7 +659,7 @@ static void rcar_canfd_get_data(struct rcar_canfd_channel *priv,
lwords = DIV_ROUND_UP(cf->len, sizeof(u32)); lwords = DIV_ROUND_UP(cf->len, sizeof(u32));
for (i = 0; i < lwords; i++) for (i = 0; i < lwords; i++)
*((u32 *)cf->data + i) = *((u32 *)cf->data + i) =
rcar_canfd_read(priv->base, off + (i * sizeof(u32))); rcar_canfd_read(priv->base, off + i * sizeof(u32));
} }
static void rcar_canfd_put_data(struct rcar_canfd_channel *priv, static void rcar_canfd_put_data(struct rcar_canfd_channel *priv,
...@@ -675,7 +669,7 @@ static void rcar_canfd_put_data(struct rcar_canfd_channel *priv, ...@@ -675,7 +669,7 @@ static void rcar_canfd_put_data(struct rcar_canfd_channel *priv,
lwords = DIV_ROUND_UP(cf->len, sizeof(u32)); lwords = DIV_ROUND_UP(cf->len, sizeof(u32));
for (i = 0; i < lwords; i++) for (i = 0; i < lwords; i++)
rcar_canfd_write(priv->base, off + (i * sizeof(u32)), rcar_canfd_write(priv->base, off + i * sizeof(u32),
*((u32 *)cf->data + i)); *((u32 *)cf->data + i));
} }
...@@ -777,7 +771,7 @@ static void rcar_canfd_configure_controller(struct rcar_canfd_global *gpriv) ...@@ -777,7 +771,7 @@ static void rcar_canfd_configure_controller(struct rcar_canfd_global *gpriv)
cfg |= RCANFD_GCFG_CMPOC; cfg |= RCANFD_GCFG_CMPOC;
/* Set External Clock if selected */ /* Set External Clock if selected */
if (gpriv->fcan != RCANFD_CANFDCLK) if (gpriv->extclk)
cfg |= RCANFD_GCFG_DCS; cfg |= RCANFD_GCFG_DCS;
rcar_canfd_set_bit(gpriv->base, RCANFD_GCFG, cfg); rcar_canfd_set_bit(gpriv->base, RCANFD_GCFG, cfg);
...@@ -1941,16 +1935,12 @@ static int rcar_canfd_probe(struct platform_device *pdev) ...@@ -1941,16 +1935,12 @@ static int rcar_canfd_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(gpriv->can_clk), return dev_err_probe(dev, PTR_ERR(gpriv->can_clk),
"cannot get canfd clock\n"); "cannot get canfd clock\n");
gpriv->fcan = RCANFD_CANFDCLK; /* CANFD clock may be further divided within the IP */
fcan_freq = clk_get_rate(gpriv->can_clk) / info->postdiv;
} else { } else {
gpriv->fcan = RCANFD_EXTCLK;
}
fcan_freq = clk_get_rate(gpriv->can_clk); fcan_freq = clk_get_rate(gpriv->can_clk);
gpriv->extclk = true;
if (gpriv->fcan == RCANFD_CANFDCLK) }
/* CANFD clock is further divided by (1/2) within the IP */
fcan_freq /= info->postdiv;
addr = devm_platform_ioremap_resource(pdev, 0); addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(addr)) { if (IS_ERR(addr)) {
...@@ -2059,8 +2049,9 @@ static int rcar_canfd_probe(struct platform_device *pdev) ...@@ -2059,8 +2049,9 @@ static int rcar_canfd_probe(struct platform_device *pdev)
} }
platform_set_drvdata(pdev, gpriv); platform_set_drvdata(pdev, gpriv);
dev_info(dev, "global operational state (clk %d, fdmode %d)\n", dev_info(dev, "global operational state (%s clk, %s mode)\n",
gpriv->fcan, gpriv->fdmode); gpriv->extclk ? "ext" : "canfd",
gpriv->fdmode ? "fd" : "classical");
return 0; return 0;
fail_channel: fail_channel:
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// //
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver // 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> // Marc Kleine-Budde <kernel@pengutronix.de>
// //
// Based on: // Based on:
...@@ -744,6 +744,7 @@ static void mcp251xfd_chip_stop(struct mcp251xfd_priv *priv, ...@@ -744,6 +744,7 @@ static void mcp251xfd_chip_stop(struct mcp251xfd_priv *priv,
mcp251xfd_chip_interrupts_disable(priv); mcp251xfd_chip_interrupts_disable(priv);
mcp251xfd_chip_rx_int_disable(priv); mcp251xfd_chip_rx_int_disable(priv);
mcp251xfd_timestamp_stop(priv);
mcp251xfd_chip_sleep(priv); mcp251xfd_chip_sleep(priv);
} }
...@@ -763,6 +764,8 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv) ...@@ -763,6 +764,8 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv)
if (err) if (err)
goto out_chip_stop; goto out_chip_stop;
mcp251xfd_timestamp_start(priv);
err = mcp251xfd_set_bittiming(priv); err = mcp251xfd_set_bittiming(priv);
if (err) if (err)
goto out_chip_stop; goto out_chip_stop;
...@@ -791,7 +794,7 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv) ...@@ -791,7 +794,7 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv)
return 0; return 0;
out_chip_stop: out_chip_stop:
mcp251xfd_dump(priv); mcp251xfd_dump(priv);
mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED); mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
...@@ -867,18 +870,18 @@ static int mcp251xfd_get_berr_counter(const struct net_device *ndev, ...@@ -867,18 +870,18 @@ static int mcp251xfd_get_berr_counter(const struct net_device *ndev,
static struct sk_buff * static struct sk_buff *
mcp251xfd_alloc_can_err_skb(struct mcp251xfd_priv *priv, 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; struct sk_buff *skb;
int err; int err;
err = mcp251xfd_get_timestamp(priv, timestamp); err = mcp251xfd_get_timestamp_raw(priv, ts_raw);
if (err) if (err)
return NULL; return NULL;
skb = alloc_can_err_skb(priv->ndev, cf); skb = alloc_can_err_skb(priv->ndev, cf);
if (skb) if (skb)
mcp251xfd_skb_set_timestamp(priv, skb, *timestamp); mcp251xfd_skb_set_timestamp_raw(priv, skb, *ts_raw);
return skb; return skb;
} }
...@@ -889,7 +892,7 @@ static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv) ...@@ -889,7 +892,7 @@ static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv)
struct mcp251xfd_rx_ring *ring; struct mcp251xfd_rx_ring *ring;
struct sk_buff *skb; struct sk_buff *skb;
struct can_frame *cf; struct can_frame *cf;
u32 timestamp, rxovif; u32 ts_raw, rxovif;
int err, i; int err, i;
stats->rx_over_errors++; stats->rx_over_errors++;
...@@ -924,14 +927,14 @@ static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv) ...@@ -924,14 +927,14 @@ static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv)
return err; return err;
} }
skb = mcp251xfd_alloc_can_err_skb(priv, &cf, &timestamp); skb = mcp251xfd_alloc_can_err_skb(priv, &cf, &ts_raw);
if (!skb) if (!skb)
return 0; return 0;
cf->can_id |= CAN_ERR_CRTL; cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; 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) if (err)
stats->rx_fifo_errors++; stats->rx_fifo_errors++;
...@@ -948,12 +951,12 @@ static int mcp251xfd_handle_txatif(struct mcp251xfd_priv *priv) ...@@ -948,12 +951,12 @@ static int mcp251xfd_handle_txatif(struct mcp251xfd_priv *priv)
static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv) static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv)
{ {
struct net_device_stats *stats = &priv->ndev->stats; struct net_device_stats *stats = &priv->ndev->stats;
u32 bdiag1, timestamp; u32 bdiag1, ts_raw;
struct sk_buff *skb; struct sk_buff *skb;
struct can_frame *cf = NULL; struct can_frame *cf = NULL;
int err; int err;
err = mcp251xfd_get_timestamp(priv, &timestamp); err = mcp251xfd_get_timestamp_raw(priv, &ts_raw);
if (err) if (err)
return err; return err;
...@@ -1035,8 +1038,8 @@ static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv) ...@@ -1035,8 +1038,8 @@ static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv)
if (!cf) if (!cf)
return 0; return 0;
mcp251xfd_skb_set_timestamp(priv, skb, timestamp); mcp251xfd_skb_set_timestamp_raw(priv, skb, ts_raw);
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp); err = can_rx_offload_queue_timestamp(&priv->offload, skb, ts_raw);
if (err) if (err)
stats->rx_fifo_errors++; stats->rx_fifo_errors++;
...@@ -1049,7 +1052,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv) ...@@ -1049,7 +1052,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv)
struct sk_buff *skb; struct sk_buff *skb;
struct can_frame *cf = NULL; struct can_frame *cf = NULL;
enum can_state new_state, rx_state, tx_state; enum can_state new_state, rx_state, tx_state;
u32 trec, timestamp; u32 trec, ts_raw;
int err; int err;
err = regmap_read(priv->map_reg, MCP251XFD_REG_TREC, &trec); err = regmap_read(priv->map_reg, MCP251XFD_REG_TREC, &trec);
...@@ -1079,7 +1082,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv) ...@@ -1079,7 +1082,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv)
/* The skb allocation might fail, but can_change_state() /* The skb allocation might fail, but can_change_state()
* handles cf == NULL. * 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); can_change_state(priv->ndev, cf, tx_state, rx_state);
if (new_state == CAN_STATE_BUS_OFF) { if (new_state == CAN_STATE_BUS_OFF) {
...@@ -1110,7 +1113,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv) ...@@ -1110,7 +1113,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv)
cf->data[7] = bec.rxerr; 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) if (err)
stats->rx_fifo_errors++; stats->rx_fifo_errors++;
...@@ -1135,7 +1138,7 @@ mcp251xfd_handle_modif(const struct mcp251xfd_priv *priv, bool *set_normal_mode) ...@@ -1135,7 +1138,7 @@ mcp251xfd_handle_modif(const struct mcp251xfd_priv *priv, bool *set_normal_mode)
return 0; 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 * MAB underflow, the controller will transition to Restricted
* Operation Mode or Listen Only Mode (depending on SERR2LOM). * Operation Mode or Listen Only Mode (depending on SERR2LOM).
* *
...@@ -1180,7 +1183,7 @@ static int mcp251xfd_handle_serrif(struct mcp251xfd_priv *priv) ...@@ -1180,7 +1183,7 @@ static int mcp251xfd_handle_serrif(struct mcp251xfd_priv *priv)
/* TX MAB underflow /* 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. * underflow is indicated by SERRIF and MODIF.
* *
* In addition to the effects mentioned in the Errata, there * In addition to the effects mentioned in the Errata, there
...@@ -1224,7 +1227,7 @@ static int mcp251xfd_handle_serrif(struct mcp251xfd_priv *priv) ...@@ -1224,7 +1227,7 @@ static int mcp251xfd_handle_serrif(struct mcp251xfd_priv *priv)
/* RX MAB overflow /* 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. * overflow is indicated by SERRIF.
* *
* In addition to the effects mentioned in the Errata, (most * 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) ...@@ -1331,7 +1334,8 @@ mcp251xfd_handle_eccif(struct mcp251xfd_priv *priv, bool set_normal_mode)
return err; return err;
/* Errata Reference: /* 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: * ECC single error correction does not work in all cases:
* *
...@@ -1576,7 +1580,7 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id) ...@@ -1576,7 +1580,7 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
handled = IRQ_HANDLED; handled = IRQ_HANDLED;
} while (1); } while (1);
out_fail: out_fail:
can_rx_offload_threaded_irq_finish(&priv->offload); can_rx_offload_threaded_irq_finish(&priv->offload);
netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n", netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n",
...@@ -1610,11 +1614,12 @@ static int mcp251xfd_open(struct net_device *ndev) ...@@ -1610,11 +1614,12 @@ static int mcp251xfd_open(struct net_device *ndev)
if (err) if (err)
goto out_mcp251xfd_ring_free; goto out_mcp251xfd_ring_free;
mcp251xfd_timestamp_init(priv);
err = mcp251xfd_chip_start(priv); err = mcp251xfd_chip_start(priv);
if (err) if (err)
goto out_transceiver_disable; goto out_transceiver_disable;
mcp251xfd_timestamp_init(priv);
clear_bit(MCP251XFD_FLAGS_DOWN, priv->flags); clear_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
can_rx_offload_enable(&priv->offload); can_rx_offload_enable(&priv->offload);
...@@ -1641,22 +1646,21 @@ static int mcp251xfd_open(struct net_device *ndev) ...@@ -1641,22 +1646,21 @@ static int mcp251xfd_open(struct net_device *ndev)
return 0; return 0;
out_free_irq: out_free_irq:
free_irq(spi->irq, priv); free_irq(spi->irq, priv);
out_destroy_workqueue: out_destroy_workqueue:
destroy_workqueue(priv->wq); destroy_workqueue(priv->wq);
out_can_rx_offload_disable: out_can_rx_offload_disable:
can_rx_offload_disable(&priv->offload); can_rx_offload_disable(&priv->offload);
set_bit(MCP251XFD_FLAGS_DOWN, priv->flags); set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
mcp251xfd_timestamp_stop(priv); out_transceiver_disable:
out_transceiver_disable:
mcp251xfd_transceiver_disable(priv); mcp251xfd_transceiver_disable(priv);
out_mcp251xfd_ring_free: out_mcp251xfd_ring_free:
mcp251xfd_ring_free(priv); mcp251xfd_ring_free(priv);
out_pm_runtime_put: out_pm_runtime_put:
mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED); mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
pm_runtime_put(ndev->dev.parent); pm_runtime_put(ndev->dev.parent);
out_close_candev: out_close_candev:
close_candev(ndev); close_candev(ndev);
return err; return err;
...@@ -1674,7 +1678,6 @@ static int mcp251xfd_stop(struct net_device *ndev) ...@@ -1674,7 +1678,6 @@ static int mcp251xfd_stop(struct net_device *ndev)
free_irq(ndev->irq, priv); free_irq(ndev->irq, priv);
destroy_workqueue(priv->wq); destroy_workqueue(priv->wq);
can_rx_offload_disable(&priv->offload); can_rx_offload_disable(&priv->offload);
mcp251xfd_timestamp_stop(priv);
mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED); mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
mcp251xfd_transceiver_disable(priv); mcp251xfd_transceiver_disable(priv);
mcp251xfd_ring_free(priv); mcp251xfd_ring_free(priv);
...@@ -1820,9 +1823,9 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id, ...@@ -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_slow = xfer[0].effective_speed_hz;
*effective_speed_hz_fast = xfer[1].effective_speed_hz; *effective_speed_hz_fast = xfer[1].effective_speed_hz;
out_kfree_buf_tx: out_kfree_buf_tx:
kfree(buf_tx); kfree(buf_tx);
out_kfree_buf_rx: out_kfree_buf_rx:
kfree(buf_rx); kfree(buf_rx);
return err; return err;
...@@ -1936,13 +1939,13 @@ static int mcp251xfd_register(struct mcp251xfd_priv *priv) ...@@ -1936,13 +1939,13 @@ static int mcp251xfd_register(struct mcp251xfd_priv *priv)
return 0; return 0;
out_unregister_candev: out_unregister_candev:
unregister_candev(ndev); unregister_candev(ndev);
out_chip_sleep: out_chip_sleep:
mcp251xfd_chip_sleep(priv); mcp251xfd_chip_sleep(priv);
out_runtime_disable: out_runtime_disable:
pm_runtime_disable(ndev->dev.parent); pm_runtime_disable(ndev->dev.parent);
out_runtime_put_noidle: out_runtime_put_noidle:
pm_runtime_put_noidle(ndev->dev.parent); pm_runtime_put_noidle(ndev->dev.parent);
mcp251xfd_clks_and_vdd_disable(priv); mcp251xfd_clks_and_vdd_disable(priv);
...@@ -2095,7 +2098,8 @@ static int mcp251xfd_probe(struct spi_device *spi) ...@@ -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); priv->devtype_data = *(struct mcp251xfd_devtype_data *)spi_get_device_match_data(spi);
/* Errata Reference: /* 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 * The SPI can write corrupted data to the RAM at fast SPI
* speeds: * speeds:
...@@ -2155,9 +2159,9 @@ static int mcp251xfd_probe(struct spi_device *spi) ...@@ -2155,9 +2159,9 @@ static int mcp251xfd_probe(struct spi_device *spi)
return 0; return 0;
out_can_rx_offload_del: out_can_rx_offload_del:
can_rx_offload_del(&priv->offload); can_rx_offload_del(&priv->offload);
out_free_candev: out_free_candev:
spi->max_speed_hz = priv->spi_max_speed_hz_orig; spi->max_speed_hz = priv->spi_max_speed_hz_orig;
free_candev(ndev); free_candev(ndev);
......
...@@ -94,7 +94,7 @@ static void mcp251xfd_dump_registers(const struct mcp251xfd_priv *priv, ...@@ -94,7 +94,7 @@ static void mcp251xfd_dump_registers(const struct mcp251xfd_priv *priv,
kfree(buf); kfree(buf);
} }
out: out:
mcp251xfd_dump_header(iter, MCP251XFD_DUMP_OBJECT_TYPE_REG, reg); mcp251xfd_dump_header(iter, MCP251XFD_DUMP_OBJECT_TYPE_REG, reg);
} }
......
...@@ -397,7 +397,7 @@ mcp251xfd_regmap_crc_read(void *context, ...@@ -397,7 +397,7 @@ mcp251xfd_regmap_crc_read(void *context,
return err; return err;
} }
out: out:
memcpy(val_buf, buf_rx->data, val_len); memcpy(val_buf, buf_rx->data, val_len);
return 0; return 0;
......
...@@ -206,6 +206,7 @@ mcp251xfd_ring_init_rx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr) ...@@ -206,6 +206,7 @@ mcp251xfd_ring_init_rx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr)
int i, j; int i, j;
mcp251xfd_for_each_rx_ring(priv, rx_ring, i) { mcp251xfd_for_each_rx_ring(priv, rx_ring, i) {
rx_ring->last_valid = timecounter_read(&priv->tc);
rx_ring->head = 0; rx_ring->head = 0;
rx_ring->tail = 0; rx_ring->tail = 0;
rx_ring->base = *base; rx_ring->base = *base;
...@@ -485,6 +486,8 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv) ...@@ -485,6 +486,8 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
clear_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags); 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; tx_ring->obj_size = tx_obj_size;
rem = priv->rx_obj_num; rem = priv->rx_obj_num;
...@@ -507,6 +510,8 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv) ...@@ -507,6 +510,8 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
} }
rx_ring->obj_num = rx_obj_num; 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; rx_ring->obj_size = rx_obj_size;
priv->rx[i] = rx_ring; priv->rx[i] = rx_ring;
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// //
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver // 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> // Marc Kleine-Budde <kernel@pengutronix.de>
// //
// Based on: // Based on:
...@@ -16,23 +16,14 @@ ...@@ -16,23 +16,14 @@
#include "mcp251xfd.h" #include "mcp251xfd.h"
static inline int static inline bool mcp251xfd_rx_fifo_sta_empty(const u32 fifo_sta)
mcp251xfd_rx_head_get_from_chip(const struct mcp251xfd_priv *priv,
const struct mcp251xfd_rx_ring *ring,
u8 *rx_head, bool *fifo_empty)
{ {
u32 fifo_sta; return !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
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 0; static inline bool mcp251xfd_rx_fifo_sta_full(const u32 fifo_sta)
{
return fifo_sta & MCP251XFD_REG_FIFOSTA_TFERFFIF;
} }
static inline int static inline int
...@@ -80,29 +71,49 @@ mcp251xfd_check_rx_tail(const struct mcp251xfd_priv *priv, ...@@ -80,29 +71,49 @@ mcp251xfd_check_rx_tail(const struct mcp251xfd_priv *priv,
} }
static int static int
mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv, mcp251xfd_get_rx_len(const struct mcp251xfd_priv *priv,
struct mcp251xfd_rx_ring *ring) const struct mcp251xfd_rx_ring *ring,
u8 *len_p)
{ {
u32 new_head; const u8 shift = ring->obj_num_shift_to_u8;
u8 chip_rx_head; u8 chip_head, tail, len;
bool fifo_empty; u32 fifo_sta;
int err; int err;
err = mcp251xfd_rx_head_get_from_chip(priv, ring, &chip_rx_head, err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(ring->fifo_nr),
&fifo_empty); &fifo_sta);
if (err || fifo_empty) 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; return err;
tail = mcp251xfd_get_rx_tail(ring);
/* chip_rx_head, is the next RX-Object filled by the HW. /* First shift to full u8. The subtraction works on signed
* The new RX head must be >= the old head. * 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; BUILD_BUG_ON(sizeof(ring->obj_num) != sizeof(chip_head));
if (new_head <= ring->head) BUILD_BUG_ON(sizeof(ring->obj_num) != sizeof(tail));
new_head += ring->obj_num; 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 static void
...@@ -148,8 +159,6 @@ mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv, ...@@ -148,8 +159,6 @@ mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv,
if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR)) if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR))
memcpy(cfd->data, hw_rx_obj->data, cfd->len); memcpy(cfd->data, hw_rx_obj->data, cfd->len);
mcp251xfd_skb_set_timestamp(priv, skb, hw_rx_obj->ts);
} }
static int static int
...@@ -160,8 +169,26 @@ mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv, ...@@ -160,8 +169,26 @@ mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
struct net_device_stats *stats = &priv->ndev->stats; struct net_device_stats *stats = &priv->ndev->stats;
struct sk_buff *skb; struct sk_buff *skb;
struct canfd_frame *cfd; struct canfd_frame *cfd;
u64 timestamp;
int err; 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) if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF)
skb = alloc_canfd_skb(priv->ndev, &cfd); skb = alloc_canfd_skb(priv->ndev, &cfd);
else else
...@@ -172,6 +199,7 @@ mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv, ...@@ -172,6 +199,7 @@ mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
return 0; return 0;
} }
mcp251xfd_skb_set_timestamp(skb, timestamp);
mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb); mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb);
err = can_rx_offload_queue_timestamp(&priv->offload, skb, hw_rx_obj->ts); err = can_rx_offload_queue_timestamp(&priv->offload, skb, hw_rx_obj->ts);
if (err) if (err)
...@@ -197,52 +225,81 @@ mcp251xfd_rx_obj_read(const struct mcp251xfd_priv *priv, ...@@ -197,52 +225,81 @@ mcp251xfd_rx_obj_read(const struct mcp251xfd_priv *priv,
return err; 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 static int
mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv, mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
struct mcp251xfd_rx_ring *ring) struct mcp251xfd_rx_ring *ring)
{ {
struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj = ring->obj; struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj = ring->obj;
u8 rx_tail, len; u8 rx_tail, len, l;
int err, i; int err, i;
err = mcp251xfd_rx_ring_update(priv, ring); err = mcp251xfd_get_rx_len(priv, ring, &len);
if (err) if (err)
return err; return err;
while ((len = mcp251xfd_get_rx_linear_len(ring))) { while ((l = mcp251xfd_get_rx_linear_len(ring, len))) {
int offset;
rx_tail = mcp251xfd_get_rx_tail(ring); rx_tail = mcp251xfd_get_rx_tail(ring);
err = mcp251xfd_rx_obj_read(priv, ring, hw_rx_obj, err = mcp251xfd_rx_obj_read(priv, ring, hw_rx_obj,
rx_tail, len); rx_tail, l);
if (err) if (err)
return err; return err;
for (i = 0; i < len; i++) { for (i = 0; i < l; i++) {
err = mcp251xfd_handle_rxif_one(priv, ring, err = mcp251xfd_handle_rxif_one(priv, ring,
(void *)hw_rx_obj + (void *)hw_rx_obj +
i * ring->obj_size); 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; return err;
} }
/* Increment the RX FIFO tail pointer 'len' times in a err = mcp251xfd_handle_rxif_ring_uinc(priv, ring, l);
* 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) if (err)
return err; return err;
ring->tail += len; len -= l;
} }
return 0; return 0;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// //
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver // 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> // Marc Kleine-Budde <kernel@pengutronix.de>
// //
// Based on: // Based on:
...@@ -16,6 +16,11 @@ ...@@ -16,6 +16,11 @@
#include "mcp251xfd.h" #include "mcp251xfd.h"
static inline bool mcp251xfd_tx_fifo_sta_full(u32 fifo_sta)
{
return !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
}
static inline int static inline int
mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv, mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv,
u8 *tef_tail) u8 *tef_tail)
...@@ -55,61 +60,44 @@ static int mcp251xfd_check_tef_tail(const struct mcp251xfd_priv *priv) ...@@ -55,61 +60,44 @@ static int mcp251xfd_check_tef_tail(const struct mcp251xfd_priv *priv)
return 0; 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 static int
mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv, mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
const struct mcp251xfd_hw_tef_obj *hw_tef_obj, const struct mcp251xfd_hw_tef_obj *hw_tef_obj,
unsigned int *frame_len_ptr) unsigned int *frame_len_ptr)
{ {
struct net_device_stats *stats = &priv->ndev->stats; struct net_device_stats *stats = &priv->ndev->stats;
u32 seq, tef_tail_masked, tef_tail;
struct sk_buff *skb; 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 /* Use the MCP2517FD mask on the MCP2518FD, too. We only
* compare 7 bits, this should be enough to detect * compare 7 bits, this is enough to detect old TEF objects.
* net-yet-completed, i.e. old TEF objects.
*/ */
seq_masked = seq & seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK,
field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK); hw_tef_obj->flags);
tef_tail_masked = priv->tef->tail & tef_tail_masked = priv->tef->tail &
field_mask(MCP251XFD_OBJ_FLAGS_SEQ_MCP2517FD_MASK); 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); tef_tail = mcp251xfd_get_tef_tail(priv);
skb = priv->can.echo_skb[tef_tail]; skb = priv->can.echo_skb[tef_tail];
if (skb) 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 += stats->tx_bytes +=
can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload, can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload,
tef_tail, hw_tef_obj->ts, tef_tail, hw_tef_obj->ts,
...@@ -120,28 +108,44 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv, ...@@ -120,28 +108,44 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
return 0; 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; const struct mcp251xfd_tx_ring *tx_ring = priv->tx;
unsigned int new_head; const u8 shift = tx_ring->obj_num_shift_to_u8;
u8 chip_tx_tail; u8 chip_tx_tail, tail, len;
u32 fifo_sta;
int err; 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) if (err)
return err; return err;
tail = mcp251xfd_get_tef_tail(priv);
/* chip_tx_tail, is the next TX-Object send by the HW. /* First shift to full u8. The subtraction works on signed
* The new TEF head must be >= the old head, ... * 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; BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(chip_tx_tail));
if (new_head <= priv->tef->head) BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(tail));
new_head += tx_ring->obj_num; BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(len));
/* ... but it cannot exceed the TX head. */ len = (chip_tx_tail << shift) - (tail << shift);
priv->tef->head = min(new_head, tx_ring->head); *len_p = len >> shift;
return mcp251xfd_check_tef_tail(priv); return 0;
} }
static inline int static inline int
...@@ -182,13 +186,12 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv) ...@@ -182,13 +186,12 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
u8 tef_tail, len, l; u8 tef_tail, len, l;
int err, i; int err, i;
err = mcp251xfd_tef_ring_update(priv); err = mcp251xfd_get_tef_len(priv, &len);
if (err) if (err)
return err; return err;
tef_tail = mcp251xfd_get_tef_tail(priv); tef_tail = mcp251xfd_get_tef_tail(priv);
len = mcp251xfd_get_tef_len(priv); l = mcp251xfd_get_tef_linear_len(priv, len);
l = mcp251xfd_get_tef_linear_len(priv);
err = mcp251xfd_tef_obj_read(priv, hw_tef_obj, tef_tail, l); err = mcp251xfd_tef_obj_read(priv, hw_tef_obj, tef_tail, l);
if (err) if (err)
return err; return err;
...@@ -203,12 +206,12 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv) ...@@ -203,12 +206,12 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
unsigned int frame_len = 0; unsigned int frame_len = 0;
err = mcp251xfd_handle_tefif_one(priv, &hw_tef_obj[i], &frame_len); err = mcp251xfd_handle_tefif_one(priv, &hw_tef_obj[i], &frame_len);
/* -EAGAIN means the Sequence Number in the TEF /* -EBADMSG means we're affected by mcp2518fd erratum
* doesn't match our tef_tail. This can happen if we * DS80000789E 6., i.e. the Sequence Number in the TEF
* read the TEF objects too early. Leave loop let the * doesn't match our tef_tail. Don't process any
* interrupt handler call us again. * further and mark processed frames as good.
*/ */
if (err == -EAGAIN) if (err == -EBADMSG)
goto out_netif_wake_queue; goto out_netif_wake_queue;
if (err) if (err)
return err; return err;
...@@ -216,13 +219,15 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv) ...@@ -216,13 +219,15 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
total_frame_len += frame_len; total_frame_len += frame_len;
} }
out_netif_wake_queue: out_netif_wake_queue:
len = i; /* number of handled goods TEFs */ len = i; /* number of handled goods TEFs */
if (len) { if (len) {
struct mcp251xfd_tef_ring *ring = priv->tef; struct mcp251xfd_tef_ring *ring = priv->tef;
struct mcp251xfd_tx_ring *tx_ring = priv->tx; struct mcp251xfd_tx_ring *tx_ring = priv->tx;
int offset; int offset;
ring->head += len;
/* Increment the TEF FIFO tail pointer 'len' times in /* Increment the TEF FIFO tail pointer 'len' times in
* a single SPI message. * a single SPI message.
* *
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// //
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver // mcp251xfd - Microchip MCP251xFD Family CAN controller driver
// //
// Copyright (c) 2021 Pengutronix, // Copyright (c) 2021, 2023 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de> // Marc Kleine-Budde <kernel@pengutronix.de>
// //
...@@ -11,20 +11,20 @@ ...@@ -11,20 +11,20 @@
#include "mcp251xfd.h" #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; const struct mcp251xfd_priv *priv;
u32 timestamp = 0; u32 ts_raw = 0;
int err; int err;
priv = container_of(cc, struct mcp251xfd_priv, cc); priv = container_of(cc, struct mcp251xfd_priv, cc);
err = mcp251xfd_get_timestamp(priv, &timestamp); err = mcp251xfd_get_timestamp_raw(priv, &ts_raw);
if (err) if (err)
netdev_err(priv->ndev, netdev_err(priv->ndev,
"Error %d while reading timestamp. HW timestamps may be inaccurate.", "Error %d while reading timestamp. HW timestamps may be inaccurate.",
err); err);
return timestamp; return ts_raw;
} }
static void mcp251xfd_timestamp_work(struct work_struct *work) static void mcp251xfd_timestamp_work(struct work_struct *work)
...@@ -39,28 +39,21 @@ 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); 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) void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv)
{ {
struct cyclecounter *cc = &priv->cc; struct cyclecounter *cc = &priv->cc;
cc->read = mcp251xfd_timestamp_read; cc->read = mcp251xfd_timestamp_raw_read;
cc->mask = CYCLECOUNTER_MASK(32); cc->mask = CYCLECOUNTER_MASK(32);
cc->shift = 1; cc->shift = 1;
cc->mult = clocksource_hz2mult(priv->can.clock.freq, cc->shift); 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); 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, schedule_delayed_work(&priv->timestamp,
MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ); MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ);
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* *
* mcp251xfd - Microchip MCP251xFD Family CAN controller driver * 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> * Marc Kleine-Budde <kernel@pengutronix.de>
* Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org> * Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
*/ */
...@@ -524,6 +524,7 @@ struct mcp251xfd_tef_ring { ...@@ -524,6 +524,7 @@ struct mcp251xfd_tef_ring {
/* u8 obj_num equals tx_ring->obj_num */ /* u8 obj_num equals tx_ring->obj_num */
/* u8 obj_size equals sizeof(struct mcp251xfd_hw_tef_obj) */ /* 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; union mcp251xfd_write_reg_buf irq_enable_buf;
struct spi_transfer irq_enable_xfer; struct spi_transfer irq_enable_xfer;
...@@ -542,6 +543,7 @@ struct mcp251xfd_tx_ring { ...@@ -542,6 +543,7 @@ struct mcp251xfd_tx_ring {
u8 nr; u8 nr;
u8 fifo_nr; u8 fifo_nr;
u8 obj_num; u8 obj_num;
u8 obj_num_shift_to_u8;
u8 obj_size; u8 obj_size;
struct mcp251xfd_tx_obj obj[MCP251XFD_TX_OBJ_NUM_MAX]; struct mcp251xfd_tx_obj obj[MCP251XFD_TX_OBJ_NUM_MAX];
...@@ -552,10 +554,14 @@ struct mcp251xfd_rx_ring { ...@@ -552,10 +554,14 @@ struct mcp251xfd_rx_ring {
unsigned int head; unsigned int head;
unsigned int tail; unsigned int tail;
/* timestamp of the last valid received CAN frame */
u64 last_valid;
u16 base; u16 base;
u8 nr; u8 nr;
u8 fifo_nr; u8 fifo_nr;
u8 obj_num; u8 obj_num;
u8 obj_num_shift_to_u8;
u8 obj_size; u8 obj_size;
union mcp251xfd_write_reg_buf irq_enable_buf; union mcp251xfd_write_reg_buf irq_enable_buf;
...@@ -809,10 +815,27 @@ mcp251xfd_spi_cmd_write(const struct mcp251xfd_priv *priv, ...@@ -809,10 +815,27 @@ mcp251xfd_spi_cmd_write(const struct mcp251xfd_priv *priv,
return data; return data;
} }
static inline int mcp251xfd_get_timestamp(const struct mcp251xfd_priv *priv, static inline int mcp251xfd_get_timestamp_raw(const struct mcp251xfd_priv *priv,
u32 *timestamp) 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) 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) ...@@ -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); 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)); 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) ...@@ -914,18 +928,9 @@ static inline u8 mcp251xfd_get_rx_tail(const struct mcp251xfd_rx_ring *ring)
return ring->tail & (ring->obj_num - 1); 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 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)); 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); ...@@ -951,9 +956,8 @@ void mcp251xfd_ring_free(struct mcp251xfd_priv *priv);
int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv); int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv);
int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv); int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv);
int mcp251xfd_handle_tefif(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_init(struct mcp251xfd_priv *priv);
void mcp251xfd_timestamp_start(struct mcp251xfd_priv *priv);
void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv); void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv);
void mcp251xfd_tx_obj_write_sync(struct work_struct *work); void mcp251xfd_tx_obj_write_sync(struct work_struct *work);
......
...@@ -40,6 +40,9 @@ ...@@ -40,6 +40,9 @@
#define USB_ABE_CANDEBUGGER_FD_VENDOR_ID 0x16d0 #define USB_ABE_CANDEBUGGER_FD_VENDOR_ID 0x16d0
#define USB_ABE_CANDEBUGGER_FD_PRODUCT_ID 0x10b8 #define USB_ABE_CANDEBUGGER_FD_PRODUCT_ID 0x10b8
#define USB_XYLANTA_SAINT3_VENDOR_ID 0x16d0
#define USB_XYLANTA_SAINT3_PRODUCT_ID 0x0f30
#define GS_USB_ENDPOINT_IN 1 #define GS_USB_ENDPOINT_IN 1
#define GS_USB_ENDPOINT_OUT 2 #define GS_USB_ENDPOINT_OUT 2
...@@ -1530,6 +1533,8 @@ static const struct usb_device_id gs_usb_table[] = { ...@@ -1530,6 +1533,8 @@ static const struct usb_device_id gs_usb_table[] = {
USB_CES_CANEXT_FD_PRODUCT_ID, 0) }, USB_CES_CANEXT_FD_PRODUCT_ID, 0) },
{ USB_DEVICE_INTERFACE_NUMBER(USB_ABE_CANDEBUGGER_FD_VENDOR_ID, { USB_DEVICE_INTERFACE_NUMBER(USB_ABE_CANDEBUGGER_FD_VENDOR_ID,
USB_ABE_CANDEBUGGER_FD_PRODUCT_ID, 0) }, USB_ABE_CANDEBUGGER_FD_PRODUCT_ID, 0) },
{ USB_DEVICE_INTERFACE_NUMBER(USB_XYLANTA_SAINT3_VENDOR_ID,
USB_XYLANTA_SAINT3_PRODUCT_ID, 0) },
{} /* Terminating entry */ {} /* Terminating entry */
}; };
......
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