// SPDX-License-Identifier: GPL-2.0 // // mcp251xfd - Microchip MCP251xFD Family CAN controller driver // // Copyright (c) 2019, 2020, 2021, 2024 Pengutronix, // Marc Kleine-Budde <kernel@pengutronix.de> // // Based on: // // CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface // // Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org> //
/* FIFO increment TEF tail pointer */
addr = MCP251XFD_REG_TEFCON;
val = MCP251XFD_REG_TEFCON_UINC;
len = mcp251xfd_cmd_prepare_write_reg(priv, &tef_ring->uinc_buf,
addr, val, val);
for (i = 0; i < ARRAY_SIZE(tef_ring->uinc_xfer); i++) {
xfer = &tef_ring->uinc_xfer[i];
xfer->tx_buf = &tef_ring->uinc_buf;
xfer->len = len;
xfer->cs_change = 1;
xfer->cs_change_delay.value = 0;
xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
}
/* "cs_change == 1" on the last transfer results in an active * chip select after the complete SPI message. This causes the * controller to interpret the next register access as * data. Set "cs_change" of the last transfer to "0" to * properly deactivate the chip select at the end of the * message.
*/
xfer->cs_change = 0;
if (priv->tx_coalesce_usecs_irq || priv->tx_obj_num_coalesce_irq) {
val = MCP251XFD_REG_TEFCON_UINC |
MCP251XFD_REG_TEFCON_TEFOVIE |
MCP251XFD_REG_TEFCON_TEFHIE;
/* "cs_change == 1" on the last transfer results in an * active chip select after the complete SPI * message. This causes the controller to interpret * the next register access as data. Set "cs_change" * of the last transfer to "0" to properly deactivate * the chip select at the end of the message.
*/
xfer->cs_change = 0;
/* Use 1st RX-FIFO for IRQ coalescing. If enabled * (rx_coalesce_usecs_irq or rx_max_coalesce_frames_irq * is activated), use the last transfer to disable: * * - TFNRFNIE (Receive FIFO Not Empty Interrupt) * * and enable: * * - TFHRFHIE (Receive FIFO Half Full Interrupt) * - or - * - TFERFFIE (Receive FIFO Full Interrupt) * * depending on rx_max_coalesce_frames_irq. * * The RXOVIE (Overflow Interrupt) is always enabled.
*/ if (rx_ring->nr == 0 && (priv->rx_coalesce_usecs_irq ||
priv->rx_obj_num_coalesce_irq)) {
val = MCP251XFD_REG_FIFOCON_UINC |
MCP251XFD_REG_FIFOCON_RXOVIE;
if (priv->rx_obj_num_coalesce_irq == rx_ring->obj_num)
val |= MCP251XFD_REG_FIFOCON_TFERFFIE; elseif (priv->rx_obj_num_coalesce_irq)
val |= MCP251XFD_REG_FIFOCON_TFHRFHIE;
/* mcp251xfd_handle_rxif() will iterate over all RX rings. * Rings with their corresponding bit set in * priv->regs_status.rxif are read out. * * If the chip is configured for only 1 RX-FIFO, and if there * is an RX interrupt pending (RXIF in INT register is set), * it must be the 1st RX-FIFO. * * We mark the RXIF of the 1st FIFO as pending here, so that * we can skip the read of the RXIF register in * mcp251xfd_read_regs_status() for the 1 RX-FIFO only case. * * If we use more than 1 RX-FIFO, this value gets overwritten * in mcp251xfd_read_regs_status(), so set it unconditionally * here.
*/
priv->regs_status.rxif = BIT(priv->rx[0]->fifo_nr);
ram_used = base - MCP251XFD_RAM_START; if (ram_used > MCP251XFD_RAM_SIZE) {
netdev_err(priv->ndev, "Error during ring configuration, using more RAM (%u bytes) than available (%u bytes).\n",
ram_used, MCP251XFD_RAM_SIZE);
err = -ENOMEM;
}
if (priv->tx_obj_num_coalesce_irq &&
priv->tx_obj_num_coalesce_irq * 2 != priv->tx->obj_num) {
netdev_err(priv->ndev, "Error during ring configuration, number of TEF coalescing buffers (%u) must be half of TEF buffers (%u).\n",
priv->tx_obj_num_coalesce_irq, priv->tx->obj_num);
err = -EINVAL;
}
return err;
}
void mcp251xfd_ring_free(struct mcp251xfd_priv *priv)
{ int i;
for (i = ARRAY_SIZE(priv->rx) - 1; i >= 0; i--) {
kfree(priv->rx[i]);
priv->rx[i] = NULL;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.