linux/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
   4//
   5// Copyright (c) 2019, 2020, 2021 Pengutronix,
   6//               Marc Kleine-Budde <kernel@pengutronix.de>
   7//
   8// Based on:
   9//
  10// CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
  11//
  12// Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
  13//
  14
  15#include <asm/unaligned.h>
  16
  17#include "mcp251xfd.h"
  18
  19static inline u8
  20mcp251xfd_cmd_prepare_write_reg(const struct mcp251xfd_priv *priv,
  21                                union mcp251xfd_write_reg_buf *write_reg_buf,
  22                                const u16 reg, const u32 mask, const u32 val)
  23{
  24        u8 first_byte, last_byte, len;
  25        u8 *data;
  26        __le32 val_le32;
  27
  28        first_byte = mcp251xfd_first_byte_set(mask);
  29        last_byte = mcp251xfd_last_byte_set(mask);
  30        len = last_byte - first_byte + 1;
  31
  32        data = mcp251xfd_spi_cmd_write(priv, write_reg_buf, reg + first_byte);
  33        val_le32 = cpu_to_le32(val >> BITS_PER_BYTE * first_byte);
  34        memcpy(data, &val_le32, len);
  35
  36        if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) {
  37                u16 crc;
  38
  39                mcp251xfd_spi_cmd_crc_set_len_in_reg(&write_reg_buf->crc.cmd,
  40                                                     len);
  41                /* CRC */
  42                len += sizeof(write_reg_buf->crc.cmd);
  43                crc = mcp251xfd_crc16_compute(&write_reg_buf->crc, len);
  44                put_unaligned_be16(crc, (void *)write_reg_buf + len);
  45
  46                /* Total length */
  47                len += sizeof(write_reg_buf->crc.crc);
  48        } else {
  49                len += sizeof(write_reg_buf->nocrc.cmd);
  50        }
  51
  52        return len;
  53}
  54
  55static void
  56mcp251xfd_tx_ring_init_tx_obj(const struct mcp251xfd_priv *priv,
  57                              const struct mcp251xfd_tx_ring *ring,
  58                              struct mcp251xfd_tx_obj *tx_obj,
  59                              const u8 rts_buf_len,
  60                              const u8 n)
  61{
  62        struct spi_transfer *xfer;
  63        u16 addr;
  64
  65        /* FIFO load */
  66        addr = mcp251xfd_get_tx_obj_addr(ring, n);
  67        if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_TX)
  68                mcp251xfd_spi_cmd_write_crc_set_addr(&tx_obj->buf.crc.cmd,
  69                                                     addr);
  70        else
  71                mcp251xfd_spi_cmd_write_nocrc(&tx_obj->buf.nocrc.cmd,
  72                                              addr);
  73
  74        xfer = &tx_obj->xfer[0];
  75        xfer->tx_buf = &tx_obj->buf;
  76        xfer->len = 0;  /* actual len is assigned on the fly */
  77        xfer->cs_change = 1;
  78        xfer->cs_change_delay.value = 0;
  79        xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
  80
  81        /* FIFO request to send */
  82        xfer = &tx_obj->xfer[1];
  83        xfer->tx_buf = &ring->rts_buf;
  84        xfer->len = rts_buf_len;
  85
  86        /* SPI message */
  87        spi_message_init_with_transfers(&tx_obj->msg, tx_obj->xfer,
  88                                        ARRAY_SIZE(tx_obj->xfer));
  89}
  90
  91void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
  92{
  93        struct mcp251xfd_tef_ring *tef_ring;
  94        struct mcp251xfd_tx_ring *tx_ring;
  95        struct mcp251xfd_rx_ring *rx_ring, *prev_rx_ring = NULL;
  96        struct mcp251xfd_tx_obj *tx_obj;
  97        struct spi_transfer *xfer;
  98        u32 val;
  99        u16 addr;
 100        u8 len;
 101        int i, j;
 102
 103        netdev_reset_queue(priv->ndev);
 104
 105        /* TEF */
 106        tef_ring = priv->tef;
 107        tef_ring->head = 0;
 108        tef_ring->tail = 0;
 109
 110        /* FIFO increment TEF tail pointer */
 111        addr = MCP251XFD_REG_TEFCON;
 112        val = MCP251XFD_REG_TEFCON_UINC;
 113        len = mcp251xfd_cmd_prepare_write_reg(priv, &tef_ring->uinc_buf,
 114                                              addr, val, val);
 115
 116        for (j = 0; j < ARRAY_SIZE(tef_ring->uinc_xfer); j++) {
 117                xfer = &tef_ring->uinc_xfer[j];
 118                xfer->tx_buf = &tef_ring->uinc_buf;
 119                xfer->len = len;
 120                xfer->cs_change = 1;
 121                xfer->cs_change_delay.value = 0;
 122                xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
 123        }
 124
 125        /* "cs_change == 1" on the last transfer results in an active
 126         * chip select after the complete SPI message. This causes the
 127         * controller to interpret the next register access as
 128         * data. Set "cs_change" of the last transfer to "0" to
 129         * properly deactivate the chip select at the end of the
 130         * message.
 131         */
 132        xfer->cs_change = 0;
 133
 134        /* TX */
 135        tx_ring = priv->tx;
 136        tx_ring->head = 0;
 137        tx_ring->tail = 0;
 138        tx_ring->base = mcp251xfd_get_tef_obj_addr(tx_ring->obj_num);
 139
 140        /* FIFO request to send */
 141        addr = MCP251XFD_REG_FIFOCON(MCP251XFD_TX_FIFO);
 142        val = MCP251XFD_REG_FIFOCON_TXREQ | MCP251XFD_REG_FIFOCON_UINC;
 143        len = mcp251xfd_cmd_prepare_write_reg(priv, &tx_ring->rts_buf,
 144                                              addr, val, val);
 145
 146        mcp251xfd_for_each_tx_obj(tx_ring, tx_obj, i)
 147                mcp251xfd_tx_ring_init_tx_obj(priv, tx_ring, tx_obj, len, i);
 148
 149        /* RX */
 150        mcp251xfd_for_each_rx_ring(priv, rx_ring, i) {
 151                rx_ring->head = 0;
 152                rx_ring->tail = 0;
 153                rx_ring->nr = i;
 154                rx_ring->fifo_nr = MCP251XFD_RX_FIFO(i);
 155
 156                if (!prev_rx_ring)
 157                        rx_ring->base =
 158                                mcp251xfd_get_tx_obj_addr(tx_ring,
 159                                                          tx_ring->obj_num);
 160                else
 161                        rx_ring->base = prev_rx_ring->base +
 162                                prev_rx_ring->obj_size *
 163                                prev_rx_ring->obj_num;
 164
 165                prev_rx_ring = rx_ring;
 166
 167                /* FIFO increment RX tail pointer */
 168                addr = MCP251XFD_REG_FIFOCON(rx_ring->fifo_nr);
 169                val = MCP251XFD_REG_FIFOCON_UINC;
 170                len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->uinc_buf,
 171                                                      addr, val, val);
 172
 173                for (j = 0; j < ARRAY_SIZE(rx_ring->uinc_xfer); j++) {
 174                        xfer = &rx_ring->uinc_xfer[j];
 175                        xfer->tx_buf = &rx_ring->uinc_buf;
 176                        xfer->len = len;
 177                        xfer->cs_change = 1;
 178                        xfer->cs_change_delay.value = 0;
 179                        xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
 180                }
 181
 182                /* "cs_change == 1" on the last transfer results in an
 183                 * active chip select after the complete SPI
 184                 * message. This causes the controller to interpret
 185                 * the next register access as data. Set "cs_change"
 186                 * of the last transfer to "0" to properly deactivate
 187                 * the chip select at the end of the message.
 188                 */
 189                xfer->cs_change = 0;
 190        }
 191}
 192
 193void mcp251xfd_ring_free(struct mcp251xfd_priv *priv)
 194{
 195        int i;
 196
 197        for (i = ARRAY_SIZE(priv->rx) - 1; i >= 0; i--) {
 198                kfree(priv->rx[i]);
 199                priv->rx[i] = NULL;
 200        }
 201}
 202
 203int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
 204{
 205        struct mcp251xfd_tx_ring *tx_ring;
 206        struct mcp251xfd_rx_ring *rx_ring;
 207        int tef_obj_size, tx_obj_size, rx_obj_size;
 208        int tx_obj_num;
 209        int ram_free, i;
 210
 211        tef_obj_size = sizeof(struct mcp251xfd_hw_tef_obj);
 212        if (mcp251xfd_is_fd_mode(priv)) {
 213                tx_obj_num = MCP251XFD_TX_OBJ_NUM_CANFD;
 214                tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_canfd);
 215                rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_canfd);
 216        } else {
 217                tx_obj_num = MCP251XFD_TX_OBJ_NUM_CAN;
 218                tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_can);
 219                rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_can);
 220        }
 221
 222        tx_ring = priv->tx;
 223        tx_ring->obj_num = tx_obj_num;
 224        tx_ring->obj_size = tx_obj_size;
 225
 226        ram_free = MCP251XFD_RAM_SIZE - tx_obj_num *
 227                (tef_obj_size + tx_obj_size);
 228
 229        for (i = 0;
 230             i < ARRAY_SIZE(priv->rx) && ram_free >= rx_obj_size;
 231             i++) {
 232                int rx_obj_num;
 233
 234                rx_obj_num = ram_free / rx_obj_size;
 235                rx_obj_num = min(1 << (fls(rx_obj_num) - 1),
 236                                 MCP251XFD_RX_OBJ_NUM_MAX);
 237
 238                rx_ring = kzalloc(sizeof(*rx_ring) + rx_obj_size * rx_obj_num,
 239                                  GFP_KERNEL);
 240                if (!rx_ring) {
 241                        mcp251xfd_ring_free(priv);
 242                        return -ENOMEM;
 243                }
 244                rx_ring->obj_num = rx_obj_num;
 245                rx_ring->obj_size = rx_obj_size;
 246                priv->rx[i] = rx_ring;
 247
 248                ram_free -= rx_ring->obj_num * rx_ring->obj_size;
 249        }
 250        priv->rx_ring_num = i;
 251
 252        netdev_dbg(priv->ndev,
 253                   "FIFO setup: TEF: %d*%d bytes = %d bytes, TX: %d*%d bytes = %d bytes\n",
 254                   tx_obj_num, tef_obj_size, tef_obj_size * tx_obj_num,
 255                   tx_obj_num, tx_obj_size, tx_obj_size * tx_obj_num);
 256
 257        mcp251xfd_for_each_rx_ring(priv, rx_ring, i) {
 258                netdev_dbg(priv->ndev,
 259                           "FIFO setup: RX-%d: %d*%d bytes = %d bytes\n",
 260                           i, rx_ring->obj_num, rx_ring->obj_size,
 261                           rx_ring->obj_size * rx_ring->obj_num);
 262        }
 263
 264        netdev_dbg(priv->ndev,
 265                   "FIFO setup: free: %d bytes\n",
 266                   ram_free);
 267
 268        return 0;
 269}
 270