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#include <linux/bitfield.h>
17
18#include "mcp251xfd.h"
19
20static inline struct
21mcp251xfd_tx_obj *mcp251xfd_get_tx_obj_next(struct mcp251xfd_tx_ring *tx_ring)
22{
23 u8 tx_head;
24
25 tx_head = mcp251xfd_get_tx_head(ring: tx_ring);
26
27 return &tx_ring->obj[tx_head];
28}
29
30static void
31mcp251xfd_tx_obj_from_skb(const struct mcp251xfd_priv *priv,
32 struct mcp251xfd_tx_obj *tx_obj,
33 const struct sk_buff *skb,
34 unsigned int seq)
35{
36 const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
37 struct mcp251xfd_hw_tx_obj_raw *hw_tx_obj;
38 union mcp251xfd_tx_obj_load_buf *load_buf;
39 u8 dlc;
40 u32 id, flags;
41 int len_sanitized = 0, len;
42
43 if (cfd->can_id & CAN_EFF_FLAG) {
44 u32 sid, eid;
45
46 sid = FIELD_GET(MCP251XFD_REG_FRAME_EFF_SID_MASK, cfd->can_id);
47 eid = FIELD_GET(MCP251XFD_REG_FRAME_EFF_EID_MASK, cfd->can_id);
48
49 id = FIELD_PREP(MCP251XFD_OBJ_ID_EID_MASK, eid) |
50 FIELD_PREP(MCP251XFD_OBJ_ID_SID_MASK, sid);
51
52 flags = MCP251XFD_OBJ_FLAGS_IDE;
53 } else {
54 id = FIELD_PREP(MCP251XFD_OBJ_ID_SID_MASK, cfd->can_id);
55 flags = 0;
56 }
57
58 /* Use the MCP2518FD mask even on the MCP2517FD. It doesn't
59 * harm, only the lower 7 bits will be transferred into the
60 * TEF object.
61 */
62 flags |= FIELD_PREP(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK, seq);
63
64 if (cfd->can_id & CAN_RTR_FLAG)
65 flags |= MCP251XFD_OBJ_FLAGS_RTR;
66 else
67 len_sanitized = canfd_sanitize_len(len: cfd->len);
68
69 /* CANFD */
70 if (can_is_canfd_skb(skb)) {
71 if (cfd->flags & CANFD_ESI)
72 flags |= MCP251XFD_OBJ_FLAGS_ESI;
73
74 flags |= MCP251XFD_OBJ_FLAGS_FDF;
75
76 if (cfd->flags & CANFD_BRS)
77 flags |= MCP251XFD_OBJ_FLAGS_BRS;
78
79 dlc = can_fd_len2dlc(len: cfd->len);
80 } else {
81 dlc = can_get_cc_dlc(cf: (struct can_frame *)cfd,
82 ctrlmode: priv->can.ctrlmode);
83 }
84
85 flags |= FIELD_PREP(MCP251XFD_OBJ_FLAGS_DLC_MASK, dlc);
86
87 load_buf = &tx_obj->buf;
88 if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_TX)
89 hw_tx_obj = &load_buf->crc.hw_tx_obj;
90 else
91 hw_tx_obj = &load_buf->nocrc.hw_tx_obj;
92
93 put_unaligned_le32(val: id, p: &hw_tx_obj->id);
94 put_unaligned_le32(val: flags, p: &hw_tx_obj->flags);
95
96 /* Copy data */
97 memcpy(hw_tx_obj->data, cfd->data, cfd->len);
98
99 /* Clear unused data at end of CAN frame */
100 if (MCP251XFD_SANITIZE_CAN && len_sanitized) {
101 int pad_len;
102
103 pad_len = len_sanitized - cfd->len;
104 if (pad_len)
105 memset(hw_tx_obj->data + cfd->len, 0x0, pad_len);
106 }
107
108 /* Number of bytes to be written into the RAM of the controller */
109 len = sizeof(hw_tx_obj->id) + sizeof(hw_tx_obj->flags);
110 if (MCP251XFD_SANITIZE_CAN)
111 len += round_up(len_sanitized, sizeof(u32));
112 else
113 len += round_up(cfd->len, sizeof(u32));
114
115 if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_TX) {
116 u16 crc;
117
118 mcp251xfd_spi_cmd_crc_set_len_in_ram(cmd: &load_buf->crc.cmd,
119 len);
120 /* CRC */
121 len += sizeof(load_buf->crc.cmd);
122 crc = mcp251xfd_crc16_compute(data: &load_buf->crc, data_size: len);
123 put_unaligned_be16(val: crc, p: (void *)load_buf + len);
124
125 /* Total length */
126 len += sizeof(load_buf->crc.crc);
127 } else {
128 len += sizeof(load_buf->nocrc.cmd);
129 }
130
131 tx_obj->xfer[0].len = len;
132}
133
134static int mcp251xfd_tx_obj_write(const struct mcp251xfd_priv *priv,
135 struct mcp251xfd_tx_obj *tx_obj)
136{
137 return spi_async(spi: priv->spi, message: &tx_obj->msg);
138}
139
140static bool mcp251xfd_tx_busy(const struct mcp251xfd_priv *priv,
141 struct mcp251xfd_tx_ring *tx_ring)
142{
143 if (mcp251xfd_get_tx_free(ring: tx_ring) > 0)
144 return false;
145
146 netif_stop_queue(dev: priv->ndev);
147
148 /* Memory barrier before checking tx_free (head and tail) */
149 smp_mb();
150
151 if (mcp251xfd_get_tx_free(ring: tx_ring) == 0) {
152 netdev_dbg(priv->ndev,
153 "Stopping tx-queue (tx_head=0x%08x, tx_tail=0x%08x, len=%d).\n",
154 tx_ring->head, tx_ring->tail,
155 tx_ring->head - tx_ring->tail);
156
157 return true;
158 }
159
160 netif_start_queue(dev: priv->ndev);
161
162 return false;
163}
164
165netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
166 struct net_device *ndev)
167{
168 struct mcp251xfd_priv *priv = netdev_priv(dev: ndev);
169 struct mcp251xfd_tx_ring *tx_ring = priv->tx;
170 struct mcp251xfd_tx_obj *tx_obj;
171 unsigned int frame_len;
172 u8 tx_head;
173 int err;
174
175 if (can_dev_dropped_skb(dev: ndev, skb))
176 return NETDEV_TX_OK;
177
178 if (mcp251xfd_tx_busy(priv, tx_ring))
179 return NETDEV_TX_BUSY;
180
181 tx_obj = mcp251xfd_get_tx_obj_next(tx_ring);
182 mcp251xfd_tx_obj_from_skb(priv, tx_obj, skb, seq: tx_ring->head);
183
184 /* Stop queue if we occupy the complete TX FIFO */
185 tx_head = mcp251xfd_get_tx_head(ring: tx_ring);
186 tx_ring->head++;
187 if (mcp251xfd_get_tx_free(ring: tx_ring) == 0)
188 netif_stop_queue(dev: ndev);
189
190 frame_len = can_skb_get_frame_len(skb);
191 err = can_put_echo_skb(skb, dev: ndev, idx: tx_head, frame_len);
192 if (!err)
193 netdev_sent_queue(dev: priv->ndev, bytes: frame_len);
194
195 err = mcp251xfd_tx_obj_write(priv, tx_obj);
196 if (err)
197 goto out_err;
198
199 return NETDEV_TX_OK;
200
201 out_err:
202 netdev_err(dev: priv->ndev, format: "ERROR in %s: %d\n", __func__, err);
203
204 return NETDEV_TX_OK;
205}
206

source code of linux/drivers/net/can/spi/mcp251xfd/mcp251xfd-tx.c