xref: /openbmc/linux/drivers/net/can/spi/mcp251xfd/mcp251xfd-tx.c (revision f91ca89e924eb287915522664a31afc71a49c05b)
109b0eb92SMarc Kleine-Budde // SPDX-License-Identifier: GPL-2.0
209b0eb92SMarc Kleine-Budde //
309b0eb92SMarc Kleine-Budde // mcp251xfd - Microchip MCP251xFD Family CAN controller driver
409b0eb92SMarc Kleine-Budde //
509b0eb92SMarc Kleine-Budde // Copyright (c) 2019, 2020, 2021 Pengutronix,
609b0eb92SMarc Kleine-Budde //               Marc Kleine-Budde <kernel@pengutronix.de>
709b0eb92SMarc Kleine-Budde //
809b0eb92SMarc Kleine-Budde // Based on:
909b0eb92SMarc Kleine-Budde //
1009b0eb92SMarc Kleine-Budde // CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
1109b0eb92SMarc Kleine-Budde //
1209b0eb92SMarc Kleine-Budde // Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
1309b0eb92SMarc Kleine-Budde //
1409b0eb92SMarc Kleine-Budde 
1509b0eb92SMarc Kleine-Budde #include <asm/unaligned.h>
1609b0eb92SMarc Kleine-Budde #include <linux/bitfield.h>
1709b0eb92SMarc Kleine-Budde 
1809b0eb92SMarc Kleine-Budde #include "mcp251xfd.h"
1909b0eb92SMarc Kleine-Budde 
2009b0eb92SMarc Kleine-Budde static inline struct
mcp251xfd_get_tx_obj_next(struct mcp251xfd_tx_ring * tx_ring)2109b0eb92SMarc Kleine-Budde mcp251xfd_tx_obj *mcp251xfd_get_tx_obj_next(struct mcp251xfd_tx_ring *tx_ring)
2209b0eb92SMarc Kleine-Budde {
2309b0eb92SMarc Kleine-Budde 	u8 tx_head;
2409b0eb92SMarc Kleine-Budde 
2509b0eb92SMarc Kleine-Budde 	tx_head = mcp251xfd_get_tx_head(tx_ring);
2609b0eb92SMarc Kleine-Budde 
2709b0eb92SMarc Kleine-Budde 	return &tx_ring->obj[tx_head];
2809b0eb92SMarc Kleine-Budde }
2909b0eb92SMarc Kleine-Budde 
3009b0eb92SMarc Kleine-Budde static void
mcp251xfd_tx_obj_from_skb(const struct mcp251xfd_priv * priv,struct mcp251xfd_tx_obj * tx_obj,const struct sk_buff * skb,unsigned int seq)3109b0eb92SMarc Kleine-Budde mcp251xfd_tx_obj_from_skb(const struct mcp251xfd_priv *priv,
3209b0eb92SMarc Kleine-Budde 			  struct mcp251xfd_tx_obj *tx_obj,
3309b0eb92SMarc Kleine-Budde 			  const struct sk_buff *skb,
3409b0eb92SMarc Kleine-Budde 			  unsigned int seq)
3509b0eb92SMarc Kleine-Budde {
3609b0eb92SMarc Kleine-Budde 	const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
3709b0eb92SMarc Kleine-Budde 	struct mcp251xfd_hw_tx_obj_raw *hw_tx_obj;
3809b0eb92SMarc Kleine-Budde 	union mcp251xfd_tx_obj_load_buf *load_buf;
3909b0eb92SMarc Kleine-Budde 	u8 dlc;
4009b0eb92SMarc Kleine-Budde 	u32 id, flags;
4109b0eb92SMarc Kleine-Budde 	int len_sanitized = 0, len;
4209b0eb92SMarc Kleine-Budde 
4309b0eb92SMarc Kleine-Budde 	if (cfd->can_id & CAN_EFF_FLAG) {
4409b0eb92SMarc Kleine-Budde 		u32 sid, eid;
4509b0eb92SMarc Kleine-Budde 
4609b0eb92SMarc Kleine-Budde 		sid = FIELD_GET(MCP251XFD_REG_FRAME_EFF_SID_MASK, cfd->can_id);
4709b0eb92SMarc Kleine-Budde 		eid = FIELD_GET(MCP251XFD_REG_FRAME_EFF_EID_MASK, cfd->can_id);
4809b0eb92SMarc Kleine-Budde 
4909b0eb92SMarc Kleine-Budde 		id = FIELD_PREP(MCP251XFD_OBJ_ID_EID_MASK, eid) |
5009b0eb92SMarc Kleine-Budde 			FIELD_PREP(MCP251XFD_OBJ_ID_SID_MASK, sid);
5109b0eb92SMarc Kleine-Budde 
5209b0eb92SMarc Kleine-Budde 		flags = MCP251XFD_OBJ_FLAGS_IDE;
5309b0eb92SMarc Kleine-Budde 	} else {
5409b0eb92SMarc Kleine-Budde 		id = FIELD_PREP(MCP251XFD_OBJ_ID_SID_MASK, cfd->can_id);
5509b0eb92SMarc Kleine-Budde 		flags = 0;
5609b0eb92SMarc Kleine-Budde 	}
5709b0eb92SMarc Kleine-Budde 
5809b0eb92SMarc Kleine-Budde 	/* Use the MCP2518FD mask even on the MCP2517FD. It doesn't
5909b0eb92SMarc Kleine-Budde 	 * harm, only the lower 7 bits will be transferred into the
6009b0eb92SMarc Kleine-Budde 	 * TEF object.
6109b0eb92SMarc Kleine-Budde 	 */
6209b0eb92SMarc Kleine-Budde 	flags |= FIELD_PREP(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK, seq);
6309b0eb92SMarc Kleine-Budde 
6409b0eb92SMarc Kleine-Budde 	if (cfd->can_id & CAN_RTR_FLAG)
6509b0eb92SMarc Kleine-Budde 		flags |= MCP251XFD_OBJ_FLAGS_RTR;
6609b0eb92SMarc Kleine-Budde 	else
6709b0eb92SMarc Kleine-Budde 		len_sanitized = canfd_sanitize_len(cfd->len);
6809b0eb92SMarc Kleine-Budde 
6909b0eb92SMarc Kleine-Budde 	/* CANFD */
7009b0eb92SMarc Kleine-Budde 	if (can_is_canfd_skb(skb)) {
7109b0eb92SMarc Kleine-Budde 		if (cfd->flags & CANFD_ESI)
7209b0eb92SMarc Kleine-Budde 			flags |= MCP251XFD_OBJ_FLAGS_ESI;
7309b0eb92SMarc Kleine-Budde 
7409b0eb92SMarc Kleine-Budde 		flags |= MCP251XFD_OBJ_FLAGS_FDF;
7509b0eb92SMarc Kleine-Budde 
7609b0eb92SMarc Kleine-Budde 		if (cfd->flags & CANFD_BRS)
7709b0eb92SMarc Kleine-Budde 			flags |= MCP251XFD_OBJ_FLAGS_BRS;
7809b0eb92SMarc Kleine-Budde 
7909b0eb92SMarc Kleine-Budde 		dlc = can_fd_len2dlc(cfd->len);
8009b0eb92SMarc Kleine-Budde 	} else {
8109b0eb92SMarc Kleine-Budde 		dlc = can_get_cc_dlc((struct can_frame *)cfd,
8209b0eb92SMarc Kleine-Budde 				     priv->can.ctrlmode);
8309b0eb92SMarc Kleine-Budde 	}
8409b0eb92SMarc Kleine-Budde 
8509b0eb92SMarc Kleine-Budde 	flags |= FIELD_PREP(MCP251XFD_OBJ_FLAGS_DLC_MASK, dlc);
8609b0eb92SMarc Kleine-Budde 
8709b0eb92SMarc Kleine-Budde 	load_buf = &tx_obj->buf;
8809b0eb92SMarc Kleine-Budde 	if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_TX)
8909b0eb92SMarc Kleine-Budde 		hw_tx_obj = &load_buf->crc.hw_tx_obj;
9009b0eb92SMarc Kleine-Budde 	else
9109b0eb92SMarc Kleine-Budde 		hw_tx_obj = &load_buf->nocrc.hw_tx_obj;
9209b0eb92SMarc Kleine-Budde 
9309b0eb92SMarc Kleine-Budde 	put_unaligned_le32(id, &hw_tx_obj->id);
9409b0eb92SMarc Kleine-Budde 	put_unaligned_le32(flags, &hw_tx_obj->flags);
9509b0eb92SMarc Kleine-Budde 
9609b0eb92SMarc Kleine-Budde 	/* Copy data */
9709b0eb92SMarc Kleine-Budde 	memcpy(hw_tx_obj->data, cfd->data, cfd->len);
9809b0eb92SMarc Kleine-Budde 
9909b0eb92SMarc Kleine-Budde 	/* Clear unused data at end of CAN frame */
10009b0eb92SMarc Kleine-Budde 	if (MCP251XFD_SANITIZE_CAN && len_sanitized) {
10109b0eb92SMarc Kleine-Budde 		int pad_len;
10209b0eb92SMarc Kleine-Budde 
10309b0eb92SMarc Kleine-Budde 		pad_len = len_sanitized - cfd->len;
10409b0eb92SMarc Kleine-Budde 		if (pad_len)
10509b0eb92SMarc Kleine-Budde 			memset(hw_tx_obj->data + cfd->len, 0x0, pad_len);
10609b0eb92SMarc Kleine-Budde 	}
10709b0eb92SMarc Kleine-Budde 
10809b0eb92SMarc Kleine-Budde 	/* Number of bytes to be written into the RAM of the controller */
10909b0eb92SMarc Kleine-Budde 	len = sizeof(hw_tx_obj->id) + sizeof(hw_tx_obj->flags);
11009b0eb92SMarc Kleine-Budde 	if (MCP251XFD_SANITIZE_CAN)
11109b0eb92SMarc Kleine-Budde 		len += round_up(len_sanitized, sizeof(u32));
11209b0eb92SMarc Kleine-Budde 	else
11309b0eb92SMarc Kleine-Budde 		len += round_up(cfd->len, sizeof(u32));
11409b0eb92SMarc Kleine-Budde 
11509b0eb92SMarc Kleine-Budde 	if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_TX) {
11609b0eb92SMarc Kleine-Budde 		u16 crc;
11709b0eb92SMarc Kleine-Budde 
11809b0eb92SMarc Kleine-Budde 		mcp251xfd_spi_cmd_crc_set_len_in_ram(&load_buf->crc.cmd,
11909b0eb92SMarc Kleine-Budde 						     len);
12009b0eb92SMarc Kleine-Budde 		/* CRC */
12109b0eb92SMarc Kleine-Budde 		len += sizeof(load_buf->crc.cmd);
12209b0eb92SMarc Kleine-Budde 		crc = mcp251xfd_crc16_compute(&load_buf->crc, len);
12309b0eb92SMarc Kleine-Budde 		put_unaligned_be16(crc, (void *)load_buf + len);
12409b0eb92SMarc Kleine-Budde 
12509b0eb92SMarc Kleine-Budde 		/* Total length */
12609b0eb92SMarc Kleine-Budde 		len += sizeof(load_buf->crc.crc);
12709b0eb92SMarc Kleine-Budde 	} else {
12809b0eb92SMarc Kleine-Budde 		len += sizeof(load_buf->nocrc.cmd);
12909b0eb92SMarc Kleine-Budde 	}
13009b0eb92SMarc Kleine-Budde 
13109b0eb92SMarc Kleine-Budde 	tx_obj->xfer[0].len = len;
13209b0eb92SMarc Kleine-Budde }
13309b0eb92SMarc Kleine-Budde 
mcp251xfd_tx_failure_drop(const struct mcp251xfd_priv * priv,struct mcp251xfd_tx_ring * tx_ring,int err)134*3e72558cSVitor Soares static void mcp251xfd_tx_failure_drop(const struct mcp251xfd_priv *priv,
135*3e72558cSVitor Soares 				      struct mcp251xfd_tx_ring *tx_ring,
136*3e72558cSVitor Soares 				      int err)
137*3e72558cSVitor Soares {
138*3e72558cSVitor Soares 	struct net_device *ndev = priv->ndev;
139*3e72558cSVitor Soares 	struct net_device_stats *stats = &ndev->stats;
140*3e72558cSVitor Soares 	unsigned int frame_len = 0;
141*3e72558cSVitor Soares 	u8 tx_head;
142*3e72558cSVitor Soares 
143*3e72558cSVitor Soares 	tx_ring->head--;
144*3e72558cSVitor Soares 	stats->tx_dropped++;
145*3e72558cSVitor Soares 	tx_head = mcp251xfd_get_tx_head(tx_ring);
146*3e72558cSVitor Soares 	can_free_echo_skb(ndev, tx_head, &frame_len);
147*3e72558cSVitor Soares 	netdev_completed_queue(ndev, 1, frame_len);
148*3e72558cSVitor Soares 	netif_wake_queue(ndev);
149*3e72558cSVitor Soares 
150*3e72558cSVitor Soares 	if (net_ratelimit())
151*3e72558cSVitor Soares 		netdev_err(priv->ndev, "ERROR in %s: %d\n", __func__, err);
152*3e72558cSVitor Soares }
153*3e72558cSVitor Soares 
mcp251xfd_tx_obj_write_sync(struct work_struct * work)154*3e72558cSVitor Soares void mcp251xfd_tx_obj_write_sync(struct work_struct *work)
155*3e72558cSVitor Soares {
156*3e72558cSVitor Soares 	struct mcp251xfd_priv *priv = container_of(work, struct mcp251xfd_priv,
157*3e72558cSVitor Soares 						   tx_work);
158*3e72558cSVitor Soares 	struct mcp251xfd_tx_obj *tx_obj = priv->tx_work_obj;
159*3e72558cSVitor Soares 	struct mcp251xfd_tx_ring *tx_ring = priv->tx;
160*3e72558cSVitor Soares 	int err;
161*3e72558cSVitor Soares 
162*3e72558cSVitor Soares 	err = spi_sync(priv->spi, &tx_obj->msg);
163*3e72558cSVitor Soares 	if (err)
164*3e72558cSVitor Soares 		mcp251xfd_tx_failure_drop(priv, tx_ring, err);
165*3e72558cSVitor Soares }
166*3e72558cSVitor Soares 
mcp251xfd_tx_obj_write(const struct mcp251xfd_priv * priv,struct mcp251xfd_tx_obj * tx_obj)16709b0eb92SMarc Kleine-Budde static int mcp251xfd_tx_obj_write(const struct mcp251xfd_priv *priv,
16809b0eb92SMarc Kleine-Budde 				  struct mcp251xfd_tx_obj *tx_obj)
16909b0eb92SMarc Kleine-Budde {
17009b0eb92SMarc Kleine-Budde 	return spi_async(priv->spi, &tx_obj->msg);
17109b0eb92SMarc Kleine-Budde }
17209b0eb92SMarc Kleine-Budde 
mcp251xfd_tx_busy(const struct mcp251xfd_priv * priv,struct mcp251xfd_tx_ring * tx_ring)17309b0eb92SMarc Kleine-Budde static bool mcp251xfd_tx_busy(const struct mcp251xfd_priv *priv,
17409b0eb92SMarc Kleine-Budde 			      struct mcp251xfd_tx_ring *tx_ring)
17509b0eb92SMarc Kleine-Budde {
17609b0eb92SMarc Kleine-Budde 	if (mcp251xfd_get_tx_free(tx_ring) > 0)
17709b0eb92SMarc Kleine-Budde 		return false;
17809b0eb92SMarc Kleine-Budde 
17909b0eb92SMarc Kleine-Budde 	netif_stop_queue(priv->ndev);
18009b0eb92SMarc Kleine-Budde 
18109b0eb92SMarc Kleine-Budde 	/* Memory barrier before checking tx_free (head and tail) */
18209b0eb92SMarc Kleine-Budde 	smp_mb();
18309b0eb92SMarc Kleine-Budde 
18409b0eb92SMarc Kleine-Budde 	if (mcp251xfd_get_tx_free(tx_ring) == 0) {
18509b0eb92SMarc Kleine-Budde 		netdev_dbg(priv->ndev,
18609b0eb92SMarc Kleine-Budde 			   "Stopping tx-queue (tx_head=0x%08x, tx_tail=0x%08x, len=%d).\n",
18709b0eb92SMarc Kleine-Budde 			   tx_ring->head, tx_ring->tail,
18809b0eb92SMarc Kleine-Budde 			   tx_ring->head - tx_ring->tail);
18909b0eb92SMarc Kleine-Budde 
19009b0eb92SMarc Kleine-Budde 		return true;
19109b0eb92SMarc Kleine-Budde 	}
19209b0eb92SMarc Kleine-Budde 
19309b0eb92SMarc Kleine-Budde 	netif_start_queue(priv->ndev);
19409b0eb92SMarc Kleine-Budde 
19509b0eb92SMarc Kleine-Budde 	return false;
19609b0eb92SMarc Kleine-Budde }
19709b0eb92SMarc Kleine-Budde 
mcp251xfd_work_busy(struct work_struct * work)198*3e72558cSVitor Soares static bool mcp251xfd_work_busy(struct work_struct *work)
199*3e72558cSVitor Soares {
200*3e72558cSVitor Soares 	return work_busy(work);
201*3e72558cSVitor Soares }
202*3e72558cSVitor Soares 
mcp251xfd_start_xmit(struct sk_buff * skb,struct net_device * ndev)20309b0eb92SMarc Kleine-Budde netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
20409b0eb92SMarc Kleine-Budde 				 struct net_device *ndev)
20509b0eb92SMarc Kleine-Budde {
20609b0eb92SMarc Kleine-Budde 	struct mcp251xfd_priv *priv = netdev_priv(ndev);
20709b0eb92SMarc Kleine-Budde 	struct mcp251xfd_tx_ring *tx_ring = priv->tx;
20809b0eb92SMarc Kleine-Budde 	struct mcp251xfd_tx_obj *tx_obj;
20909b0eb92SMarc Kleine-Budde 	unsigned int frame_len;
21009b0eb92SMarc Kleine-Budde 	u8 tx_head;
21109b0eb92SMarc Kleine-Budde 	int err;
21209b0eb92SMarc Kleine-Budde 
213ae64438bSOliver Hartkopp 	if (can_dev_dropped_skb(ndev, skb))
21409b0eb92SMarc Kleine-Budde 		return NETDEV_TX_OK;
21509b0eb92SMarc Kleine-Budde 
216*3e72558cSVitor Soares 	if (mcp251xfd_tx_busy(priv, tx_ring) ||
217*3e72558cSVitor Soares 	    mcp251xfd_work_busy(&priv->tx_work))
21809b0eb92SMarc Kleine-Budde 		return NETDEV_TX_BUSY;
21909b0eb92SMarc Kleine-Budde 
22009b0eb92SMarc Kleine-Budde 	tx_obj = mcp251xfd_get_tx_obj_next(tx_ring);
22109b0eb92SMarc Kleine-Budde 	mcp251xfd_tx_obj_from_skb(priv, tx_obj, skb, tx_ring->head);
22209b0eb92SMarc Kleine-Budde 
22309b0eb92SMarc Kleine-Budde 	/* Stop queue if we occupy the complete TX FIFO */
22409b0eb92SMarc Kleine-Budde 	tx_head = mcp251xfd_get_tx_head(tx_ring);
22509b0eb92SMarc Kleine-Budde 	tx_ring->head++;
22609b0eb92SMarc Kleine-Budde 	if (mcp251xfd_get_tx_free(tx_ring) == 0)
22709b0eb92SMarc Kleine-Budde 		netif_stop_queue(ndev);
22809b0eb92SMarc Kleine-Budde 
22909b0eb92SMarc Kleine-Budde 	frame_len = can_skb_get_frame_len(skb);
23009b0eb92SMarc Kleine-Budde 	err = can_put_echo_skb(skb, ndev, tx_head, frame_len);
23109b0eb92SMarc Kleine-Budde 	if (!err)
23209b0eb92SMarc Kleine-Budde 		netdev_sent_queue(priv->ndev, frame_len);
23309b0eb92SMarc Kleine-Budde 
23409b0eb92SMarc Kleine-Budde 	err = mcp251xfd_tx_obj_write(priv, tx_obj);
235*3e72558cSVitor Soares 	if (err == -EBUSY) {
236*3e72558cSVitor Soares 		netif_stop_queue(ndev);
237*3e72558cSVitor Soares 		priv->tx_work_obj = tx_obj;
238*3e72558cSVitor Soares 		queue_work(priv->wq, &priv->tx_work);
239*3e72558cSVitor Soares 	} else if (err) {
240*3e72558cSVitor Soares 		mcp251xfd_tx_failure_drop(priv, tx_ring, err);
241*3e72558cSVitor Soares 	}
24209b0eb92SMarc Kleine-Budde 
24309b0eb92SMarc Kleine-Budde 	return NETDEV_TX_OK;
24409b0eb92SMarc Kleine-Budde }
245