Linux Audio

Check our new training course

Loading...
  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 <linux/bitfield.h>
 16
 17#include "mcp251xfd.h"
 18
 19static inline int
 20mcp251xfd_rx_head_get_from_chip(const struct mcp251xfd_priv *priv,
 21				const struct mcp251xfd_rx_ring *ring,
 22				u8 *rx_head, bool *fifo_empty)
 23{
 24	u32 fifo_sta;
 25	int err;
 26
 27	err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOSTA(ring->fifo_nr),
 28			  &fifo_sta);
 29	if (err)
 30		return err;
 31
 32	*rx_head = FIELD_GET(MCP251XFD_REG_FIFOSTA_FIFOCI_MASK, fifo_sta);
 33	*fifo_empty = !(fifo_sta & MCP251XFD_REG_FIFOSTA_TFNRFNIF);
 34
 35	return 0;
 36}
 37
 38static inline int
 39mcp251xfd_rx_tail_get_from_chip(const struct mcp251xfd_priv *priv,
 40				const struct mcp251xfd_rx_ring *ring,
 41				u8 *rx_tail)
 42{
 43	u32 fifo_ua;
 44	int err;
 45
 46	err = regmap_read(priv->map_reg, MCP251XFD_REG_FIFOUA(ring->fifo_nr),
 47			  &fifo_ua);
 48	if (err)
 49		return err;
 50
 51	fifo_ua -= ring->base - MCP251XFD_RAM_START;
 52	*rx_tail = fifo_ua / ring->obj_size;
 53
 54	return 0;
 55}
 56
 57static int
 58mcp251xfd_check_rx_tail(const struct mcp251xfd_priv *priv,
 59			const struct mcp251xfd_rx_ring *ring)
 60{
 61	u8 rx_tail_chip, rx_tail;
 62	int err;
 63
 64	if (!IS_ENABLED(CONFIG_CAN_MCP251XFD_SANITY))
 65		return 0;
 66
 67	err = mcp251xfd_rx_tail_get_from_chip(priv, ring, &rx_tail_chip);
 68	if (err)
 69		return err;
 70
 71	rx_tail = mcp251xfd_get_rx_tail(ring);
 72	if (rx_tail_chip != rx_tail) {
 73		netdev_err(priv->ndev,
 74			   "RX tail of chip (%d) and ours (%d) inconsistent.\n",
 75			   rx_tail_chip, rx_tail);
 76		return -EILSEQ;
 77	}
 78
 79	return 0;
 80}
 81
 82static int
 83mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv,
 84			 struct mcp251xfd_rx_ring *ring)
 85{
 86	u32 new_head;
 87	u8 chip_rx_head;
 88	bool fifo_empty;
 89	int err;
 90
 91	err = mcp251xfd_rx_head_get_from_chip(priv, ring, &chip_rx_head,
 92					      &fifo_empty);
 93	if (err || fifo_empty)
 94		return err;
 95
 96	/* chip_rx_head, is the next RX-Object filled by the HW.
 97	 * The new RX head must be >= the old head.
 98	 */
 99	new_head = round_down(ring->head, ring->obj_num) + chip_rx_head;
100	if (new_head <= ring->head)
101		new_head += ring->obj_num;
102
103	ring->head = new_head;
104
105	return mcp251xfd_check_rx_tail(priv, ring);
106}
107
108static void
109mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv,
110			   const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
111			   struct sk_buff *skb)
112{
113	struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
114	u8 dlc;
115
116	if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_IDE) {
117		u32 sid, eid;
118
119		eid = FIELD_GET(MCP251XFD_OBJ_ID_EID_MASK, hw_rx_obj->id);
120		sid = FIELD_GET(MCP251XFD_OBJ_ID_SID_MASK, hw_rx_obj->id);
121
122		cfd->can_id = CAN_EFF_FLAG |
123			FIELD_PREP(MCP251XFD_REG_FRAME_EFF_EID_MASK, eid) |
124			FIELD_PREP(MCP251XFD_REG_FRAME_EFF_SID_MASK, sid);
125	} else {
126		cfd->can_id = FIELD_GET(MCP251XFD_OBJ_ID_SID_MASK,
127					hw_rx_obj->id);
128	}
129
130	dlc = FIELD_GET(MCP251XFD_OBJ_FLAGS_DLC_MASK, hw_rx_obj->flags);
131
132	/* CANFD */
133	if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF) {
134		if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_ESI)
135			cfd->flags |= CANFD_ESI;
136
137		if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_BRS)
138			cfd->flags |= CANFD_BRS;
139
140		cfd->len = can_fd_dlc2len(dlc);
141	} else {
142		if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR)
143			cfd->can_id |= CAN_RTR_FLAG;
144
145		can_frame_set_cc_len((struct can_frame *)cfd, dlc,
146				     priv->can.ctrlmode);
147	}
148
149	if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR))
150		memcpy(cfd->data, hw_rx_obj->data, cfd->len);
151
152	mcp251xfd_skb_set_timestamp(priv, skb, hw_rx_obj->ts);
153}
154
155static int
156mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
157			  struct mcp251xfd_rx_ring *ring,
158			  const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj)
159{
160	struct net_device_stats *stats = &priv->ndev->stats;
161	struct sk_buff *skb;
162	struct canfd_frame *cfd;
163	int err;
164
165	if (hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_FDF)
166		skb = alloc_canfd_skb(priv->ndev, &cfd);
167	else
168		skb = alloc_can_skb(priv->ndev, (struct can_frame **)&cfd);
169
170	if (!skb) {
171		stats->rx_dropped++;
172		return 0;
173	}
174
175	mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb);
176	err = can_rx_offload_queue_timestamp(&priv->offload, skb, hw_rx_obj->ts);
177	if (err)
178		stats->rx_fifo_errors++;
179
180	return 0;
181}
182
183static inline int
184mcp251xfd_rx_obj_read(const struct mcp251xfd_priv *priv,
185		      const struct mcp251xfd_rx_ring *ring,
186		      struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
187		      const u8 offset, const u8 len)
188{
189	const int val_bytes = regmap_get_val_bytes(priv->map_rx);
190	int err;
191
192	err = regmap_bulk_read(priv->map_rx,
193			       mcp251xfd_get_rx_obj_addr(ring, offset),
194			       hw_rx_obj,
195			       len * ring->obj_size / val_bytes);
196
197	return err;
198}
199
200static int
201mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
202			   struct mcp251xfd_rx_ring *ring)
203{
204	struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj = ring->obj;
205	u8 rx_tail, len;
206	int err, i;
207
208	err = mcp251xfd_rx_ring_update(priv, ring);
209	if (err)
210		return err;
211
212	while ((len = mcp251xfd_get_rx_linear_len(ring))) {
213		int offset;
214
215		rx_tail = mcp251xfd_get_rx_tail(ring);
216
217		err = mcp251xfd_rx_obj_read(priv, ring, hw_rx_obj,
218					    rx_tail, len);
219		if (err)
220			return err;
221
222		for (i = 0; i < len; i++) {
223			err = mcp251xfd_handle_rxif_one(priv, ring,
224							(void *)hw_rx_obj +
225							i * ring->obj_size);
226			if (err)
227				return err;
228		}
229
230		/* Increment the RX FIFO tail pointer 'len' times in a
231		 * single SPI message.
232		 *
233		 * Note:
234		 * Calculate offset, so that the SPI transfer ends on
235		 * the last message of the uinc_xfer array, which has
236		 * "cs_change == 0", to properly deactivate the chip
237		 * select.
238		 */
239		offset = ARRAY_SIZE(ring->uinc_xfer) - len;
240		err = spi_sync_transfer(priv->spi,
241					ring->uinc_xfer + offset, len);
242		if (err)
243			return err;
244
245		ring->tail += len;
246	}
247
248	return 0;
249}
250
251int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
252{
253	struct mcp251xfd_rx_ring *ring;
254	int err, n;
255
256	mcp251xfd_for_each_rx_ring(priv, ring, n) {
257		/* - if RX IRQ coalescing is active always handle ring 0
258		 * - only handle rings if RX IRQ is active
259		 */
260		if ((ring->nr > 0 || !priv->rx_obj_num_coalesce_irq) &&
261		    !(priv->regs_status.rxif & BIT(ring->fifo_nr)))
262			continue;
263
264		err = mcp251xfd_handle_rxif_ring(priv, ring);
265		if (err)
266			return err;
267	}
268
269	if (priv->rx_coalesce_usecs_irq)
270		hrtimer_start(&priv->rx_irq_timer,
271			      ns_to_ktime(priv->rx_coalesce_usecs_irq *
272					  NSEC_PER_USEC),
273			      HRTIMER_MODE_REL);
274
275	return 0;
276}