Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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(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(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(cfd->len);
 80	} else {
 81		dlc = can_get_cc_dlc((struct can_frame *)cfd,
 82				     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(id, &hw_tx_obj->id);
 94	put_unaligned_le32(flags, &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(&load_buf->crc.cmd,
119						     len);
120		/* CRC */
121		len += sizeof(load_buf->crc.cmd);
122		crc = mcp251xfd_crc16_compute(&load_buf->crc, len);
123		put_unaligned_be16(crc, (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(priv->spi, &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(tx_ring) > 0)
144		return false;
145
146	netif_stop_queue(priv->ndev);
147
148	/* Memory barrier before checking tx_free (head and tail) */
149	smp_mb();
150
151	if (mcp251xfd_get_tx_free(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(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(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(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, tx_ring->head);
183
184	/* Stop queue if we occupy the complete TX FIFO */
185	tx_head = mcp251xfd_get_tx_head(tx_ring);
186	tx_ring->head++;
187	if (mcp251xfd_get_tx_free(tx_ring) == 0)
188		netif_stop_queue(ndev);
189
190	frame_len = can_skb_get_frame_len(skb);
191	err = can_put_echo_skb(skb, ndev, tx_head, frame_len);
192	if (!err)
193		netdev_sent_queue(priv->ndev, 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(priv->ndev, "ERROR in %s: %d\n", __func__, err);
203
204	return NETDEV_TX_OK;
205}