]> Git Repo - linux.git/blob - drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c
net: bgmac: Fix return value check for fixed_phy_register()
[linux.git] / drivers / net / can / spi / mcp251xfd / mcp251xfd-rx.c
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 <[email protected]>
7 //
8 // Based on:
9 //
10 // CAN bus driver for Microchip 25XXFD CAN Controller with SPI Interface
11 //
12 // Copyright (c) 2019 Martin Sperl <[email protected]>
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(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
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(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
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_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
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, &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
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((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
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(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
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(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
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                                             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
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(&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 }
This page took 0.042735 seconds and 4 git commands to generate.