linux-can-next-for-6.11-20240629
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEUEC6huC2BN0pvD5fKDiiPnotvG8FAmZ/8VUTHG1rbEBwZW5n dXRyb25peC5kZQAKCRAoOKI+ei28b35qB/44WrOFDefCGNuERFq5/8Kq0FGoDvoa ie1PJXjfGbhn5A53pNpB7jOyDnr6DwWVTdF6AMZObHGpqjRT03LuflWqeC9+JIC1 X6pIAeZVToBMTi8SKTGvK0Fw13dZuxc/QqlHp3S6cd8s+9ETTDnIBN3iQx4vqPTc +G0iJUNC49zf9D4F6MsJTYGP8bmzeexTcjOwj+i2oiZvNN/vSrWs+cjC9l8K3Y0a b1FL7rv4l+TcUWrSIxbqNUUZBrzA5uV0JFUOokhC3MvLKw+61r3L9DMUUBZBIB+Q aFgJyCwX+ju/j1c76lJT2U3EnzNLxego7fLzha5BcftzCk3974Hvr/3y =Ykzx -----END PGP SIGNATURE----- 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.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
1eea11e937
@ -91,7 +91,7 @@ struct m_can_classdev {
|
||||
|
||||
ktime_t irq_timer_wait;
|
||||
|
||||
struct m_can_ops *ops;
|
||||
const struct m_can_ops *ops;
|
||||
|
||||
int version;
|
||||
u32 irqstatus;
|
||||
|
@ -77,7 +77,7 @@ static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
|
||||
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,
|
||||
.write_reg = iomap_write_reg,
|
||||
.write_fifo = iomap_write_fifo,
|
||||
|
@ -68,7 +68,7 @@ static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
|
||||
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,
|
||||
.write_reg = iomap_write_reg,
|
||||
.write_fifo = iomap_write_fifo,
|
||||
|
@ -357,7 +357,7 @@ static int tcan4x5x_get_gpios(struct m_can_classdev *cdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct m_can_ops tcan4x5x_ops = {
|
||||
static const struct m_can_ops tcan4x5x_ops = {
|
||||
.init = tcan4x5x_init,
|
||||
.read_reg = tcan4x5x_read_reg,
|
||||
.write_reg = tcan4x5x_write_reg,
|
||||
|
@ -508,12 +508,6 @@
|
||||
*/
|
||||
#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_hw_info {
|
||||
@ -545,8 +539,8 @@ struct rcar_canfd_global {
|
||||
struct platform_device *pdev; /* Respective platform device */
|
||||
struct clk *clkp; /* Peripheral clock */
|
||||
struct clk *can_clk; /* fCAN clock */
|
||||
enum rcar_canfd_fcanclk fcan; /* CANFD or Ext clock */
|
||||
unsigned long channels_mask; /* Enabled channels mask */
|
||||
bool extclk; /* CANFD or Ext clock */
|
||||
bool fdmode; /* CAN FD or Classical CAN only mode */
|
||||
struct reset_control *rstc1;
|
||||
struct reset_control *rstc2;
|
||||
@ -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)
|
||||
{
|
||||
return readl(base + (offset));
|
||||
return readl(base + offset);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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,
|
||||
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,
|
||||
@ -665,7 +659,7 @@ static void rcar_canfd_get_data(struct rcar_canfd_channel *priv,
|
||||
lwords = DIV_ROUND_UP(cf->len, sizeof(u32));
|
||||
for (i = 0; i < lwords; 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,
|
||||
@ -675,7 +669,7 @@ static void rcar_canfd_put_data(struct rcar_canfd_channel *priv,
|
||||
|
||||
lwords = DIV_ROUND_UP(cf->len, sizeof(u32));
|
||||
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));
|
||||
}
|
||||
|
||||
@ -777,7 +771,7 @@ static void rcar_canfd_configure_controller(struct rcar_canfd_global *gpriv)
|
||||
cfg |= RCANFD_GCFG_CMPOC;
|
||||
|
||||
/* Set External Clock if selected */
|
||||
if (gpriv->fcan != RCANFD_CANFDCLK)
|
||||
if (gpriv->extclk)
|
||||
cfg |= RCANFD_GCFG_DCS;
|
||||
|
||||
rcar_canfd_set_bit(gpriv->base, RCANFD_GCFG, cfg);
|
||||
@ -1941,16 +1935,12 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(dev, PTR_ERR(gpriv->can_clk),
|
||||
"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 {
|
||||
gpriv->fcan = RCANFD_EXTCLK;
|
||||
fcan_freq = clk_get_rate(gpriv->can_clk);
|
||||
gpriv->extclk = true;
|
||||
}
|
||||
fcan_freq = clk_get_rate(gpriv->can_clk);
|
||||
|
||||
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);
|
||||
if (IS_ERR(addr)) {
|
||||
@ -2059,8 +2049,9 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, gpriv);
|
||||
dev_info(dev, "global operational state (clk %d, fdmode %d)\n",
|
||||
gpriv->fcan, gpriv->fdmode);
|
||||
dev_info(dev, "global operational state (%s clk, %s mode)\n",
|
||||
gpriv->extclk ? "ext" : "canfd",
|
||||
gpriv->fdmode ? "fd" : "classical");
|
||||
return 0;
|
||||
|
||||
fail_channel:
|
||||
|
@ -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, ×tamp);
|
||||
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, ×tamp);
|
||||
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, ×tamp);
|
||||
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;
|
||||
return !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
|
||||
}
|
||||
|
||||
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
|
||||
@ -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;
|
||||
|
||||
/* chip_rx_head, is the next RX-Object filled by the HW.
|
||||
* The new RX head must be >= the old head.
|
||||
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);
|
||||
|
||||
/* 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, ×tamp);
|
||||
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, timestamp);
|
||||
return regmap_read(priv->map_reg, MCP251XFD_REG_TBC, ts_raw);
|
||||
}
|
||||
|
||||
static inline void mcp251xfd_skb_set_timestamp(struct sk_buff *skb, u64 ns)
|
||||
{
|
||||
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);
|
||||
|
@ -40,6 +40,9 @@
|
||||
#define USB_ABE_CANDEBUGGER_FD_VENDOR_ID 0x16d0
|
||||
#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_OUT 2
|
||||
|
||||
@ -1530,6 +1533,8 @@ static const struct usb_device_id gs_usb_table[] = {
|
||||
USB_CES_CANEXT_FD_PRODUCT_ID, 0) },
|
||||
{ USB_DEVICE_INTERFACE_NUMBER(USB_ABE_CANDEBUGGER_FD_VENDOR_ID,
|
||||
USB_ABE_CANDEBUGGER_FD_PRODUCT_ID, 0) },
|
||||
{ USB_DEVICE_INTERFACE_NUMBER(USB_XYLANTA_SAINT3_VENDOR_ID,
|
||||
USB_XYLANTA_SAINT3_PRODUCT_ID, 0) },
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user