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