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 | |
19 | static inline int |
20 | mcp251xfd_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(map: priv->map_reg, MCP251XFD_REG_FIFOSTA(ring->fifo_nr), |
28 | val: &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 | |
38 | static inline int |
39 | mcp251xfd_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(map: priv->map_reg, MCP251XFD_REG_FIFOUA(ring->fifo_nr), |
47 | val: &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 | |
57 | static int |
58 | mcp251xfd_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: &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(dev: priv->ndev, |
74 | format: "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 | |
82 | static int |
83 | mcp251xfd_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, rx_head: &chip_rx_head, |
92 | fifo_empty: &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 | |
108 | static void |
109 | mcp251xfd_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(cf: (struct can_frame *)cfd, dlc, |
146 | ctrlmode: 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, timestamp: hw_rx_obj->ts); |
153 | } |
154 | |
155 | static int |
156 | mcp251xfd_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(dev: priv->ndev, cfd: &cfd); |
167 | else |
168 | skb = alloc_can_skb(dev: priv->ndev, cf: (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(offload: &priv->offload, skb, timestamp: hw_rx_obj->ts); |
177 | if (err) |
178 | stats->rx_fifo_errors++; |
179 | |
180 | return 0; |
181 | } |
182 | |
183 | static inline int |
184 | mcp251xfd_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(map: priv->map_rx); |
190 | int err; |
191 | |
192 | err = regmap_bulk_read(map: priv->map_rx, |
193 | reg: mcp251xfd_get_rx_obj_addr(ring, n: offset), |
194 | val: hw_rx_obj, |
195 | val_count: len * ring->obj_size / val_bytes); |
196 | |
197 | return err; |
198 | } |
199 | |
200 | static int |
201 | mcp251xfd_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 | offset: 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 | hw_rx_obj: (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(spi: priv->spi, |
241 | xfers: ring->uinc_xfer + offset, num_xfers: len); |
242 | if (err) |
243 | return err; |
244 | |
245 | ring->tail += len; |
246 | } |
247 | |
248 | return 0; |
249 | } |
250 | |
251 | int 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(timer: &priv->rx_irq_timer, |
271 | tim: ns_to_ktime(ns: priv->rx_coalesce_usecs_irq * |
272 | NSEC_PER_USEC), |
273 | mode: HRTIMER_MODE_REL); |
274 | |
275 | return 0; |
276 | } |
277 | |