155bc37c8SMarc Kleine-Budde // SPDX-License-Identifier: GPL-2.0 255bc37c8SMarc Kleine-Budde // 355bc37c8SMarc Kleine-Budde // mcp251xfd - Microchip MCP251xFD Family CAN controller driver 455bc37c8SMarc Kleine-Budde // 555bc37c8SMarc Kleine-Budde // Copyright (c) 2019, 2020, 2021 Pengutronix, 655bc37c8SMarc Kleine-Budde // Marc Kleine-Budde <kernel@pengutronix.de> 755bc37c8SMarc Kleine-Budde // 855bc37c8SMarc Kleine-Budde // Based on: 955bc37c8SMarc Kleine-Budde // 1055bc37c8SMarc Kleine-Budde // CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface 1155bc37c8SMarc Kleine-Budde // 1255bc37c8SMarc Kleine-Budde // Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org> 1355bc37c8SMarc Kleine-Budde // 1455bc37c8SMarc Kleine-Budde 15*5f60d5f6SAl Viro #include <linux/unaligned.h> 1655bc37c8SMarc Kleine-Budde 1755bc37c8SMarc Kleine-Budde #include "mcp251xfd.h" 189263c2e9SMarc Kleine-Budde #include "mcp251xfd-ram.h" 1955bc37c8SMarc Kleine-Budde 2055bc37c8SMarc Kleine-Budde static inline u8 2155bc37c8SMarc Kleine-Budde mcp251xfd_cmd_prepare_write_reg(const struct mcp251xfd_priv *priv, 2255bc37c8SMarc Kleine-Budde union mcp251xfd_write_reg_buf *write_reg_buf, 2355bc37c8SMarc Kleine-Budde const u16 reg, const u32 mask, const u32 val) 2455bc37c8SMarc Kleine-Budde { 2555bc37c8SMarc Kleine-Budde u8 first_byte, last_byte, len; 2655bc37c8SMarc Kleine-Budde u8 *data; 2755bc37c8SMarc Kleine-Budde __le32 val_le32; 2855bc37c8SMarc Kleine-Budde 2955bc37c8SMarc Kleine-Budde first_byte = mcp251xfd_first_byte_set(mask); 3055bc37c8SMarc Kleine-Budde last_byte = mcp251xfd_last_byte_set(mask); 3155bc37c8SMarc Kleine-Budde len = last_byte - first_byte + 1; 3255bc37c8SMarc Kleine-Budde 332e8ca20bSThomas Kopp data = mcp251xfd_spi_cmd_write(priv, write_reg_buf, reg + first_byte, len); 3455bc37c8SMarc Kleine-Budde val_le32 = cpu_to_le32(val >> BITS_PER_BYTE * first_byte); 3555bc37c8SMarc Kleine-Budde memcpy(data, &val_le32, len); 3655bc37c8SMarc Kleine-Budde 372e8ca20bSThomas Kopp if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG)) { 382e8ca20bSThomas Kopp len += sizeof(write_reg_buf->nocrc.cmd); 392e8ca20bSThomas Kopp } else if (len == 1) { 402e8ca20bSThomas Kopp u16 crc; 412e8ca20bSThomas Kopp 422e8ca20bSThomas Kopp /* CRC */ 432e8ca20bSThomas Kopp len += sizeof(write_reg_buf->safe.cmd); 442e8ca20bSThomas Kopp crc = mcp251xfd_crc16_compute(&write_reg_buf->safe, len); 452e8ca20bSThomas Kopp put_unaligned_be16(crc, (void *)write_reg_buf + len); 462e8ca20bSThomas Kopp 472e8ca20bSThomas Kopp /* Total length */ 482e8ca20bSThomas Kopp len += sizeof(write_reg_buf->safe.crc); 492e8ca20bSThomas Kopp } else { 5055bc37c8SMarc Kleine-Budde u16 crc; 5155bc37c8SMarc Kleine-Budde 5255bc37c8SMarc Kleine-Budde mcp251xfd_spi_cmd_crc_set_len_in_reg(&write_reg_buf->crc.cmd, 5355bc37c8SMarc Kleine-Budde len); 5455bc37c8SMarc Kleine-Budde /* CRC */ 5555bc37c8SMarc Kleine-Budde len += sizeof(write_reg_buf->crc.cmd); 5655bc37c8SMarc Kleine-Budde crc = mcp251xfd_crc16_compute(&write_reg_buf->crc, len); 5755bc37c8SMarc Kleine-Budde put_unaligned_be16(crc, (void *)write_reg_buf + len); 5855bc37c8SMarc Kleine-Budde 5955bc37c8SMarc Kleine-Budde /* Total length */ 6055bc37c8SMarc Kleine-Budde len += sizeof(write_reg_buf->crc.crc); 6155bc37c8SMarc Kleine-Budde } 6255bc37c8SMarc Kleine-Budde 6355bc37c8SMarc Kleine-Budde return len; 6455bc37c8SMarc Kleine-Budde } 6555bc37c8SMarc Kleine-Budde 66617283b9SMarc Kleine-Budde static void 67617283b9SMarc Kleine-Budde mcp251xfd_ring_init_tef(struct mcp251xfd_priv *priv, u16 *base) 68d2d5397fSMarc Kleine-Budde { 69d2d5397fSMarc Kleine-Budde struct mcp251xfd_tef_ring *tef_ring; 70d2d5397fSMarc Kleine-Budde struct spi_transfer *xfer; 71d2d5397fSMarc Kleine-Budde u32 val; 72d2d5397fSMarc Kleine-Budde u16 addr; 73d2d5397fSMarc Kleine-Budde u8 len; 74d2d5397fSMarc Kleine-Budde int i; 75d2d5397fSMarc Kleine-Budde 76d2d5397fSMarc Kleine-Budde /* TEF */ 77d2d5397fSMarc Kleine-Budde tef_ring = priv->tef; 78d2d5397fSMarc Kleine-Budde tef_ring->head = 0; 79d2d5397fSMarc Kleine-Budde tef_ring->tail = 0; 80d2d5397fSMarc Kleine-Budde 81617283b9SMarc Kleine-Budde /* TEF- and TX-FIFO have same number of objects */ 82617283b9SMarc Kleine-Budde *base = mcp251xfd_get_tef_obj_addr(priv->tx->obj_num); 83617283b9SMarc Kleine-Budde 84169d00a2SMarc Kleine-Budde /* FIFO IRQ enable */ 85169d00a2SMarc Kleine-Budde addr = MCP251XFD_REG_TEFCON; 86169d00a2SMarc Kleine-Budde val = MCP251XFD_REG_TEFCON_TEFOVIE | MCP251XFD_REG_TEFCON_TEFNEIE; 87169d00a2SMarc Kleine-Budde 88169d00a2SMarc Kleine-Budde len = mcp251xfd_cmd_prepare_write_reg(priv, &tef_ring->irq_enable_buf, 89169d00a2SMarc Kleine-Budde addr, val, val); 90169d00a2SMarc Kleine-Budde tef_ring->irq_enable_xfer.tx_buf = &tef_ring->irq_enable_buf; 91169d00a2SMarc Kleine-Budde tef_ring->irq_enable_xfer.len = len; 92169d00a2SMarc Kleine-Budde spi_message_init_with_transfers(&tef_ring->irq_enable_msg, 93169d00a2SMarc Kleine-Budde &tef_ring->irq_enable_xfer, 1); 94169d00a2SMarc Kleine-Budde 95d2d5397fSMarc Kleine-Budde /* FIFO increment TEF tail pointer */ 96d2d5397fSMarc Kleine-Budde addr = MCP251XFD_REG_TEFCON; 97d2d5397fSMarc Kleine-Budde val = MCP251XFD_REG_TEFCON_UINC; 98d2d5397fSMarc Kleine-Budde len = mcp251xfd_cmd_prepare_write_reg(priv, &tef_ring->uinc_buf, 99d2d5397fSMarc Kleine-Budde addr, val, val); 100d2d5397fSMarc Kleine-Budde 101d2d5397fSMarc Kleine-Budde for (i = 0; i < ARRAY_SIZE(tef_ring->uinc_xfer); i++) { 102d2d5397fSMarc Kleine-Budde xfer = &tef_ring->uinc_xfer[i]; 103d2d5397fSMarc Kleine-Budde xfer->tx_buf = &tef_ring->uinc_buf; 104d2d5397fSMarc Kleine-Budde xfer->len = len; 105d2d5397fSMarc Kleine-Budde xfer->cs_change = 1; 106d2d5397fSMarc Kleine-Budde xfer->cs_change_delay.value = 0; 107d2d5397fSMarc Kleine-Budde xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; 108d2d5397fSMarc Kleine-Budde } 109d2d5397fSMarc Kleine-Budde 110d2d5397fSMarc Kleine-Budde /* "cs_change == 1" on the last transfer results in an active 111d2d5397fSMarc Kleine-Budde * chip select after the complete SPI message. This causes the 112d2d5397fSMarc Kleine-Budde * controller to interpret the next register access as 113d2d5397fSMarc Kleine-Budde * data. Set "cs_change" of the last transfer to "0" to 114d2d5397fSMarc Kleine-Budde * properly deactivate the chip select at the end of the 115d2d5397fSMarc Kleine-Budde * message. 116d2d5397fSMarc Kleine-Budde */ 117d2d5397fSMarc Kleine-Budde xfer->cs_change = 0; 118169d00a2SMarc Kleine-Budde 119169d00a2SMarc Kleine-Budde if (priv->tx_coalesce_usecs_irq || priv->tx_obj_num_coalesce_irq) { 120169d00a2SMarc Kleine-Budde val = MCP251XFD_REG_TEFCON_UINC | 121169d00a2SMarc Kleine-Budde MCP251XFD_REG_TEFCON_TEFOVIE | 122169d00a2SMarc Kleine-Budde MCP251XFD_REG_TEFCON_TEFHIE; 123169d00a2SMarc Kleine-Budde 124169d00a2SMarc Kleine-Budde len = mcp251xfd_cmd_prepare_write_reg(priv, 125169d00a2SMarc Kleine-Budde &tef_ring->uinc_irq_disable_buf, 126169d00a2SMarc Kleine-Budde addr, val, val); 127169d00a2SMarc Kleine-Budde xfer->tx_buf = &tef_ring->uinc_irq_disable_buf; 128169d00a2SMarc Kleine-Budde xfer->len = len; 129169d00a2SMarc Kleine-Budde } 130d2d5397fSMarc Kleine-Budde } 131d2d5397fSMarc Kleine-Budde 13255bc37c8SMarc Kleine-Budde static void 13355bc37c8SMarc Kleine-Budde mcp251xfd_tx_ring_init_tx_obj(const struct mcp251xfd_priv *priv, 13455bc37c8SMarc Kleine-Budde const struct mcp251xfd_tx_ring *ring, 13555bc37c8SMarc Kleine-Budde struct mcp251xfd_tx_obj *tx_obj, 13655bc37c8SMarc Kleine-Budde const u8 rts_buf_len, 13755bc37c8SMarc Kleine-Budde const u8 n) 13855bc37c8SMarc Kleine-Budde { 13955bc37c8SMarc Kleine-Budde struct spi_transfer *xfer; 14055bc37c8SMarc Kleine-Budde u16 addr; 14155bc37c8SMarc Kleine-Budde 14255bc37c8SMarc Kleine-Budde /* FIFO load */ 14355bc37c8SMarc Kleine-Budde addr = mcp251xfd_get_tx_obj_addr(ring, n); 14455bc37c8SMarc Kleine-Budde if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_TX) 14555bc37c8SMarc Kleine-Budde mcp251xfd_spi_cmd_write_crc_set_addr(&tx_obj->buf.crc.cmd, 14655bc37c8SMarc Kleine-Budde addr); 14755bc37c8SMarc Kleine-Budde else 14855bc37c8SMarc Kleine-Budde mcp251xfd_spi_cmd_write_nocrc(&tx_obj->buf.nocrc.cmd, 14955bc37c8SMarc Kleine-Budde addr); 15055bc37c8SMarc Kleine-Budde 15155bc37c8SMarc Kleine-Budde xfer = &tx_obj->xfer[0]; 15255bc37c8SMarc Kleine-Budde xfer->tx_buf = &tx_obj->buf; 15355bc37c8SMarc Kleine-Budde xfer->len = 0; /* actual len is assigned on the fly */ 15455bc37c8SMarc Kleine-Budde xfer->cs_change = 1; 15555bc37c8SMarc Kleine-Budde xfer->cs_change_delay.value = 0; 15655bc37c8SMarc Kleine-Budde xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; 15755bc37c8SMarc Kleine-Budde 15855bc37c8SMarc Kleine-Budde /* FIFO request to send */ 15955bc37c8SMarc Kleine-Budde xfer = &tx_obj->xfer[1]; 16055bc37c8SMarc Kleine-Budde xfer->tx_buf = &ring->rts_buf; 16155bc37c8SMarc Kleine-Budde xfer->len = rts_buf_len; 16255bc37c8SMarc Kleine-Budde 16355bc37c8SMarc Kleine-Budde /* SPI message */ 16455bc37c8SMarc Kleine-Budde spi_message_init_with_transfers(&tx_obj->msg, tx_obj->xfer, 16555bc37c8SMarc Kleine-Budde ARRAY_SIZE(tx_obj->xfer)); 16655bc37c8SMarc Kleine-Budde } 16755bc37c8SMarc Kleine-Budde 168617283b9SMarc Kleine-Budde static void 169617283b9SMarc Kleine-Budde mcp251xfd_ring_init_tx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr) 17055bc37c8SMarc Kleine-Budde { 17155bc37c8SMarc Kleine-Budde struct mcp251xfd_tx_ring *tx_ring; 17255bc37c8SMarc Kleine-Budde struct mcp251xfd_tx_obj *tx_obj; 17355bc37c8SMarc Kleine-Budde u32 val; 17455bc37c8SMarc Kleine-Budde u16 addr; 17555bc37c8SMarc Kleine-Budde u8 len; 176d2d5397fSMarc Kleine-Budde int i; 17755bc37c8SMarc Kleine-Budde 17855bc37c8SMarc Kleine-Budde tx_ring = priv->tx; 17955bc37c8SMarc Kleine-Budde tx_ring->head = 0; 18055bc37c8SMarc Kleine-Budde tx_ring->tail = 0; 181617283b9SMarc Kleine-Budde tx_ring->base = *base; 182c912f19eSMarc Kleine-Budde tx_ring->nr = 0; 183617283b9SMarc Kleine-Budde tx_ring->fifo_nr = *fifo_nr; 184617283b9SMarc Kleine-Budde 185617283b9SMarc Kleine-Budde *base = mcp251xfd_get_tx_obj_addr(tx_ring, tx_ring->obj_num); 186617283b9SMarc Kleine-Budde *fifo_nr += 1; 18755bc37c8SMarc Kleine-Budde 18855bc37c8SMarc Kleine-Budde /* FIFO request to send */ 189c912f19eSMarc Kleine-Budde addr = MCP251XFD_REG_FIFOCON(tx_ring->fifo_nr); 19055bc37c8SMarc Kleine-Budde val = MCP251XFD_REG_FIFOCON_TXREQ | MCP251XFD_REG_FIFOCON_UINC; 19155bc37c8SMarc Kleine-Budde len = mcp251xfd_cmd_prepare_write_reg(priv, &tx_ring->rts_buf, 19255bc37c8SMarc Kleine-Budde addr, val, val); 19355bc37c8SMarc Kleine-Budde 19455bc37c8SMarc Kleine-Budde mcp251xfd_for_each_tx_obj(tx_ring, tx_obj, i) 19555bc37c8SMarc Kleine-Budde mcp251xfd_tx_ring_init_tx_obj(priv, tx_ring, tx_obj, len, i); 196d2d5397fSMarc Kleine-Budde } 19755bc37c8SMarc Kleine-Budde 198617283b9SMarc Kleine-Budde static void 199617283b9SMarc Kleine-Budde mcp251xfd_ring_init_rx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr) 200d2d5397fSMarc Kleine-Budde { 201617283b9SMarc Kleine-Budde struct mcp251xfd_rx_ring *rx_ring; 202d2d5397fSMarc Kleine-Budde struct spi_transfer *xfer; 203d2d5397fSMarc Kleine-Budde u32 val; 204d2d5397fSMarc Kleine-Budde u16 addr; 205d2d5397fSMarc Kleine-Budde u8 len; 206d2d5397fSMarc Kleine-Budde int i, j; 207d2d5397fSMarc Kleine-Budde 20855bc37c8SMarc Kleine-Budde mcp251xfd_for_each_rx_ring(priv, rx_ring, i) { 20924436be5SMarc Kleine-Budde rx_ring->last_valid = timecounter_read(&priv->tc); 21055bc37c8SMarc Kleine-Budde rx_ring->head = 0; 21155bc37c8SMarc Kleine-Budde rx_ring->tail = 0; 212617283b9SMarc Kleine-Budde rx_ring->base = *base; 21355bc37c8SMarc Kleine-Budde rx_ring->nr = i; 214617283b9SMarc Kleine-Budde rx_ring->fifo_nr = *fifo_nr; 21555bc37c8SMarc Kleine-Budde 216617283b9SMarc Kleine-Budde *base = mcp251xfd_get_rx_obj_addr(rx_ring, rx_ring->obj_num); 217617283b9SMarc Kleine-Budde *fifo_nr += 1; 21855bc37c8SMarc Kleine-Budde 21960a848c5SMarc Kleine-Budde /* FIFO IRQ enable */ 22055bc37c8SMarc Kleine-Budde addr = MCP251XFD_REG_FIFOCON(rx_ring->fifo_nr); 22160a848c5SMarc Kleine-Budde val = MCP251XFD_REG_FIFOCON_RXOVIE | 22260a848c5SMarc Kleine-Budde MCP251XFD_REG_FIFOCON_TFNRFNIE; 22360a848c5SMarc Kleine-Budde len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->irq_enable_buf, 22460a848c5SMarc Kleine-Budde addr, val, val); 22560a848c5SMarc Kleine-Budde rx_ring->irq_enable_xfer.tx_buf = &rx_ring->irq_enable_buf; 22660a848c5SMarc Kleine-Budde rx_ring->irq_enable_xfer.len = len; 22760a848c5SMarc Kleine-Budde spi_message_init_with_transfers(&rx_ring->irq_enable_msg, 22860a848c5SMarc Kleine-Budde &rx_ring->irq_enable_xfer, 1); 22960a848c5SMarc Kleine-Budde 23060a848c5SMarc Kleine-Budde /* FIFO increment RX tail pointer */ 23155bc37c8SMarc Kleine-Budde val = MCP251XFD_REG_FIFOCON_UINC; 23255bc37c8SMarc Kleine-Budde len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->uinc_buf, 23355bc37c8SMarc Kleine-Budde addr, val, val); 23455bc37c8SMarc Kleine-Budde 23555bc37c8SMarc Kleine-Budde for (j = 0; j < ARRAY_SIZE(rx_ring->uinc_xfer); j++) { 23655bc37c8SMarc Kleine-Budde xfer = &rx_ring->uinc_xfer[j]; 23755bc37c8SMarc Kleine-Budde xfer->tx_buf = &rx_ring->uinc_buf; 23855bc37c8SMarc Kleine-Budde xfer->len = len; 23955bc37c8SMarc Kleine-Budde xfer->cs_change = 1; 24055bc37c8SMarc Kleine-Budde xfer->cs_change_delay.value = 0; 24155bc37c8SMarc Kleine-Budde xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; 24255bc37c8SMarc Kleine-Budde } 24355bc37c8SMarc Kleine-Budde 24455bc37c8SMarc Kleine-Budde /* "cs_change == 1" on the last transfer results in an 24555bc37c8SMarc Kleine-Budde * active chip select after the complete SPI 24655bc37c8SMarc Kleine-Budde * message. This causes the controller to interpret 24755bc37c8SMarc Kleine-Budde * the next register access as data. Set "cs_change" 24855bc37c8SMarc Kleine-Budde * of the last transfer to "0" to properly deactivate 24955bc37c8SMarc Kleine-Budde * the chip select at the end of the message. 25055bc37c8SMarc Kleine-Budde */ 25155bc37c8SMarc Kleine-Budde xfer->cs_change = 0; 25260a848c5SMarc Kleine-Budde 25360a848c5SMarc Kleine-Budde /* Use 1st RX-FIFO for IRQ coalescing. If enabled 25460a848c5SMarc Kleine-Budde * (rx_coalesce_usecs_irq or rx_max_coalesce_frames_irq 25560a848c5SMarc Kleine-Budde * is activated), use the last transfer to disable: 25660a848c5SMarc Kleine-Budde * 25760a848c5SMarc Kleine-Budde * - TFNRFNIE (Receive FIFO Not Empty Interrupt) 25860a848c5SMarc Kleine-Budde * 25960a848c5SMarc Kleine-Budde * and enable: 26060a848c5SMarc Kleine-Budde * 26160a848c5SMarc Kleine-Budde * - TFHRFHIE (Receive FIFO Half Full Interrupt) 26260a848c5SMarc Kleine-Budde * - or - 26360a848c5SMarc Kleine-Budde * - TFERFFIE (Receive FIFO Full Interrupt) 26460a848c5SMarc Kleine-Budde * 26560a848c5SMarc Kleine-Budde * depending on rx_max_coalesce_frames_irq. 26660a848c5SMarc Kleine-Budde * 26760a848c5SMarc Kleine-Budde * The RXOVIE (Overflow Interrupt) is always enabled. 26860a848c5SMarc Kleine-Budde */ 26960a848c5SMarc Kleine-Budde if (rx_ring->nr == 0 && (priv->rx_coalesce_usecs_irq || 27060a848c5SMarc Kleine-Budde priv->rx_obj_num_coalesce_irq)) { 27160a848c5SMarc Kleine-Budde val = MCP251XFD_REG_FIFOCON_UINC | 27260a848c5SMarc Kleine-Budde MCP251XFD_REG_FIFOCON_RXOVIE; 27360a848c5SMarc Kleine-Budde 27460a848c5SMarc Kleine-Budde if (priv->rx_obj_num_coalesce_irq == rx_ring->obj_num) 27560a848c5SMarc Kleine-Budde val |= MCP251XFD_REG_FIFOCON_TFERFFIE; 27660a848c5SMarc Kleine-Budde else if (priv->rx_obj_num_coalesce_irq) 27760a848c5SMarc Kleine-Budde val |= MCP251XFD_REG_FIFOCON_TFHRFHIE; 27860a848c5SMarc Kleine-Budde 27960a848c5SMarc Kleine-Budde len = mcp251xfd_cmd_prepare_write_reg(priv, 28060a848c5SMarc Kleine-Budde &rx_ring->uinc_irq_disable_buf, 28160a848c5SMarc Kleine-Budde addr, val, val); 28260a848c5SMarc Kleine-Budde xfer->tx_buf = &rx_ring->uinc_irq_disable_buf; 28360a848c5SMarc Kleine-Budde xfer->len = len; 28460a848c5SMarc Kleine-Budde } 28555bc37c8SMarc Kleine-Budde } 28655bc37c8SMarc Kleine-Budde } 28755bc37c8SMarc Kleine-Budde 288fa0b68dfSMarc Kleine-Budde int mcp251xfd_ring_init(struct mcp251xfd_priv *priv) 289d2d5397fSMarc Kleine-Budde { 29083daa863SMarc Kleine-Budde const struct mcp251xfd_rx_ring *rx_ring; 291fa0b68dfSMarc Kleine-Budde u16 base = 0, ram_used; 292617283b9SMarc Kleine-Budde u8 fifo_nr = 1; 293ac2b81ebSMarc Kleine-Budde int err = 0, i; 294617283b9SMarc Kleine-Budde 295d2d5397fSMarc Kleine-Budde netdev_reset_queue(priv->ndev); 296d2d5397fSMarc Kleine-Budde 297617283b9SMarc Kleine-Budde mcp251xfd_ring_init_tef(priv, &base); 298617283b9SMarc Kleine-Budde mcp251xfd_ring_init_rx(priv, &base, &fifo_nr); 29962713f0dSMarc Kleine-Budde mcp251xfd_ring_init_tx(priv, &base, &fifo_nr); 300fa0b68dfSMarc Kleine-Budde 301887e359dSMarc Kleine-Budde /* mcp251xfd_handle_rxif() will iterate over all RX rings. 302887e359dSMarc Kleine-Budde * Rings with their corresponding bit set in 303887e359dSMarc Kleine-Budde * priv->regs_status.rxif are read out. 304887e359dSMarc Kleine-Budde * 305887e359dSMarc Kleine-Budde * If the chip is configured for only 1 RX-FIFO, and if there 306887e359dSMarc Kleine-Budde * is an RX interrupt pending (RXIF in INT register is set), 307887e359dSMarc Kleine-Budde * it must be the 1st RX-FIFO. 308887e359dSMarc Kleine-Budde * 309887e359dSMarc Kleine-Budde * We mark the RXIF of the 1st FIFO as pending here, so that 310887e359dSMarc Kleine-Budde * we can skip the read of the RXIF register in 311887e359dSMarc Kleine-Budde * mcp251xfd_read_regs_status() for the 1 RX-FIFO only case. 312887e359dSMarc Kleine-Budde * 313887e359dSMarc Kleine-Budde * If we use more than 1 RX-FIFO, this value gets overwritten 314887e359dSMarc Kleine-Budde * in mcp251xfd_read_regs_status(), so set it unconditionally 315887e359dSMarc Kleine-Budde * here. 316887e359dSMarc Kleine-Budde */ 317887e359dSMarc Kleine-Budde priv->regs_status.rxif = BIT(priv->rx[0]->fifo_nr); 318887e359dSMarc Kleine-Budde 319169d00a2SMarc Kleine-Budde if (priv->tx_obj_num_coalesce_irq) { 320169d00a2SMarc Kleine-Budde netdev_dbg(priv->ndev, 321169d00a2SMarc Kleine-Budde "FIFO setup: TEF: 0x%03x: %2d*%zu bytes = %4zu bytes (coalesce)\n", 322169d00a2SMarc Kleine-Budde mcp251xfd_get_tef_obj_addr(0), 323169d00a2SMarc Kleine-Budde priv->tx_obj_num_coalesce_irq, 324169d00a2SMarc Kleine-Budde sizeof(struct mcp251xfd_hw_tef_obj), 325169d00a2SMarc Kleine-Budde priv->tx_obj_num_coalesce_irq * 326169d00a2SMarc Kleine-Budde sizeof(struct mcp251xfd_hw_tef_obj)); 327169d00a2SMarc Kleine-Budde 328169d00a2SMarc Kleine-Budde netdev_dbg(priv->ndev, 329169d00a2SMarc Kleine-Budde " 0x%03x: %2d*%zu bytes = %4zu bytes\n", 330169d00a2SMarc Kleine-Budde mcp251xfd_get_tef_obj_addr(priv->tx_obj_num_coalesce_irq), 331169d00a2SMarc Kleine-Budde priv->tx->obj_num - priv->tx_obj_num_coalesce_irq, 332169d00a2SMarc Kleine-Budde sizeof(struct mcp251xfd_hw_tef_obj), 333169d00a2SMarc Kleine-Budde (priv->tx->obj_num - priv->tx_obj_num_coalesce_irq) * 334169d00a2SMarc Kleine-Budde sizeof(struct mcp251xfd_hw_tef_obj)); 335169d00a2SMarc Kleine-Budde } else { 33683daa863SMarc Kleine-Budde netdev_dbg(priv->ndev, 33783daa863SMarc Kleine-Budde "FIFO setup: TEF: 0x%03x: %2d*%zu bytes = %4zu bytes\n", 33883daa863SMarc Kleine-Budde mcp251xfd_get_tef_obj_addr(0), 33983daa863SMarc Kleine-Budde priv->tx->obj_num, sizeof(struct mcp251xfd_hw_tef_obj), 34083daa863SMarc Kleine-Budde priv->tx->obj_num * sizeof(struct mcp251xfd_hw_tef_obj)); 341169d00a2SMarc Kleine-Budde } 34283daa863SMarc Kleine-Budde 34383daa863SMarc Kleine-Budde mcp251xfd_for_each_rx_ring(priv, rx_ring, i) { 34460a848c5SMarc Kleine-Budde if (rx_ring->nr == 0 && priv->rx_obj_num_coalesce_irq) { 34560a848c5SMarc Kleine-Budde netdev_dbg(priv->ndev, 34660a848c5SMarc Kleine-Budde "FIFO setup: RX-%u: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes (coalesce)\n", 34760a848c5SMarc Kleine-Budde rx_ring->nr, rx_ring->fifo_nr, 34860a848c5SMarc Kleine-Budde mcp251xfd_get_rx_obj_addr(rx_ring, 0), 34960a848c5SMarc Kleine-Budde priv->rx_obj_num_coalesce_irq, rx_ring->obj_size, 35060a848c5SMarc Kleine-Budde priv->rx_obj_num_coalesce_irq * rx_ring->obj_size); 35160a848c5SMarc Kleine-Budde 35260a848c5SMarc Kleine-Budde if (priv->rx_obj_num_coalesce_irq == MCP251XFD_FIFO_DEPTH) 35360a848c5SMarc Kleine-Budde continue; 35460a848c5SMarc Kleine-Budde 35560a848c5SMarc Kleine-Budde netdev_dbg(priv->ndev, 35660a848c5SMarc Kleine-Budde " 0x%03x: %2u*%u bytes = %4u bytes\n", 35760a848c5SMarc Kleine-Budde mcp251xfd_get_rx_obj_addr(rx_ring, 35860a848c5SMarc Kleine-Budde priv->rx_obj_num_coalesce_irq), 35960a848c5SMarc Kleine-Budde rx_ring->obj_num - priv->rx_obj_num_coalesce_irq, 36060a848c5SMarc Kleine-Budde rx_ring->obj_size, 36160a848c5SMarc Kleine-Budde (rx_ring->obj_num - priv->rx_obj_num_coalesce_irq) * 36260a848c5SMarc Kleine-Budde rx_ring->obj_size); 36360a848c5SMarc Kleine-Budde } else { 36483daa863SMarc Kleine-Budde netdev_dbg(priv->ndev, 36583daa863SMarc Kleine-Budde "FIFO setup: RX-%u: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes\n", 36683daa863SMarc Kleine-Budde rx_ring->nr, rx_ring->fifo_nr, 36783daa863SMarc Kleine-Budde mcp251xfd_get_rx_obj_addr(rx_ring, 0), 36883daa863SMarc Kleine-Budde rx_ring->obj_num, rx_ring->obj_size, 36983daa863SMarc Kleine-Budde rx_ring->obj_num * rx_ring->obj_size); 37083daa863SMarc Kleine-Budde } 37160a848c5SMarc Kleine-Budde } 37283daa863SMarc Kleine-Budde 37383daa863SMarc Kleine-Budde netdev_dbg(priv->ndev, 37483daa863SMarc Kleine-Budde "FIFO setup: TX: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes\n", 37583daa863SMarc Kleine-Budde priv->tx->fifo_nr, 37683daa863SMarc Kleine-Budde mcp251xfd_get_tx_obj_addr(priv->tx, 0), 37783daa863SMarc Kleine-Budde priv->tx->obj_num, priv->tx->obj_size, 37883daa863SMarc Kleine-Budde priv->tx->obj_num * priv->tx->obj_size); 37983daa863SMarc Kleine-Budde 38083daa863SMarc Kleine-Budde netdev_dbg(priv->ndev, 381c47675b1SMarc Kleine-Budde "FIFO setup: free: %4d bytes\n", 38283daa863SMarc Kleine-Budde MCP251XFD_RAM_SIZE - (base - MCP251XFD_RAM_START)); 38383daa863SMarc Kleine-Budde 384fa0b68dfSMarc Kleine-Budde ram_used = base - MCP251XFD_RAM_START; 385fa0b68dfSMarc Kleine-Budde if (ram_used > MCP251XFD_RAM_SIZE) { 386fa0b68dfSMarc Kleine-Budde netdev_err(priv->ndev, 387fa0b68dfSMarc Kleine-Budde "Error during ring configuration, using more RAM (%u bytes) than available (%u bytes).\n", 388fa0b68dfSMarc Kleine-Budde ram_used, MCP251XFD_RAM_SIZE); 389ac2b81ebSMarc Kleine-Budde err = -ENOMEM; 390fa0b68dfSMarc Kleine-Budde } 391fa0b68dfSMarc Kleine-Budde 392ac2b81ebSMarc Kleine-Budde if (priv->tx_obj_num_coalesce_irq && 393ac2b81ebSMarc Kleine-Budde priv->tx_obj_num_coalesce_irq * 2 != priv->tx->obj_num) { 394ac2b81ebSMarc Kleine-Budde netdev_err(priv->ndev, 395ac2b81ebSMarc Kleine-Budde "Error during ring configuration, number of TEF coalescing buffers (%u) must be half of TEF buffers (%u).\n", 396ac2b81ebSMarc Kleine-Budde priv->tx_obj_num_coalesce_irq, priv->tx->obj_num); 397ac2b81ebSMarc Kleine-Budde err = -EINVAL; 398ac2b81ebSMarc Kleine-Budde } 399ac2b81ebSMarc Kleine-Budde 400ac2b81ebSMarc Kleine-Budde return err; 401d2d5397fSMarc Kleine-Budde } 402d2d5397fSMarc Kleine-Budde 40355bc37c8SMarc Kleine-Budde void mcp251xfd_ring_free(struct mcp251xfd_priv *priv) 40455bc37c8SMarc Kleine-Budde { 40555bc37c8SMarc Kleine-Budde int i; 40655bc37c8SMarc Kleine-Budde 40755bc37c8SMarc Kleine-Budde for (i = ARRAY_SIZE(priv->rx) - 1; i >= 0; i--) { 40855bc37c8SMarc Kleine-Budde kfree(priv->rx[i]); 40955bc37c8SMarc Kleine-Budde priv->rx[i] = NULL; 41055bc37c8SMarc Kleine-Budde } 41155bc37c8SMarc Kleine-Budde } 41255bc37c8SMarc Kleine-Budde 41360a848c5SMarc Kleine-Budde static enum hrtimer_restart mcp251xfd_rx_irq_timer(struct hrtimer *t) 41460a848c5SMarc Kleine-Budde { 41560a848c5SMarc Kleine-Budde struct mcp251xfd_priv *priv = container_of(t, struct mcp251xfd_priv, 41660a848c5SMarc Kleine-Budde rx_irq_timer); 41760a848c5SMarc Kleine-Budde struct mcp251xfd_rx_ring *ring = priv->rx[0]; 41860a848c5SMarc Kleine-Budde 41960a848c5SMarc Kleine-Budde if (test_bit(MCP251XFD_FLAGS_DOWN, priv->flags)) 42060a848c5SMarc Kleine-Budde return HRTIMER_NORESTART; 42160a848c5SMarc Kleine-Budde 42260a848c5SMarc Kleine-Budde spi_async(priv->spi, &ring->irq_enable_msg); 42360a848c5SMarc Kleine-Budde 42460a848c5SMarc Kleine-Budde return HRTIMER_NORESTART; 42560a848c5SMarc Kleine-Budde } 42660a848c5SMarc Kleine-Budde 427169d00a2SMarc Kleine-Budde static enum hrtimer_restart mcp251xfd_tx_irq_timer(struct hrtimer *t) 428169d00a2SMarc Kleine-Budde { 429169d00a2SMarc Kleine-Budde struct mcp251xfd_priv *priv = container_of(t, struct mcp251xfd_priv, 430169d00a2SMarc Kleine-Budde tx_irq_timer); 431169d00a2SMarc Kleine-Budde struct mcp251xfd_tef_ring *ring = priv->tef; 432169d00a2SMarc Kleine-Budde 433169d00a2SMarc Kleine-Budde if (test_bit(MCP251XFD_FLAGS_DOWN, priv->flags)) 434169d00a2SMarc Kleine-Budde return HRTIMER_NORESTART; 435169d00a2SMarc Kleine-Budde 436169d00a2SMarc Kleine-Budde spi_async(priv->spi, &ring->irq_enable_msg); 437169d00a2SMarc Kleine-Budde 438169d00a2SMarc Kleine-Budde return HRTIMER_NORESTART; 439169d00a2SMarc Kleine-Budde } 440169d00a2SMarc Kleine-Budde 4419263c2e9SMarc Kleine-Budde const struct can_ram_config mcp251xfd_ram_config = { 4429263c2e9SMarc Kleine-Budde .rx = { 4439263c2e9SMarc Kleine-Budde .size[CAN_RAM_MODE_CAN] = sizeof(struct mcp251xfd_hw_rx_obj_can), 4449263c2e9SMarc Kleine-Budde .size[CAN_RAM_MODE_CANFD] = sizeof(struct mcp251xfd_hw_rx_obj_canfd), 4459263c2e9SMarc Kleine-Budde .min = MCP251XFD_RX_OBJ_NUM_MIN, 4469263c2e9SMarc Kleine-Budde .max = MCP251XFD_RX_OBJ_NUM_MAX, 4479263c2e9SMarc Kleine-Budde .def[CAN_RAM_MODE_CAN] = CAN_RAM_NUM_MAX, 4489263c2e9SMarc Kleine-Budde .def[CAN_RAM_MODE_CANFD] = CAN_RAM_NUM_MAX, 4499263c2e9SMarc Kleine-Budde .fifo_num = MCP251XFD_FIFO_RX_NUM, 4509263c2e9SMarc Kleine-Budde .fifo_depth_min = MCP251XFD_RX_FIFO_DEPTH_MIN, 451846990e0SMarc Kleine-Budde .fifo_depth_coalesce_min = MCP251XFD_RX_FIFO_DEPTH_COALESCE_MIN, 4529263c2e9SMarc Kleine-Budde }, 4539263c2e9SMarc Kleine-Budde .tx = { 4549263c2e9SMarc Kleine-Budde .size[CAN_RAM_MODE_CAN] = sizeof(struct mcp251xfd_hw_tef_obj) + 4559263c2e9SMarc Kleine-Budde sizeof(struct mcp251xfd_hw_tx_obj_can), 4569263c2e9SMarc Kleine-Budde .size[CAN_RAM_MODE_CANFD] = sizeof(struct mcp251xfd_hw_tef_obj) + 4579263c2e9SMarc Kleine-Budde sizeof(struct mcp251xfd_hw_tx_obj_canfd), 4589263c2e9SMarc Kleine-Budde .min = MCP251XFD_TX_OBJ_NUM_MIN, 4599263c2e9SMarc Kleine-Budde .max = MCP251XFD_TX_OBJ_NUM_MAX, 4609263c2e9SMarc Kleine-Budde .def[CAN_RAM_MODE_CAN] = MCP251XFD_TX_OBJ_NUM_CAN_DEFAULT, 4619263c2e9SMarc Kleine-Budde .def[CAN_RAM_MODE_CANFD] = MCP251XFD_TX_OBJ_NUM_CANFD_DEFAULT, 4629263c2e9SMarc Kleine-Budde .fifo_num = MCP251XFD_FIFO_TX_NUM, 4639263c2e9SMarc Kleine-Budde .fifo_depth_min = MCP251XFD_TX_FIFO_DEPTH_MIN, 464656fc12dSMarc Kleine-Budde .fifo_depth_coalesce_min = MCP251XFD_TX_FIFO_DEPTH_COALESCE_MIN, 4659263c2e9SMarc Kleine-Budde }, 4669263c2e9SMarc Kleine-Budde .size = MCP251XFD_RAM_SIZE, 4679263c2e9SMarc Kleine-Budde .fifo_depth = MCP251XFD_FIFO_DEPTH, 4689263c2e9SMarc Kleine-Budde }; 4699263c2e9SMarc Kleine-Budde 47055bc37c8SMarc Kleine-Budde int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv) 47155bc37c8SMarc Kleine-Budde { 4729263c2e9SMarc Kleine-Budde const bool fd_mode = mcp251xfd_is_fd_mode(priv); 4739263c2e9SMarc Kleine-Budde struct mcp251xfd_tx_ring *tx_ring = priv->tx; 47455bc37c8SMarc Kleine-Budde struct mcp251xfd_rx_ring *rx_ring; 4759263c2e9SMarc Kleine-Budde u8 tx_obj_size, rx_obj_size; 4760a1f2e65SMarc Kleine-Budde u8 rem, i; 47755bc37c8SMarc Kleine-Budde 4789263c2e9SMarc Kleine-Budde /* switching from CAN-2.0 to CAN-FD mode or vice versa */ 4799263c2e9SMarc Kleine-Budde if (fd_mode != test_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags)) { 48050ea5449SMarc Kleine-Budde const struct ethtool_ringparam ring = { 48150ea5449SMarc Kleine-Budde .rx_pending = priv->rx_obj_num, 48250ea5449SMarc Kleine-Budde .tx_pending = priv->tx->obj_num, 48350ea5449SMarc Kleine-Budde }; 48450ea5449SMarc Kleine-Budde const struct ethtool_coalesce ec = { 48550ea5449SMarc Kleine-Budde .rx_coalesce_usecs_irq = priv->rx_coalesce_usecs_irq, 48650ea5449SMarc Kleine-Budde .rx_max_coalesced_frames_irq = priv->rx_obj_num_coalesce_irq, 48750ea5449SMarc Kleine-Budde .tx_coalesce_usecs_irq = priv->tx_coalesce_usecs_irq, 48850ea5449SMarc Kleine-Budde .tx_max_coalesced_frames_irq = priv->tx_obj_num_coalesce_irq, 48950ea5449SMarc Kleine-Budde }; 4909263c2e9SMarc Kleine-Budde struct can_ram_layout layout; 4919263c2e9SMarc Kleine-Budde 49250ea5449SMarc Kleine-Budde can_ram_get_layout(&layout, &mcp251xfd_ram_config, &ring, &ec, fd_mode); 49350ea5449SMarc Kleine-Budde 49450ea5449SMarc Kleine-Budde priv->rx_obj_num = layout.cur_rx; 49550ea5449SMarc Kleine-Budde priv->rx_obj_num_coalesce_irq = layout.rx_coalesce; 49650ea5449SMarc Kleine-Budde 49750ea5449SMarc Kleine-Budde tx_ring->obj_num = layout.cur_tx; 49850ea5449SMarc Kleine-Budde priv->tx_obj_num_coalesce_irq = layout.tx_coalesce; 49955bc37c8SMarc Kleine-Budde } 50055bc37c8SMarc Kleine-Budde 5019263c2e9SMarc Kleine-Budde if (fd_mode) { 5029263c2e9SMarc Kleine-Budde tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_canfd); 5039263c2e9SMarc Kleine-Budde rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_canfd); 5049263c2e9SMarc Kleine-Budde set_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags); 5059263c2e9SMarc Kleine-Budde } else { 5069263c2e9SMarc Kleine-Budde tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_can); 5079263c2e9SMarc Kleine-Budde rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_can); 5089263c2e9SMarc Kleine-Budde clear_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags); 5099263c2e9SMarc Kleine-Budde } 510d86ba8dbSMarc Kleine-Budde 511b8e0ddd3SMarc Kleine-Budde tx_ring->obj_num_shift_to_u8 = BITS_PER_TYPE(tx_ring->obj_num) - 512b8e0ddd3SMarc Kleine-Budde ilog2(tx_ring->obj_num); 51355bc37c8SMarc Kleine-Budde tx_ring->obj_size = tx_obj_size; 51455bc37c8SMarc Kleine-Budde 5159263c2e9SMarc Kleine-Budde rem = priv->rx_obj_num; 5160a1f2e65SMarc Kleine-Budde for (i = 0; i < ARRAY_SIZE(priv->rx) && rem; i++) { 5170a1f2e65SMarc Kleine-Budde u8 rx_obj_num; 51855bc37c8SMarc Kleine-Budde 51960a848c5SMarc Kleine-Budde if (i == 0 && priv->rx_obj_num_coalesce_irq) 52060a848c5SMarc Kleine-Budde rx_obj_num = min_t(u8, priv->rx_obj_num_coalesce_irq * 2, 52160a848c5SMarc Kleine-Budde MCP251XFD_FIFO_DEPTH); 52260a848c5SMarc Kleine-Budde else 5230a1f2e65SMarc Kleine-Budde rx_obj_num = min_t(u8, rounddown_pow_of_two(rem), 5240a1f2e65SMarc Kleine-Budde MCP251XFD_FIFO_DEPTH); 5250a1f2e65SMarc Kleine-Budde rem -= rx_obj_num; 52655bc37c8SMarc Kleine-Budde 52755bc37c8SMarc Kleine-Budde rx_ring = kzalloc(sizeof(*rx_ring) + rx_obj_size * rx_obj_num, 52855bc37c8SMarc Kleine-Budde GFP_KERNEL); 52955bc37c8SMarc Kleine-Budde if (!rx_ring) { 53055bc37c8SMarc Kleine-Budde mcp251xfd_ring_free(priv); 53155bc37c8SMarc Kleine-Budde return -ENOMEM; 53255bc37c8SMarc Kleine-Budde } 5330a1f2e65SMarc Kleine-Budde 53455bc37c8SMarc Kleine-Budde rx_ring->obj_num = rx_obj_num; 53585505e58SMarc Kleine-Budde rx_ring->obj_num_shift_to_u8 = BITS_PER_TYPE(rx_ring->obj_num_shift_to_u8) - 53685505e58SMarc Kleine-Budde ilog2(rx_obj_num); 53755bc37c8SMarc Kleine-Budde rx_ring->obj_size = rx_obj_size; 53855bc37c8SMarc Kleine-Budde priv->rx[i] = rx_ring; 53955bc37c8SMarc Kleine-Budde } 54055bc37c8SMarc Kleine-Budde priv->rx_ring_num = i; 54155bc37c8SMarc Kleine-Budde 54260a848c5SMarc Kleine-Budde hrtimer_init(&priv->rx_irq_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 54360a848c5SMarc Kleine-Budde priv->rx_irq_timer.function = mcp251xfd_rx_irq_timer; 54460a848c5SMarc Kleine-Budde 545169d00a2SMarc Kleine-Budde hrtimer_init(&priv->tx_irq_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 546169d00a2SMarc Kleine-Budde priv->tx_irq_timer.function = mcp251xfd_tx_irq_timer; 547169d00a2SMarc Kleine-Budde 54855bc37c8SMarc Kleine-Budde return 0; 54955bc37c8SMarc Kleine-Budde } 550