File Index
Files and directories
Sign in
FILE

mcp251xfd-rx.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c C
  1// SPDX-License-Identifier: GPL-2.0
  2//
  3// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
  4//
  5// Copyright (c) 2019, 2020, 2021, 2023 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 <linux/bitfield.h>
 16
 17#include "mcp251xfd.h"
 18
 19static inline bool mcp251xfd_rx_fifo_sta_empty(const u32 fifo_sta)
 20{
 21	return !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
 22}
 23
 24static inline bool mcp251xfd_rx_fifo_sta_full(const u32 fifo_sta)
 25{
 26	return fifo_sta & MCP251XFD_REG_FIFOSTA_TFERFFIF;
 27}
 28
 29static inline int
 30mcp251xfd_rx_tail_get_from_chip(const struct mcp251xfd_priv *priv,
 31				const struct mcp251xfd_rx_ring *ring,
 32				u8 *rx_tail)
 33{
 34	u32 fifo_ua;
 35	int err;
 36
 37	err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOUA(ring->fifo_nr),
 38			  &fifo_ua);
 39	if (err)
 40		return err;
 41
 42	fifo_ua -= ring->base - MCP251XFD_RAM_START;
 43	*rx_tail = fifo_ua / ring->obj_size;
 44
 45	return 0;
 46}
 47
 48static int
 49mcp251xfd_check_rx_tail(const struct mcp251xfd_priv *priv,
 50			const struct mcp251xfd_rx_ring *ring)
 51{
 52	u8 rx_tail_chip, rx_tail;
 53	int err;
 54
 55	if (!IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY))
 56		return 0;
 57
 58	err = mcp251xfd_rx_tail_get_from_chip(priv, ring, &rx_tail_chip);
 59	if (err)
 60		return err;
 61
 62	rx_tail = mcp251xfd_get_rx_tail(ring);
 63	if (rx_tail_chip != rx_tail) {
 64		netdev_err(priv->ndev,
 65			   "RX tail of chip (%d) and ours (%d) inconsistent.\n",
 66			   rx_tail_chip, rx_tail);
 67		return -EILSEQ;
 68	}
 69
 70	return 0;
 71}
 72
 73static int
 74mcp251xfd_get_rx_len(const struct mcp251xfd_priv *priv,
 75		     const struct mcp251xfd_rx_ring *ring,
 76		     u8 *len_p)
 77{
 78	const u8 shift = ring->obj_num_shift_to_u8;
 79	u8 chip_head, tail, len;
 80	u32 fifo_sta;
 81	int err;
 82
 83	err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(ring->fifo_nr),
 84			  &fifo_sta);
 85	if (err)
 86		return err;
 87
 88	if (mcp251xfd_rx_fifo_sta_empty(fifo_sta)) {
 89		*len_p = 0;
 90		return 0;
 91	}
 92
 93	if (mcp251xfd_rx_fifo_sta_full(fifo_sta)) {
 94		*len_p = ring->obj_num;
 95		return 0;
 96	}
 97
 98	chip_head = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);
 99
100	err =  mcp251xfd_check_rx_tail(priv, ring);
101	if (err)
102		return err;
103	tail = mcp251xfd_get_rx_tail(ring);
104
105	/* First shift to full u8. The subtraction works on signed
106	 * values, that keeps the difference steady around the u8
107	 * overflow. The right shift acts on len, which is an u8.
108	 */
109	BUILD_BUG_ON(sizeof(ring->obj_num) != sizeof(chip_head));
110	BUILD_BUG_ON(sizeof(ring->obj_num) != sizeof(tail));
111	BUILD_BUG_ON(sizeof(ring->obj_num) != sizeof(len));
112
113	len = (chip_head << shift) - (tail << shift);
114	*len_p = len >> shift;
115
116	return 0;
117}
118
119static void
120mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv,
121			   const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
122			   struct sk_buff *skb)
123{
124	struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
125	u8 dlc;
126
127	if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_IDE) {
128		u32 sid, eid;
129
130		eid = FIELD_GET(MCP251XFD_OBJ_ID_EID_MASK, hw_rx_obj->id);
131		sid = FIELD_GET(MCP251XFD_OBJ_ID_SID_MASK, hw_rx_obj->id);
132
133		cfd->can_id = CAN_EFF_FLAG |
134			FIELD_PREP(MCP251XFD_REG_FRAME_EFF_EID_MASK, eid) |
135			FIELD_PREP(MCP251XFD_REG_FRAME_EFF_SID_MASK, sid);
136	} else {
137		cfd->can_id = FIELD_GET(MCP251XFD_OBJ_ID_SID_MASK,
138					hw_rx_obj->id);
139	}
140
141	dlc = FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC_MASK, hw_rx_obj->flags);
142
143	/* CANFD */
144	if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF) {
145		if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_ESI)
146			cfd->flags |= CANFD_ESI;
147
148		if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_BRS)
149			cfd->flags |= CANFD_BRS;
150
151		cfd->len = can_fd_dlc2len(dlc);
152	} else {
153		if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR)
154			cfd->can_id |= CAN_RTR_FLAG;
155
156		can_frame_set_cc_len((struct can_frame *)cfd, dlc,
157				     priv->can.ctrlmode);
158	}
159
160	if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR))
161		memcpy(cfd->data, hw_rx_obj->data, cfd->len);
162}
163
164static int
165mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
166			  struct mcp251xfd_rx_ring *ring,
167			  const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj)
168{
169	struct net_device_stats *stats = &priv->ndev->stats;
170	struct sk_buff *skb;
171	struct canfd_frame *cfd;
172	u64 timestamp;
173	int err;
174
175	/* According to mcp2518fd erratum DS80000789E 6. the FIFOCI
176	 * bits of a FIFOSTA register, here the RX FIFO head index
177	 * might be corrupted and we might process past the RX FIFO's
178	 * head into old CAN frames.
179	 *
180	 * Compare the timestamp of currently processed CAN frame with
181	 * last valid frame received. Abort with -EBADMSG if an old
182	 * CAN frame is detected.
183	 */
184	timestamp = timecounter_cyc2time(&priv->tc, hw_rx_obj->ts);
185	if (timestamp <= ring->last_valid) {
186		stats->rx_fifo_errors++;
187
188		return -EBADMSG;
189	}
190	ring->last_valid = timestamp;
191
192	if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF)
193		skb = alloc_canfd_skb(priv->ndev, &cfd);
194	else
195		skb = alloc_can_skb(priv->ndev, (struct can_frame **)&cfd);
196
197	if (!skb) {
198		stats->rx_dropped++;
199		return 0;
200	}
201
202	mcp251xfd_skb_set_timestamp(skb, timestamp);
203	mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb);
204	err = can_rx_offload_queue_timestamp(&priv->offload, skb, hw_rx_obj->ts);
205	if (err)
206		stats->rx_fifo_errors++;
207
208	return 0;
209}
210
211static inline int
212mcp251xfd_rx_obj_read(const struct mcp251xfd_priv *priv,
213		      const struct mcp251xfd_rx_ring *ring,
214		      struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
215		      const u8 offset, const u8 len)
216{
217	const int val_bytes = regmap_get_val_bytes(priv->map_rx);
218	int err;
219
220	err = regmap_bulk_read(priv->map_rx,
221			       mcp251xfd_get_rx_obj_addr(ring, offset),
222			       hw_rx_obj,
223			       len * ring->obj_size / val_bytes);
224
225	return err;
226}
227
228static int
229mcp251xfd_handle_rxif_ring_uinc(const struct mcp251xfd_priv *priv,
230				struct mcp251xfd_rx_ring *ring,
231				u8 len)
232{
233	int offset;
234	int err;
235
236	if (!len)
237		return 0;
238
239	ring->head += len;
240
241	/* Increment the RX FIFO tail pointer 'len' times in a
242	 * single SPI message.
243	 *
244	 * Note:
245	 * Calculate offset, so that the SPI transfer ends on
246	 * the last message of the uinc_xfer array, which has
247	 * "cs_change == 0", to properly deactivate the chip
248	 * select.
249	 */
250	offset = ARRAY_SIZE(ring->uinc_xfer) - len;
251	err = spi_sync_transfer(priv->spi,
252				ring->uinc_xfer + offset, len);
253	if (err)
254		return err;
255
256	ring->tail += len;
257
258	return 0;
259}
260
261static int
262mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
263			   struct mcp251xfd_rx_ring *ring)
264{
265	struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj = ring->obj;
266	u8 rx_tail, len, l;
267	int err, i;
268
269	err = mcp251xfd_get_rx_len(priv, ring, &len);
270	if (err)
271		return err;
272
273	while ((l = mcp251xfd_get_rx_linear_len(ring, len))) {
274		rx_tail = mcp251xfd_get_rx_tail(ring);
275
276		err = mcp251xfd_rx_obj_read(priv, ring, hw_rx_obj,
277					    rx_tail, l);
278		if (err)
279			return err;
280
281		for (i = 0; i < l; i++) {
282			err = mcp251xfd_handle_rxif_one(priv, ring,
283							(void *)hw_rx_obj +
284							i * ring->obj_size);
285
286			/* -EBADMSG means we're affected by mcp2518fd
287			 * erratum DS80000789E 6., i.e. the timestamp
288			 * in the RX object is older that the last
289			 * valid received CAN frame. Don't process any
290			 * further and mark processed frames as good.
291			 */
292			if (err == -EBADMSG)
293				return mcp251xfd_handle_rxif_ring_uinc(priv, ring, i);
294			else if (err)
295				return err;
296		}
297
298		err = mcp251xfd_handle_rxif_ring_uinc(priv, ring, l);
299		if (err)
300			return err;
301
302		len -= l;
303	}
304
305	return 0;
306}
307
308int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
309{
310	struct mcp251xfd_rx_ring *ring;
311	int err, n;
312
313	mcp251xfd_for_each_rx_ring(priv, ring, n) {
314		/* - if RX IRQ coalescing is active always handle ring 0
315		 * - only handle rings if RX IRQ is active
316		 */
317		if ((ring->nr > 0 || !priv->rx_obj_num_coalesce_irq) &&
318		    !(priv->regs_status.rxif & BIT(ring->fifo_nr)))
319			continue;
320
321		err = mcp251xfd_handle_rxif_ring(priv, ring);
322		if (err)
323			return err;
324	}
325
326	if (priv->rx_coalesce_usecs_irq)
327		hrtimer_start(&priv->rx_irq_timer,
328			      ns_to_ktime(priv->rx_coalesce_usecs_irq *
329					  NSEC_PER_USEC),
330			      HRTIMER_MODE_REL);
331
332	return 0;
333}
~/ Read-only file preview.