xref: /linux/drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c (revision 85505e585637a737e4713c1386c30e37c325b82e)
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 
19 static inline bool mcp251xfd_rx_fifo_sta_empty(const u32 fifo_sta)
20 {
21 	return !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
22 }
23 
24 static inline bool mcp251xfd_rx_fifo_sta_full(const u32 fifo_sta)
25 {
26 	return fifo_sta & MCP251XFD_REG_FIFOSTA_TFERFFIF;
27 }
28 
29 static inline int
30 mcp251xfd_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 
48 static int
49 mcp251xfd_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 
73 static int
74 mcp251xfd_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 
119 static void
120 mcp251xfd_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 	mcp251xfd_skb_set_timestamp_raw(priv, skb, hw_rx_obj->ts);
164 }
165 
166 static int
167 mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
168 			  struct mcp251xfd_rx_ring *ring,
169 			  const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj)
170 {
171 	struct net_device_stats *stats = &priv->ndev->stats;
172 	struct sk_buff *skb;
173 	struct canfd_frame *cfd;
174 	int err;
175 
176 	if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF)
177 		skb = alloc_canfd_skb(priv->ndev, &cfd);
178 	else
179 		skb = alloc_can_skb(priv->ndev, (struct can_frame **)&cfd);
180 
181 	if (!skb) {
182 		stats->rx_dropped++;
183 		return 0;
184 	}
185 
186 	mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb);
187 	err = can_rx_offload_queue_timestamp(&priv->offload, skb, hw_rx_obj->ts);
188 	if (err)
189 		stats->rx_fifo_errors++;
190 
191 	return 0;
192 }
193 
194 static inline int
195 mcp251xfd_rx_obj_read(const struct mcp251xfd_priv *priv,
196 		      const struct mcp251xfd_rx_ring *ring,
197 		      struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
198 		      const u8 offset, const u8 len)
199 {
200 	const int val_bytes = regmap_get_val_bytes(priv->map_rx);
201 	int err;
202 
203 	err = regmap_bulk_read(priv->map_rx,
204 			       mcp251xfd_get_rx_obj_addr(ring, offset),
205 			       hw_rx_obj,
206 			       len * ring->obj_size / val_bytes);
207 
208 	return err;
209 }
210 
211 static int
212 mcp251xfd_handle_rxif_ring_uinc(const struct mcp251xfd_priv *priv,
213 				struct mcp251xfd_rx_ring *ring,
214 				u8 len)
215 {
216 	int offset;
217 	int err;
218 
219 	if (!len)
220 		return 0;
221 
222 	ring->head += len;
223 
224 	/* Increment the RX FIFO tail pointer 'len' times in a
225 	 * single SPI message.
226 	 *
227 	 * Note:
228 	 * Calculate offset, so that the SPI transfer ends on
229 	 * the last message of the uinc_xfer array, which has
230 	 * "cs_change == 0", to properly deactivate the chip
231 	 * select.
232 	 */
233 	offset = ARRAY_SIZE(ring->uinc_xfer) - len;
234 	err = spi_sync_transfer(priv->spi,
235 				ring->uinc_xfer + offset, len);
236 	if (err)
237 		return err;
238 
239 	ring->tail += len;
240 
241 	return 0;
242 }
243 
244 static int
245 mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
246 			   struct mcp251xfd_rx_ring *ring)
247 {
248 	struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj = ring->obj;
249 	u8 rx_tail, len, l;
250 	int err, i;
251 
252 	err = mcp251xfd_get_rx_len(priv, ring, &len);
253 	if (err)
254 		return err;
255 
256 	while ((l = mcp251xfd_get_rx_linear_len(ring, len))) {
257 		rx_tail = mcp251xfd_get_rx_tail(ring);
258 
259 		err = mcp251xfd_rx_obj_read(priv, ring, hw_rx_obj,
260 					    rx_tail, l);
261 		if (err)
262 			return err;
263 
264 		for (i = 0; i < l; i++) {
265 			err = mcp251xfd_handle_rxif_one(priv, ring,
266 							(void *)hw_rx_obj +
267 							i * ring->obj_size);
268 			if (err)
269 				return err;
270 		}
271 
272 		err = mcp251xfd_handle_rxif_ring_uinc(priv, ring, l);
273 		if (err)
274 			return err;
275 
276 		len -= l;
277 	}
278 
279 	return 0;
280 }
281 
282 int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
283 {
284 	struct mcp251xfd_rx_ring *ring;
285 	int err, n;
286 
287 	mcp251xfd_for_each_rx_ring(priv, ring, n) {
288 		/* - if RX IRQ coalescing is active always handle ring 0
289 		 * - only handle rings if RX IRQ is active
290 		 */
291 		if ((ring->nr > 0 || !priv->rx_obj_num_coalesce_irq) &&
292 		    !(priv->regs_status.rxif & BIT(ring->fifo_nr)))
293 			continue;
294 
295 		err = mcp251xfd_handle_rxif_ring(priv, ring);
296 		if (err)
297 			return err;
298 	}
299 
300 	if (priv->rx_coalesce_usecs_irq)
301 		hrtimer_start(&priv->rx_irq_timer,
302 			      ns_to_ktime(priv->rx_coalesce_usecs_irq *
303 					  NSEC_PER_USEC),
304 			      HRTIMER_MODE_REL);
305 
306 	return 0;
307 }
308