1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | /* Texas Instruments ICSSG Ethernet Driver |
4 | * |
5 | * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ |
6 | * |
7 | */ |
8 | |
9 | #include <linux/bitops.h> |
10 | #include <linux/clk.h> |
11 | #include <linux/delay.h> |
12 | #include <linux/dma-mapping.h> |
13 | #include <linux/dma/ti-cppi5.h> |
14 | #include <linux/etherdevice.h> |
15 | #include <linux/genalloc.h> |
16 | #include <linux/if_vlan.h> |
17 | #include <linux/interrupt.h> |
18 | #include <linux/kernel.h> |
19 | #include <linux/mfd/syscon.h> |
20 | #include <linux/module.h> |
21 | #include <linux/of.h> |
22 | #include <linux/of_mdio.h> |
23 | #include <linux/of_net.h> |
24 | #include <linux/platform_device.h> |
25 | #include <linux/phy.h> |
26 | #include <linux/property.h> |
27 | #include <linux/remoteproc/pruss.h> |
28 | #include <linux/regmap.h> |
29 | #include <linux/remoteproc.h> |
30 | |
31 | #include "icssg_prueth.h" |
32 | #include "icssg_mii_rt.h" |
33 | #include "../k3-cppi-desc-pool.h" |
34 | |
35 | #define PRUETH_MODULE_DESCRIPTION "PRUSS ICSSG Ethernet driver" |
36 | |
37 | /* Netif debug messages possible */ |
38 | #define PRUETH_EMAC_DEBUG (NETIF_MSG_DRV | \ |
39 | NETIF_MSG_PROBE | \ |
40 | NETIF_MSG_LINK | \ |
41 | NETIF_MSG_TIMER | \ |
42 | NETIF_MSG_IFDOWN | \ |
43 | NETIF_MSG_IFUP | \ |
44 | NETIF_MSG_RX_ERR | \ |
45 | NETIF_MSG_TX_ERR | \ |
46 | NETIF_MSG_TX_QUEUED | \ |
47 | NETIF_MSG_INTR | \ |
48 | NETIF_MSG_TX_DONE | \ |
49 | NETIF_MSG_RX_STATUS | \ |
50 | NETIF_MSG_PKTDATA | \ |
51 | NETIF_MSG_HW | \ |
52 | NETIF_MSG_WOL) |
53 | |
54 | #define prueth_napi_to_emac(napi) container_of(napi, struct prueth_emac, napi_rx) |
55 | |
56 | /* CTRLMMR_ICSSG_RGMII_CTRL register bits */ |
57 | #define ICSSG_CTRL_RGMII_ID_MODE BIT(24) |
58 | |
59 | #define IEP_DEFAULT_CYCLE_TIME_NS 1000000 /* 1 ms */ |
60 | |
61 | static void prueth_cleanup_rx_chns(struct prueth_emac *emac, |
62 | struct prueth_rx_chn *rx_chn, |
63 | int max_rflows) |
64 | { |
65 | if (rx_chn->desc_pool) |
66 | k3_cppi_desc_pool_destroy(pool: rx_chn->desc_pool); |
67 | |
68 | if (rx_chn->rx_chn) |
69 | k3_udma_glue_release_rx_chn(rx_chn: rx_chn->rx_chn); |
70 | } |
71 | |
72 | static void prueth_cleanup_tx_chns(struct prueth_emac *emac) |
73 | { |
74 | int i; |
75 | |
76 | for (i = 0; i < emac->tx_ch_num; i++) { |
77 | struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; |
78 | |
79 | if (tx_chn->desc_pool) |
80 | k3_cppi_desc_pool_destroy(pool: tx_chn->desc_pool); |
81 | |
82 | if (tx_chn->tx_chn) |
83 | k3_udma_glue_release_tx_chn(tx_chn: tx_chn->tx_chn); |
84 | |
85 | /* Assume prueth_cleanup_tx_chns() is called at the |
86 | * end after all channel resources are freed |
87 | */ |
88 | memset(tx_chn, 0, sizeof(*tx_chn)); |
89 | } |
90 | } |
91 | |
92 | static void prueth_ndev_del_tx_napi(struct prueth_emac *emac, int num) |
93 | { |
94 | int i; |
95 | |
96 | for (i = 0; i < num; i++) { |
97 | struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; |
98 | |
99 | if (tx_chn->irq) |
100 | free_irq(tx_chn->irq, tx_chn); |
101 | netif_napi_del(napi: &tx_chn->napi_tx); |
102 | } |
103 | } |
104 | |
105 | static void prueth_xmit_free(struct prueth_tx_chn *tx_chn, |
106 | struct cppi5_host_desc_t *desc) |
107 | { |
108 | struct cppi5_host_desc_t *first_desc, *next_desc; |
109 | dma_addr_t buf_dma, next_desc_dma; |
110 | u32 buf_dma_len; |
111 | |
112 | first_desc = desc; |
113 | next_desc = first_desc; |
114 | |
115 | cppi5_hdesc_get_obuf(desc: first_desc, obuf: &buf_dma, obuf_len: &buf_dma_len); |
116 | k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn: tx_chn->tx_chn, addr: &buf_dma); |
117 | |
118 | dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len, |
119 | DMA_TO_DEVICE); |
120 | |
121 | next_desc_dma = cppi5_hdesc_get_next_hbdesc(desc: first_desc); |
122 | k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn: tx_chn->tx_chn, addr: &next_desc_dma); |
123 | while (next_desc_dma) { |
124 | next_desc = k3_cppi_desc_pool_dma2virt(pool: tx_chn->desc_pool, |
125 | dma: next_desc_dma); |
126 | cppi5_hdesc_get_obuf(desc: next_desc, obuf: &buf_dma, obuf_len: &buf_dma_len); |
127 | k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn: tx_chn->tx_chn, addr: &buf_dma); |
128 | |
129 | dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len, |
130 | DMA_TO_DEVICE); |
131 | |
132 | next_desc_dma = cppi5_hdesc_get_next_hbdesc(desc: next_desc); |
133 | k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn: tx_chn->tx_chn, addr: &next_desc_dma); |
134 | |
135 | k3_cppi_desc_pool_free(pool: tx_chn->desc_pool, addr: next_desc); |
136 | } |
137 | |
138 | k3_cppi_desc_pool_free(pool: tx_chn->desc_pool, addr: first_desc); |
139 | } |
140 | |
141 | static int emac_tx_complete_packets(struct prueth_emac *emac, int chn, |
142 | int budget) |
143 | { |
144 | struct net_device *ndev = emac->ndev; |
145 | struct cppi5_host_desc_t *desc_tx; |
146 | struct netdev_queue *netif_txq; |
147 | struct prueth_tx_chn *tx_chn; |
148 | unsigned int total_bytes = 0; |
149 | struct sk_buff *skb; |
150 | dma_addr_t desc_dma; |
151 | int res, num_tx = 0; |
152 | void **swdata; |
153 | |
154 | tx_chn = &emac->tx_chns[chn]; |
155 | |
156 | while (true) { |
157 | res = k3_udma_glue_pop_tx_chn(tx_chn: tx_chn->tx_chn, desc_dma: &desc_dma); |
158 | if (res == -ENODATA) |
159 | break; |
160 | |
161 | /* teardown completion */ |
162 | if (cppi5_desc_is_tdcm(paddr: desc_dma)) { |
163 | if (atomic_dec_and_test(v: &emac->tdown_cnt)) |
164 | complete(&emac->tdown_complete); |
165 | break; |
166 | } |
167 | |
168 | desc_tx = k3_cppi_desc_pool_dma2virt(pool: tx_chn->desc_pool, |
169 | dma: desc_dma); |
170 | swdata = cppi5_hdesc_get_swdata(desc: desc_tx); |
171 | |
172 | skb = *(swdata); |
173 | prueth_xmit_free(tx_chn, desc: desc_tx); |
174 | |
175 | ndev = skb->dev; |
176 | ndev->stats.tx_packets++; |
177 | ndev->stats.tx_bytes += skb->len; |
178 | total_bytes += skb->len; |
179 | napi_consume_skb(skb, budget); |
180 | num_tx++; |
181 | } |
182 | |
183 | if (!num_tx) |
184 | return 0; |
185 | |
186 | netif_txq = netdev_get_tx_queue(dev: ndev, index: chn); |
187 | netdev_tx_completed_queue(dev_queue: netif_txq, pkts: num_tx, bytes: total_bytes); |
188 | |
189 | if (netif_tx_queue_stopped(dev_queue: netif_txq)) { |
190 | /* If the TX queue was stopped, wake it now |
191 | * if we have enough room. |
192 | */ |
193 | __netif_tx_lock(txq: netif_txq, smp_processor_id()); |
194 | if (netif_running(dev: ndev) && |
195 | (k3_cppi_desc_pool_avail(pool: tx_chn->desc_pool) >= |
196 | MAX_SKB_FRAGS)) |
197 | netif_tx_wake_queue(dev_queue: netif_txq); |
198 | __netif_tx_unlock(txq: netif_txq); |
199 | } |
200 | |
201 | return num_tx; |
202 | } |
203 | |
204 | static int emac_napi_tx_poll(struct napi_struct *napi_tx, int budget) |
205 | { |
206 | struct prueth_tx_chn *tx_chn = prueth_napi_to_tx_chn(napi_tx); |
207 | struct prueth_emac *emac = tx_chn->emac; |
208 | int num_tx_packets; |
209 | |
210 | num_tx_packets = emac_tx_complete_packets(emac, chn: tx_chn->id, budget); |
211 | |
212 | if (num_tx_packets >= budget) |
213 | return budget; |
214 | |
215 | if (napi_complete_done(n: napi_tx, work_done: num_tx_packets)) |
216 | enable_irq(irq: tx_chn->irq); |
217 | |
218 | return num_tx_packets; |
219 | } |
220 | |
221 | static irqreturn_t prueth_tx_irq(int irq, void *dev_id) |
222 | { |
223 | struct prueth_tx_chn *tx_chn = dev_id; |
224 | |
225 | disable_irq_nosync(irq); |
226 | napi_schedule(n: &tx_chn->napi_tx); |
227 | |
228 | return IRQ_HANDLED; |
229 | } |
230 | |
231 | static int prueth_ndev_add_tx_napi(struct prueth_emac *emac) |
232 | { |
233 | struct prueth *prueth = emac->prueth; |
234 | int i, ret; |
235 | |
236 | for (i = 0; i < emac->tx_ch_num; i++) { |
237 | struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; |
238 | |
239 | netif_napi_add_tx(dev: emac->ndev, napi: &tx_chn->napi_tx, poll: emac_napi_tx_poll); |
240 | ret = request_irq(irq: tx_chn->irq, handler: prueth_tx_irq, |
241 | IRQF_TRIGGER_HIGH, name: tx_chn->name, |
242 | dev: tx_chn); |
243 | if (ret) { |
244 | netif_napi_del(napi: &tx_chn->napi_tx); |
245 | dev_err(prueth->dev, "unable to request TX IRQ %d\n" , |
246 | tx_chn->irq); |
247 | goto fail; |
248 | } |
249 | } |
250 | |
251 | return 0; |
252 | fail: |
253 | prueth_ndev_del_tx_napi(emac, num: i); |
254 | return ret; |
255 | } |
256 | |
257 | static int prueth_init_tx_chns(struct prueth_emac *emac) |
258 | { |
259 | static const struct k3_ring_cfg ring_cfg = { |
260 | .elm_size = K3_RINGACC_RING_ELSIZE_8, |
261 | .mode = K3_RINGACC_RING_MODE_RING, |
262 | .flags = 0, |
263 | .size = PRUETH_MAX_TX_DESC, |
264 | }; |
265 | struct k3_udma_glue_tx_channel_cfg tx_cfg; |
266 | struct device *dev = emac->prueth->dev; |
267 | struct net_device *ndev = emac->ndev; |
268 | int ret, slice, i; |
269 | u32 hdesc_size; |
270 | |
271 | slice = prueth_emac_slice(emac); |
272 | if (slice < 0) |
273 | return slice; |
274 | |
275 | init_completion(x: &emac->tdown_complete); |
276 | |
277 | hdesc_size = cppi5_hdesc_calc_size(epib: true, PRUETH_NAV_PS_DATA_SIZE, |
278 | PRUETH_NAV_SW_DATA_SIZE); |
279 | memset(&tx_cfg, 0, sizeof(tx_cfg)); |
280 | tx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE; |
281 | tx_cfg.tx_cfg = ring_cfg; |
282 | tx_cfg.txcq_cfg = ring_cfg; |
283 | |
284 | for (i = 0; i < emac->tx_ch_num; i++) { |
285 | struct prueth_tx_chn *tx_chn = &emac->tx_chns[i]; |
286 | |
287 | /* To differentiate channels for SLICE0 vs SLICE1 */ |
288 | snprintf(buf: tx_chn->name, size: sizeof(tx_chn->name), |
289 | fmt: "tx%d-%d" , slice, i); |
290 | |
291 | tx_chn->emac = emac; |
292 | tx_chn->id = i; |
293 | tx_chn->descs_num = PRUETH_MAX_TX_DESC; |
294 | |
295 | tx_chn->tx_chn = |
296 | k3_udma_glue_request_tx_chn(dev, name: tx_chn->name, |
297 | cfg: &tx_cfg); |
298 | if (IS_ERR(ptr: tx_chn->tx_chn)) { |
299 | ret = PTR_ERR(ptr: tx_chn->tx_chn); |
300 | tx_chn->tx_chn = NULL; |
301 | netdev_err(dev: ndev, |
302 | format: "Failed to request tx dma ch: %d\n" , ret); |
303 | goto fail; |
304 | } |
305 | |
306 | tx_chn->dma_dev = k3_udma_glue_tx_get_dma_device(tx_chn: tx_chn->tx_chn); |
307 | tx_chn->desc_pool = |
308 | k3_cppi_desc_pool_create_name(dev: tx_chn->dma_dev, |
309 | size: tx_chn->descs_num, |
310 | desc_size: hdesc_size, |
311 | name: tx_chn->name); |
312 | if (IS_ERR(ptr: tx_chn->desc_pool)) { |
313 | ret = PTR_ERR(ptr: tx_chn->desc_pool); |
314 | tx_chn->desc_pool = NULL; |
315 | netdev_err(dev: ndev, format: "Failed to create tx pool: %d\n" , ret); |
316 | goto fail; |
317 | } |
318 | |
319 | ret = k3_udma_glue_tx_get_irq(tx_chn: tx_chn->tx_chn); |
320 | if (ret < 0) { |
321 | netdev_err(dev: ndev, format: "failed to get tx irq\n" ); |
322 | goto fail; |
323 | } |
324 | tx_chn->irq = ret; |
325 | |
326 | snprintf(buf: tx_chn->name, size: sizeof(tx_chn->name), fmt: "%s-tx%d" , |
327 | dev_name(dev), tx_chn->id); |
328 | } |
329 | |
330 | return 0; |
331 | |
332 | fail: |
333 | prueth_cleanup_tx_chns(emac); |
334 | return ret; |
335 | } |
336 | |
337 | static int prueth_init_rx_chns(struct prueth_emac *emac, |
338 | struct prueth_rx_chn *rx_chn, |
339 | char *name, u32 max_rflows, |
340 | u32 max_desc_num) |
341 | { |
342 | struct k3_udma_glue_rx_channel_cfg rx_cfg; |
343 | struct device *dev = emac->prueth->dev; |
344 | struct net_device *ndev = emac->ndev; |
345 | u32 fdqring_id, hdesc_size; |
346 | int i, ret = 0, slice; |
347 | |
348 | slice = prueth_emac_slice(emac); |
349 | if (slice < 0) |
350 | return slice; |
351 | |
352 | /* To differentiate channels for SLICE0 vs SLICE1 */ |
353 | snprintf(buf: rx_chn->name, size: sizeof(rx_chn->name), fmt: "%s%d" , name, slice); |
354 | |
355 | hdesc_size = cppi5_hdesc_calc_size(epib: true, PRUETH_NAV_PS_DATA_SIZE, |
356 | PRUETH_NAV_SW_DATA_SIZE); |
357 | memset(&rx_cfg, 0, sizeof(rx_cfg)); |
358 | rx_cfg.swdata_size = PRUETH_NAV_SW_DATA_SIZE; |
359 | rx_cfg.flow_id_num = max_rflows; |
360 | rx_cfg.flow_id_base = -1; /* udmax will auto select flow id base */ |
361 | |
362 | /* init all flows */ |
363 | rx_chn->dev = dev; |
364 | rx_chn->descs_num = max_desc_num; |
365 | |
366 | rx_chn->rx_chn = k3_udma_glue_request_rx_chn(dev, name: rx_chn->name, |
367 | cfg: &rx_cfg); |
368 | if (IS_ERR(ptr: rx_chn->rx_chn)) { |
369 | ret = PTR_ERR(ptr: rx_chn->rx_chn); |
370 | rx_chn->rx_chn = NULL; |
371 | netdev_err(dev: ndev, format: "Failed to request rx dma ch: %d\n" , ret); |
372 | goto fail; |
373 | } |
374 | |
375 | rx_chn->dma_dev = k3_udma_glue_rx_get_dma_device(rx_chn: rx_chn->rx_chn); |
376 | rx_chn->desc_pool = k3_cppi_desc_pool_create_name(dev: rx_chn->dma_dev, |
377 | size: rx_chn->descs_num, |
378 | desc_size: hdesc_size, |
379 | name: rx_chn->name); |
380 | if (IS_ERR(ptr: rx_chn->desc_pool)) { |
381 | ret = PTR_ERR(ptr: rx_chn->desc_pool); |
382 | rx_chn->desc_pool = NULL; |
383 | netdev_err(dev: ndev, format: "Failed to create rx pool: %d\n" , ret); |
384 | goto fail; |
385 | } |
386 | |
387 | emac->rx_flow_id_base = k3_udma_glue_rx_get_flow_id_base(rx_chn: rx_chn->rx_chn); |
388 | netdev_dbg(ndev, "flow id base = %d\n" , emac->rx_flow_id_base); |
389 | |
390 | fdqring_id = K3_RINGACC_RING_ID_ANY; |
391 | for (i = 0; i < rx_cfg.flow_id_num; i++) { |
392 | struct k3_ring_cfg rxring_cfg = { |
393 | .elm_size = K3_RINGACC_RING_ELSIZE_8, |
394 | .mode = K3_RINGACC_RING_MODE_RING, |
395 | .flags = 0, |
396 | }; |
397 | struct k3_ring_cfg fdqring_cfg = { |
398 | .elm_size = K3_RINGACC_RING_ELSIZE_8, |
399 | .flags = K3_RINGACC_RING_SHARED, |
400 | }; |
401 | struct k3_udma_glue_rx_flow_cfg rx_flow_cfg = { |
402 | .rx_cfg = rxring_cfg, |
403 | .rxfdq_cfg = fdqring_cfg, |
404 | .ring_rxq_id = K3_RINGACC_RING_ID_ANY, |
405 | .src_tag_lo_sel = |
406 | K3_UDMA_GLUE_SRC_TAG_LO_USE_REMOTE_SRC_TAG, |
407 | }; |
408 | |
409 | rx_flow_cfg.ring_rxfdq0_id = fdqring_id; |
410 | rx_flow_cfg.rx_cfg.size = max_desc_num; |
411 | rx_flow_cfg.rxfdq_cfg.size = max_desc_num; |
412 | rx_flow_cfg.rxfdq_cfg.mode = emac->prueth->pdata.fdqring_mode; |
413 | |
414 | ret = k3_udma_glue_rx_flow_init(rx_chn: rx_chn->rx_chn, |
415 | flow_idx: i, flow_cfg: &rx_flow_cfg); |
416 | if (ret) { |
417 | netdev_err(dev: ndev, format: "Failed to init rx flow%d %d\n" , |
418 | i, ret); |
419 | goto fail; |
420 | } |
421 | if (!i) |
422 | fdqring_id = k3_udma_glue_rx_flow_get_fdq_id(rx_chn: rx_chn->rx_chn, |
423 | flow_idx: i); |
424 | rx_chn->irq[i] = k3_udma_glue_rx_get_irq(rx_chn: rx_chn->rx_chn, flow_num: i); |
425 | if (rx_chn->irq[i] <= 0) { |
426 | ret = rx_chn->irq[i]; |
427 | netdev_err(dev: ndev, format: "Failed to get rx dma irq" ); |
428 | goto fail; |
429 | } |
430 | } |
431 | |
432 | return 0; |
433 | |
434 | fail: |
435 | prueth_cleanup_rx_chns(emac, rx_chn, max_rflows); |
436 | return ret; |
437 | } |
438 | |
439 | static int prueth_dma_rx_push(struct prueth_emac *emac, |
440 | struct sk_buff *skb, |
441 | struct prueth_rx_chn *rx_chn) |
442 | { |
443 | struct net_device *ndev = emac->ndev; |
444 | struct cppi5_host_desc_t *desc_rx; |
445 | u32 pkt_len = skb_tailroom(skb); |
446 | dma_addr_t desc_dma; |
447 | dma_addr_t buf_dma; |
448 | void **swdata; |
449 | |
450 | desc_rx = k3_cppi_desc_pool_alloc(pool: rx_chn->desc_pool); |
451 | if (!desc_rx) { |
452 | netdev_err(dev: ndev, format: "rx push: failed to allocate descriptor\n" ); |
453 | return -ENOMEM; |
454 | } |
455 | desc_dma = k3_cppi_desc_pool_virt2dma(pool: rx_chn->desc_pool, addr: desc_rx); |
456 | |
457 | buf_dma = dma_map_single(rx_chn->dma_dev, skb->data, pkt_len, DMA_FROM_DEVICE); |
458 | if (unlikely(dma_mapping_error(rx_chn->dma_dev, buf_dma))) { |
459 | k3_cppi_desc_pool_free(pool: rx_chn->desc_pool, addr: desc_rx); |
460 | netdev_err(dev: ndev, format: "rx push: failed to map rx pkt buffer\n" ); |
461 | return -EINVAL; |
462 | } |
463 | |
464 | cppi5_hdesc_init(desc: desc_rx, CPPI5_INFO0_HDESC_EPIB_PRESENT, |
465 | PRUETH_NAV_PS_DATA_SIZE); |
466 | k3_udma_glue_rx_dma_to_cppi5_addr(rx_chn: rx_chn->rx_chn, addr: &buf_dma); |
467 | cppi5_hdesc_attach_buf(desc: desc_rx, buf: buf_dma, buf_data_len: skb_tailroom(skb), obuf: buf_dma, obuf_len: skb_tailroom(skb)); |
468 | |
469 | swdata = cppi5_hdesc_get_swdata(desc: desc_rx); |
470 | *swdata = skb; |
471 | |
472 | return k3_udma_glue_push_rx_chn(rx_chn: rx_chn->rx_chn, flow_num: 0, |
473 | desc_tx: desc_rx, desc_dma); |
474 | } |
475 | |
476 | static u64 icssg_ts_to_ns(u32 hi_sw, u32 hi, u32 lo, u32 cycle_time_ns) |
477 | { |
478 | u32 iepcount_lo, iepcount_hi, hi_rollover_count; |
479 | u64 ns; |
480 | |
481 | iepcount_lo = lo & GENMASK(19, 0); |
482 | iepcount_hi = (hi & GENMASK(11, 0)) << 12 | lo >> 20; |
483 | hi_rollover_count = hi >> 11; |
484 | |
485 | ns = ((u64)hi_rollover_count) << 23 | (iepcount_hi + hi_sw); |
486 | ns = ns * cycle_time_ns + iepcount_lo; |
487 | |
488 | return ns; |
489 | } |
490 | |
491 | static void emac_rx_timestamp(struct prueth_emac *emac, |
492 | struct sk_buff *skb, u32 *psdata) |
493 | { |
494 | struct skb_shared_hwtstamps *ssh; |
495 | u64 ns; |
496 | |
497 | u32 hi_sw = readl(addr: emac->prueth->shram.va + |
498 | TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET); |
499 | ns = icssg_ts_to_ns(hi_sw, hi: psdata[1], lo: psdata[0], |
500 | IEP_DEFAULT_CYCLE_TIME_NS); |
501 | |
502 | ssh = skb_hwtstamps(skb); |
503 | memset(ssh, 0, sizeof(*ssh)); |
504 | ssh->hwtstamp = ns_to_ktime(ns); |
505 | } |
506 | |
507 | static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id) |
508 | { |
509 | struct prueth_rx_chn *rx_chn = &emac->rx_chns; |
510 | u32 buf_dma_len, pkt_len, port_id = 0; |
511 | struct net_device *ndev = emac->ndev; |
512 | struct cppi5_host_desc_t *desc_rx; |
513 | struct sk_buff *skb, *new_skb; |
514 | dma_addr_t desc_dma, buf_dma; |
515 | void **swdata; |
516 | u32 *psdata; |
517 | int ret; |
518 | |
519 | ret = k3_udma_glue_pop_rx_chn(rx_chn: rx_chn->rx_chn, flow_num: flow_id, desc_dma: &desc_dma); |
520 | if (ret) { |
521 | if (ret != -ENODATA) |
522 | netdev_err(dev: ndev, format: "rx pop: failed: %d\n" , ret); |
523 | return ret; |
524 | } |
525 | |
526 | if (cppi5_desc_is_tdcm(paddr: desc_dma)) /* Teardown ? */ |
527 | return 0; |
528 | |
529 | desc_rx = k3_cppi_desc_pool_dma2virt(pool: rx_chn->desc_pool, dma: desc_dma); |
530 | |
531 | swdata = cppi5_hdesc_get_swdata(desc: desc_rx); |
532 | skb = *swdata; |
533 | |
534 | psdata = cppi5_hdesc_get_psdata(desc: desc_rx); |
535 | /* RX HW timestamp */ |
536 | if (emac->rx_ts_enabled) |
537 | emac_rx_timestamp(emac, skb, psdata); |
538 | |
539 | cppi5_hdesc_get_obuf(desc: desc_rx, obuf: &buf_dma, obuf_len: &buf_dma_len); |
540 | k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn: rx_chn->rx_chn, addr: &buf_dma); |
541 | pkt_len = cppi5_hdesc_get_pktlen(desc: desc_rx); |
542 | /* firmware adds 4 CRC bytes, strip them */ |
543 | pkt_len -= 4; |
544 | cppi5_desc_get_tags_ids(desc_hdr: &desc_rx->hdr, src_tag_id: &port_id, NULL); |
545 | |
546 | dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE); |
547 | k3_cppi_desc_pool_free(pool: rx_chn->desc_pool, addr: desc_rx); |
548 | |
549 | skb->dev = ndev; |
550 | new_skb = netdev_alloc_skb_ip_align(dev: ndev, PRUETH_MAX_PKT_SIZE); |
551 | /* if allocation fails we drop the packet but push the |
552 | * descriptor back to the ring with old skb to prevent a stall |
553 | */ |
554 | if (!new_skb) { |
555 | ndev->stats.rx_dropped++; |
556 | new_skb = skb; |
557 | } else { |
558 | /* send the filled skb up the n/w stack */ |
559 | skb_put(skb, len: pkt_len); |
560 | skb->protocol = eth_type_trans(skb, dev: ndev); |
561 | napi_gro_receive(napi: &emac->napi_rx, skb); |
562 | ndev->stats.rx_bytes += pkt_len; |
563 | ndev->stats.rx_packets++; |
564 | } |
565 | |
566 | /* queue another RX DMA */ |
567 | ret = prueth_dma_rx_push(emac, skb: new_skb, rx_chn: &emac->rx_chns); |
568 | if (WARN_ON(ret < 0)) { |
569 | dev_kfree_skb_any(skb: new_skb); |
570 | ndev->stats.rx_errors++; |
571 | ndev->stats.rx_dropped++; |
572 | } |
573 | |
574 | return ret; |
575 | } |
576 | |
577 | static void prueth_rx_cleanup(void *data, dma_addr_t desc_dma) |
578 | { |
579 | struct prueth_rx_chn *rx_chn = data; |
580 | struct cppi5_host_desc_t *desc_rx; |
581 | struct sk_buff *skb; |
582 | dma_addr_t buf_dma; |
583 | u32 buf_dma_len; |
584 | void **swdata; |
585 | |
586 | desc_rx = k3_cppi_desc_pool_dma2virt(pool: rx_chn->desc_pool, dma: desc_dma); |
587 | swdata = cppi5_hdesc_get_swdata(desc: desc_rx); |
588 | skb = *swdata; |
589 | cppi5_hdesc_get_obuf(desc: desc_rx, obuf: &buf_dma, obuf_len: &buf_dma_len); |
590 | k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn: rx_chn->rx_chn, addr: &buf_dma); |
591 | |
592 | dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, |
593 | DMA_FROM_DEVICE); |
594 | k3_cppi_desc_pool_free(pool: rx_chn->desc_pool, addr: desc_rx); |
595 | |
596 | dev_kfree_skb_any(skb); |
597 | } |
598 | |
599 | static int emac_get_tx_ts(struct prueth_emac *emac, |
600 | struct emac_tx_ts_response *rsp) |
601 | { |
602 | struct prueth *prueth = emac->prueth; |
603 | int slice = prueth_emac_slice(emac); |
604 | int addr; |
605 | |
606 | addr = icssg_queue_pop(prueth, queue: slice == 0 ? |
607 | ICSSG_TS_POP_SLICE0 : ICSSG_TS_POP_SLICE1); |
608 | if (addr < 0) |
609 | return addr; |
610 | |
611 | memcpy_fromio(rsp, prueth->shram.va + addr, sizeof(*rsp)); |
612 | /* return buffer back for to pool */ |
613 | icssg_queue_push(prueth, queue: slice == 0 ? |
614 | ICSSG_TS_PUSH_SLICE0 : ICSSG_TS_PUSH_SLICE1, addr); |
615 | |
616 | return 0; |
617 | } |
618 | |
619 | static void tx_ts_work(struct prueth_emac *emac) |
620 | { |
621 | struct skb_shared_hwtstamps ssh; |
622 | struct emac_tx_ts_response tsr; |
623 | struct sk_buff *skb; |
624 | int ret = 0; |
625 | u32 hi_sw; |
626 | u64 ns; |
627 | |
628 | /* There may be more than one pending requests */ |
629 | while (1) { |
630 | ret = emac_get_tx_ts(emac, rsp: &tsr); |
631 | if (ret) /* nothing more */ |
632 | break; |
633 | |
634 | if (tsr.cookie >= PRUETH_MAX_TX_TS_REQUESTS || |
635 | !emac->tx_ts_skb[tsr.cookie]) { |
636 | netdev_err(dev: emac->ndev, format: "Invalid TX TS cookie 0x%x\n" , |
637 | tsr.cookie); |
638 | break; |
639 | } |
640 | |
641 | skb = emac->tx_ts_skb[tsr.cookie]; |
642 | emac->tx_ts_skb[tsr.cookie] = NULL; /* free slot */ |
643 | if (!skb) { |
644 | netdev_err(dev: emac->ndev, format: "Driver Bug! got NULL skb\n" ); |
645 | break; |
646 | } |
647 | |
648 | hi_sw = readl(addr: emac->prueth->shram.va + |
649 | TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET); |
650 | ns = icssg_ts_to_ns(hi_sw, hi: tsr.hi_ts, lo: tsr.lo_ts, |
651 | IEP_DEFAULT_CYCLE_TIME_NS); |
652 | |
653 | memset(&ssh, 0, sizeof(ssh)); |
654 | ssh.hwtstamp = ns_to_ktime(ns); |
655 | |
656 | skb_tstamp_tx(orig_skb: skb, hwtstamps: &ssh); |
657 | dev_consume_skb_any(skb); |
658 | |
659 | if (atomic_dec_and_test(v: &emac->tx_ts_pending)) /* no more? */ |
660 | break; |
661 | } |
662 | } |
663 | |
664 | static int prueth_tx_ts_cookie_get(struct prueth_emac *emac) |
665 | { |
666 | int i; |
667 | |
668 | /* search and get the next free slot */ |
669 | for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) { |
670 | if (!emac->tx_ts_skb[i]) { |
671 | emac->tx_ts_skb[i] = ERR_PTR(error: -EBUSY); /* reserve slot */ |
672 | return i; |
673 | } |
674 | } |
675 | |
676 | return -EBUSY; |
677 | } |
678 | |
679 | /** |
680 | * emac_ndo_start_xmit - EMAC Transmit function |
681 | * @skb: SKB pointer |
682 | * @ndev: EMAC network adapter |
683 | * |
684 | * Called by the system to transmit a packet - we queue the packet in |
685 | * EMAC hardware transmit queue |
686 | * Doesn't wait for completion we'll check for TX completion in |
687 | * emac_tx_complete_packets(). |
688 | * |
689 | * Return: enum netdev_tx |
690 | */ |
691 | static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev) |
692 | { |
693 | struct cppi5_host_desc_t *first_desc, *next_desc, *cur_desc; |
694 | struct prueth_emac *emac = netdev_priv(dev: ndev); |
695 | struct netdev_queue *netif_txq; |
696 | struct prueth_tx_chn *tx_chn; |
697 | dma_addr_t desc_dma, buf_dma; |
698 | int i, ret = 0, q_idx; |
699 | bool in_tx_ts = 0; |
700 | int tx_ts_cookie; |
701 | void **swdata; |
702 | u32 pkt_len; |
703 | u32 *epib; |
704 | |
705 | pkt_len = skb_headlen(skb); |
706 | q_idx = skb_get_queue_mapping(skb); |
707 | |
708 | tx_chn = &emac->tx_chns[q_idx]; |
709 | netif_txq = netdev_get_tx_queue(dev: ndev, index: q_idx); |
710 | |
711 | /* Map the linear buffer */ |
712 | buf_dma = dma_map_single(tx_chn->dma_dev, skb->data, pkt_len, DMA_TO_DEVICE); |
713 | if (dma_mapping_error(dev: tx_chn->dma_dev, dma_addr: buf_dma)) { |
714 | netdev_err(dev: ndev, format: "tx: failed to map skb buffer\n" ); |
715 | ret = NETDEV_TX_OK; |
716 | goto drop_free_skb; |
717 | } |
718 | |
719 | first_desc = k3_cppi_desc_pool_alloc(pool: tx_chn->desc_pool); |
720 | if (!first_desc) { |
721 | netdev_dbg(ndev, "tx: failed to allocate descriptor\n" ); |
722 | dma_unmap_single(tx_chn->dma_dev, buf_dma, pkt_len, DMA_TO_DEVICE); |
723 | goto drop_stop_q_busy; |
724 | } |
725 | |
726 | cppi5_hdesc_init(desc: first_desc, CPPI5_INFO0_HDESC_EPIB_PRESENT, |
727 | PRUETH_NAV_PS_DATA_SIZE); |
728 | cppi5_hdesc_set_pkttype(desc: first_desc, pkt_type: 0); |
729 | epib = first_desc->epib; |
730 | epib[0] = 0; |
731 | epib[1] = 0; |
732 | if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && |
733 | emac->tx_ts_enabled) { |
734 | tx_ts_cookie = prueth_tx_ts_cookie_get(emac); |
735 | if (tx_ts_cookie >= 0) { |
736 | skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; |
737 | /* Request TX timestamp */ |
738 | epib[0] = (u32)tx_ts_cookie; |
739 | epib[1] = 0x80000000; /* TX TS request */ |
740 | emac->tx_ts_skb[tx_ts_cookie] = skb_get(skb); |
741 | in_tx_ts = 1; |
742 | } |
743 | } |
744 | |
745 | /* set dst tag to indicate internal qid at the firmware which is at |
746 | * bit8..bit15. bit0..bit7 indicates port num for directed |
747 | * packets in case of switch mode operation |
748 | */ |
749 | cppi5_desc_set_tags_ids(desc_hdr: &first_desc->hdr, src_tag_id: 0, dst_tag_id: (emac->port_id | (q_idx << 8))); |
750 | k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn: tx_chn->tx_chn, addr: &buf_dma); |
751 | cppi5_hdesc_attach_buf(desc: first_desc, buf: buf_dma, buf_data_len: pkt_len, obuf: buf_dma, obuf_len: pkt_len); |
752 | swdata = cppi5_hdesc_get_swdata(desc: first_desc); |
753 | *swdata = skb; |
754 | |
755 | /* Handle the case where skb is fragmented in pages */ |
756 | cur_desc = first_desc; |
757 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { |
758 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; |
759 | u32 frag_size = skb_frag_size(frag); |
760 | |
761 | next_desc = k3_cppi_desc_pool_alloc(pool: tx_chn->desc_pool); |
762 | if (!next_desc) { |
763 | netdev_err(dev: ndev, |
764 | format: "tx: failed to allocate frag. descriptor\n" ); |
765 | goto free_desc_stop_q_busy_cleanup_tx_ts; |
766 | } |
767 | |
768 | buf_dma = skb_frag_dma_map(dev: tx_chn->dma_dev, frag, offset: 0, size: frag_size, |
769 | dir: DMA_TO_DEVICE); |
770 | if (dma_mapping_error(dev: tx_chn->dma_dev, dma_addr: buf_dma)) { |
771 | netdev_err(dev: ndev, format: "tx: Failed to map skb page\n" ); |
772 | k3_cppi_desc_pool_free(pool: tx_chn->desc_pool, addr: next_desc); |
773 | ret = NETDEV_TX_OK; |
774 | goto cleanup_tx_ts; |
775 | } |
776 | |
777 | cppi5_hdesc_reset_hbdesc(desc: next_desc); |
778 | k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn: tx_chn->tx_chn, addr: &buf_dma); |
779 | cppi5_hdesc_attach_buf(desc: next_desc, |
780 | buf: buf_dma, buf_data_len: frag_size, obuf: buf_dma, obuf_len: frag_size); |
781 | |
782 | desc_dma = k3_cppi_desc_pool_virt2dma(pool: tx_chn->desc_pool, |
783 | addr: next_desc); |
784 | k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn: tx_chn->tx_chn, addr: &desc_dma); |
785 | cppi5_hdesc_link_hbdesc(desc: cur_desc, hbuf_desc: desc_dma); |
786 | |
787 | pkt_len += frag_size; |
788 | cur_desc = next_desc; |
789 | } |
790 | WARN_ON_ONCE(pkt_len != skb->len); |
791 | |
792 | /* report bql before sending packet */ |
793 | netdev_tx_sent_queue(dev_queue: netif_txq, bytes: pkt_len); |
794 | |
795 | cppi5_hdesc_set_pktlen(desc: first_desc, pkt_len); |
796 | desc_dma = k3_cppi_desc_pool_virt2dma(pool: tx_chn->desc_pool, addr: first_desc); |
797 | /* cppi5_desc_dump(first_desc, 64); */ |
798 | |
799 | skb_tx_timestamp(skb); /* SW timestamp if SKBTX_IN_PROGRESS not set */ |
800 | ret = k3_udma_glue_push_tx_chn(tx_chn: tx_chn->tx_chn, desc_tx: first_desc, desc_dma); |
801 | if (ret) { |
802 | netdev_err(dev: ndev, format: "tx: push failed: %d\n" , ret); |
803 | goto drop_free_descs; |
804 | } |
805 | |
806 | if (in_tx_ts) |
807 | atomic_inc(v: &emac->tx_ts_pending); |
808 | |
809 | if (k3_cppi_desc_pool_avail(pool: tx_chn->desc_pool) < MAX_SKB_FRAGS) { |
810 | netif_tx_stop_queue(dev_queue: netif_txq); |
811 | /* Barrier, so that stop_queue visible to other cpus */ |
812 | smp_mb__after_atomic(); |
813 | |
814 | if (k3_cppi_desc_pool_avail(pool: tx_chn->desc_pool) >= |
815 | MAX_SKB_FRAGS) |
816 | netif_tx_wake_queue(dev_queue: netif_txq); |
817 | } |
818 | |
819 | return NETDEV_TX_OK; |
820 | |
821 | cleanup_tx_ts: |
822 | if (in_tx_ts) { |
823 | dev_kfree_skb_any(skb: emac->tx_ts_skb[tx_ts_cookie]); |
824 | emac->tx_ts_skb[tx_ts_cookie] = NULL; |
825 | } |
826 | |
827 | drop_free_descs: |
828 | prueth_xmit_free(tx_chn, desc: first_desc); |
829 | |
830 | drop_free_skb: |
831 | dev_kfree_skb_any(skb); |
832 | |
833 | /* error */ |
834 | ndev->stats.tx_dropped++; |
835 | netdev_err(dev: ndev, format: "tx: error: %d\n" , ret); |
836 | |
837 | return ret; |
838 | |
839 | free_desc_stop_q_busy_cleanup_tx_ts: |
840 | if (in_tx_ts) { |
841 | dev_kfree_skb_any(skb: emac->tx_ts_skb[tx_ts_cookie]); |
842 | emac->tx_ts_skb[tx_ts_cookie] = NULL; |
843 | } |
844 | prueth_xmit_free(tx_chn, desc: first_desc); |
845 | |
846 | drop_stop_q_busy: |
847 | netif_tx_stop_queue(dev_queue: netif_txq); |
848 | return NETDEV_TX_BUSY; |
849 | } |
850 | |
851 | static void prueth_tx_cleanup(void *data, dma_addr_t desc_dma) |
852 | { |
853 | struct prueth_tx_chn *tx_chn = data; |
854 | struct cppi5_host_desc_t *desc_tx; |
855 | struct sk_buff *skb; |
856 | void **swdata; |
857 | |
858 | desc_tx = k3_cppi_desc_pool_dma2virt(pool: tx_chn->desc_pool, dma: desc_dma); |
859 | swdata = cppi5_hdesc_get_swdata(desc: desc_tx); |
860 | skb = *(swdata); |
861 | prueth_xmit_free(tx_chn, desc: desc_tx); |
862 | |
863 | dev_kfree_skb_any(skb); |
864 | } |
865 | |
866 | static irqreturn_t prueth_tx_ts_irq(int irq, void *dev_id) |
867 | { |
868 | struct prueth_emac *emac = dev_id; |
869 | |
870 | /* currently only TX timestamp is being returned */ |
871 | tx_ts_work(emac); |
872 | |
873 | return IRQ_HANDLED; |
874 | } |
875 | |
876 | static irqreturn_t prueth_rx_irq(int irq, void *dev_id) |
877 | { |
878 | struct prueth_emac *emac = dev_id; |
879 | |
880 | disable_irq_nosync(irq); |
881 | napi_schedule(n: &emac->napi_rx); |
882 | |
883 | return IRQ_HANDLED; |
884 | } |
885 | |
886 | struct icssg_firmwares { |
887 | char *pru; |
888 | char *rtu; |
889 | char *txpru; |
890 | }; |
891 | |
892 | static struct icssg_firmwares icssg_emac_firmwares[] = { |
893 | { |
894 | .pru = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf" , |
895 | .rtu = "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf" , |
896 | .txpru = "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf" , |
897 | }, |
898 | { |
899 | .pru = "ti-pruss/am65x-sr2-pru1-prueth-fw.elf" , |
900 | .rtu = "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf" , |
901 | .txpru = "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf" , |
902 | } |
903 | }; |
904 | |
905 | static int prueth_emac_start(struct prueth *prueth, struct prueth_emac *emac) |
906 | { |
907 | struct icssg_firmwares *firmwares; |
908 | struct device *dev = prueth->dev; |
909 | int slice, ret; |
910 | |
911 | firmwares = icssg_emac_firmwares; |
912 | |
913 | slice = prueth_emac_slice(emac); |
914 | if (slice < 0) { |
915 | netdev_err(dev: emac->ndev, format: "invalid port\n" ); |
916 | return -EINVAL; |
917 | } |
918 | |
919 | ret = icssg_config(prueth, emac, slice); |
920 | if (ret) |
921 | return ret; |
922 | |
923 | ret = rproc_set_firmware(rproc: prueth->pru[slice], fw_name: firmwares[slice].pru); |
924 | ret = rproc_boot(rproc: prueth->pru[slice]); |
925 | if (ret) { |
926 | dev_err(dev, "failed to boot PRU%d: %d\n" , slice, ret); |
927 | return -EINVAL; |
928 | } |
929 | |
930 | ret = rproc_set_firmware(rproc: prueth->rtu[slice], fw_name: firmwares[slice].rtu); |
931 | ret = rproc_boot(rproc: prueth->rtu[slice]); |
932 | if (ret) { |
933 | dev_err(dev, "failed to boot RTU%d: %d\n" , slice, ret); |
934 | goto halt_pru; |
935 | } |
936 | |
937 | ret = rproc_set_firmware(rproc: prueth->txpru[slice], fw_name: firmwares[slice].txpru); |
938 | ret = rproc_boot(rproc: prueth->txpru[slice]); |
939 | if (ret) { |
940 | dev_err(dev, "failed to boot TX_PRU%d: %d\n" , slice, ret); |
941 | goto halt_rtu; |
942 | } |
943 | |
944 | emac->fw_running = 1; |
945 | return 0; |
946 | |
947 | halt_rtu: |
948 | rproc_shutdown(rproc: prueth->rtu[slice]); |
949 | |
950 | halt_pru: |
951 | rproc_shutdown(rproc: prueth->pru[slice]); |
952 | |
953 | return ret; |
954 | } |
955 | |
956 | static void prueth_emac_stop(struct prueth_emac *emac) |
957 | { |
958 | struct prueth *prueth = emac->prueth; |
959 | int slice; |
960 | |
961 | switch (emac->port_id) { |
962 | case PRUETH_PORT_MII0: |
963 | slice = ICSS_SLICE0; |
964 | break; |
965 | case PRUETH_PORT_MII1: |
966 | slice = ICSS_SLICE1; |
967 | break; |
968 | default: |
969 | netdev_err(dev: emac->ndev, format: "invalid port\n" ); |
970 | return; |
971 | } |
972 | |
973 | emac->fw_running = 0; |
974 | rproc_shutdown(rproc: prueth->txpru[slice]); |
975 | rproc_shutdown(rproc: prueth->rtu[slice]); |
976 | rproc_shutdown(rproc: prueth->pru[slice]); |
977 | } |
978 | |
979 | static void prueth_cleanup_tx_ts(struct prueth_emac *emac) |
980 | { |
981 | int i; |
982 | |
983 | for (i = 0; i < PRUETH_MAX_TX_TS_REQUESTS; i++) { |
984 | if (emac->tx_ts_skb[i]) { |
985 | dev_kfree_skb_any(skb: emac->tx_ts_skb[i]); |
986 | emac->tx_ts_skb[i] = NULL; |
987 | } |
988 | } |
989 | } |
990 | |
991 | /* called back by PHY layer if there is change in link state of hw port*/ |
992 | static void emac_adjust_link(struct net_device *ndev) |
993 | { |
994 | struct prueth_emac *emac = netdev_priv(dev: ndev); |
995 | struct phy_device *phydev = ndev->phydev; |
996 | struct prueth *prueth = emac->prueth; |
997 | bool new_state = false; |
998 | unsigned long flags; |
999 | |
1000 | if (phydev->link) { |
1001 | /* check the mode of operation - full/half duplex */ |
1002 | if (phydev->duplex != emac->duplex) { |
1003 | new_state = true; |
1004 | emac->duplex = phydev->duplex; |
1005 | } |
1006 | if (phydev->speed != emac->speed) { |
1007 | new_state = true; |
1008 | emac->speed = phydev->speed; |
1009 | } |
1010 | if (!emac->link) { |
1011 | new_state = true; |
1012 | emac->link = 1; |
1013 | } |
1014 | } else if (emac->link) { |
1015 | new_state = true; |
1016 | emac->link = 0; |
1017 | |
1018 | /* f/w should support 100 & 1000 */ |
1019 | emac->speed = SPEED_1000; |
1020 | |
1021 | /* half duplex may not be supported by f/w */ |
1022 | emac->duplex = DUPLEX_FULL; |
1023 | } |
1024 | |
1025 | if (new_state) { |
1026 | phy_print_status(phydev); |
1027 | |
1028 | /* update RGMII and MII configuration based on PHY negotiated |
1029 | * values |
1030 | */ |
1031 | if (emac->link) { |
1032 | if (emac->duplex == DUPLEX_HALF) |
1033 | icssg_config_half_duplex(emac); |
1034 | /* Set the RGMII cfg for gig en and full duplex */ |
1035 | icssg_update_rgmii_cfg(miig_rt: prueth->miig_rt, emac); |
1036 | |
1037 | /* update the Tx IPG based on 100M/1G speed */ |
1038 | spin_lock_irqsave(&emac->lock, flags); |
1039 | icssg_config_ipg(emac); |
1040 | spin_unlock_irqrestore(lock: &emac->lock, flags); |
1041 | icssg_config_set_speed(emac); |
1042 | emac_set_port_state(emac, state: ICSSG_EMAC_PORT_FORWARD); |
1043 | |
1044 | } else { |
1045 | emac_set_port_state(emac, state: ICSSG_EMAC_PORT_DISABLE); |
1046 | } |
1047 | } |
1048 | |
1049 | if (emac->link) { |
1050 | /* reactivate the transmit queue */ |
1051 | netif_tx_wake_all_queues(dev: ndev); |
1052 | } else { |
1053 | netif_tx_stop_all_queues(dev: ndev); |
1054 | prueth_cleanup_tx_ts(emac); |
1055 | } |
1056 | } |
1057 | |
1058 | static int emac_napi_rx_poll(struct napi_struct *napi_rx, int budget) |
1059 | { |
1060 | struct prueth_emac *emac = prueth_napi_to_emac(napi_rx); |
1061 | int rx_flow = PRUETH_RX_FLOW_DATA; |
1062 | int flow = PRUETH_MAX_RX_FLOWS; |
1063 | int num_rx = 0; |
1064 | int cur_budget; |
1065 | int ret; |
1066 | |
1067 | while (flow--) { |
1068 | cur_budget = budget - num_rx; |
1069 | |
1070 | while (cur_budget--) { |
1071 | ret = emac_rx_packet(emac, flow_id: flow); |
1072 | if (ret) |
1073 | break; |
1074 | num_rx++; |
1075 | } |
1076 | |
1077 | if (num_rx >= budget) |
1078 | break; |
1079 | } |
1080 | |
1081 | if (num_rx < budget && napi_complete_done(n: napi_rx, work_done: num_rx)) |
1082 | enable_irq(irq: emac->rx_chns.irq[rx_flow]); |
1083 | |
1084 | return num_rx; |
1085 | } |
1086 | |
1087 | static int prueth_prepare_rx_chan(struct prueth_emac *emac, |
1088 | struct prueth_rx_chn *chn, |
1089 | int buf_size) |
1090 | { |
1091 | struct sk_buff *skb; |
1092 | int i, ret; |
1093 | |
1094 | for (i = 0; i < chn->descs_num; i++) { |
1095 | skb = __netdev_alloc_skb_ip_align(NULL, length: buf_size, GFP_KERNEL); |
1096 | if (!skb) |
1097 | return -ENOMEM; |
1098 | |
1099 | ret = prueth_dma_rx_push(emac, skb, rx_chn: chn); |
1100 | if (ret < 0) { |
1101 | netdev_err(dev: emac->ndev, |
1102 | format: "cannot submit skb for rx chan %s ret %d\n" , |
1103 | chn->name, ret); |
1104 | kfree_skb(skb); |
1105 | return ret; |
1106 | } |
1107 | } |
1108 | |
1109 | return 0; |
1110 | } |
1111 | |
1112 | static void prueth_reset_tx_chan(struct prueth_emac *emac, int ch_num, |
1113 | bool free_skb) |
1114 | { |
1115 | int i; |
1116 | |
1117 | for (i = 0; i < ch_num; i++) { |
1118 | if (free_skb) |
1119 | k3_udma_glue_reset_tx_chn(tx_chn: emac->tx_chns[i].tx_chn, |
1120 | data: &emac->tx_chns[i], |
1121 | cleanup: prueth_tx_cleanup); |
1122 | k3_udma_glue_disable_tx_chn(tx_chn: emac->tx_chns[i].tx_chn); |
1123 | } |
1124 | } |
1125 | |
1126 | static void prueth_reset_rx_chan(struct prueth_rx_chn *chn, |
1127 | int num_flows, bool disable) |
1128 | { |
1129 | int i; |
1130 | |
1131 | for (i = 0; i < num_flows; i++) |
1132 | k3_udma_glue_reset_rx_chn(rx_chn: chn->rx_chn, flow_num: i, data: chn, |
1133 | cleanup: prueth_rx_cleanup, skip_fdq: !!i); |
1134 | if (disable) |
1135 | k3_udma_glue_disable_rx_chn(rx_chn: chn->rx_chn); |
1136 | } |
1137 | |
1138 | static int emac_phy_connect(struct prueth_emac *emac) |
1139 | { |
1140 | struct prueth *prueth = emac->prueth; |
1141 | struct net_device *ndev = emac->ndev; |
1142 | /* connect PHY */ |
1143 | ndev->phydev = of_phy_connect(dev: emac->ndev, phy_np: emac->phy_node, |
1144 | hndlr: &emac_adjust_link, flags: 0, |
1145 | iface: emac->phy_if); |
1146 | if (!ndev->phydev) { |
1147 | dev_err(prueth->dev, "couldn't connect to phy %s\n" , |
1148 | emac->phy_node->full_name); |
1149 | return -ENODEV; |
1150 | } |
1151 | |
1152 | if (!emac->half_duplex) { |
1153 | dev_dbg(prueth->dev, "half duplex mode is not supported\n" ); |
1154 | phy_remove_link_mode(phydev: ndev->phydev, link_mode: ETHTOOL_LINK_MODE_10baseT_Half_BIT); |
1155 | phy_remove_link_mode(phydev: ndev->phydev, link_mode: ETHTOOL_LINK_MODE_100baseT_Half_BIT); |
1156 | } |
1157 | |
1158 | /* remove unsupported modes */ |
1159 | phy_remove_link_mode(phydev: ndev->phydev, link_mode: ETHTOOL_LINK_MODE_1000baseT_Half_BIT); |
1160 | phy_remove_link_mode(phydev: ndev->phydev, link_mode: ETHTOOL_LINK_MODE_Pause_BIT); |
1161 | phy_remove_link_mode(phydev: ndev->phydev, link_mode: ETHTOOL_LINK_MODE_Asym_Pause_BIT); |
1162 | |
1163 | if (emac->phy_if == PHY_INTERFACE_MODE_MII) |
1164 | phy_set_max_speed(phydev: ndev->phydev, SPEED_100); |
1165 | |
1166 | return 0; |
1167 | } |
1168 | |
1169 | static u64 prueth_iep_gettime(void *clockops_data, struct ptp_system_timestamp *sts) |
1170 | { |
1171 | u32 hi_rollover_count, hi_rollover_count_r; |
1172 | struct prueth_emac *emac = clockops_data; |
1173 | struct prueth *prueth = emac->prueth; |
1174 | void __iomem *fw_hi_r_count_addr; |
1175 | void __iomem *fw_count_hi_addr; |
1176 | u32 iepcount_hi, iepcount_hi_r; |
1177 | unsigned long flags; |
1178 | u32 iepcount_lo; |
1179 | u64 ts = 0; |
1180 | |
1181 | fw_count_hi_addr = prueth->shram.va + TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET; |
1182 | fw_hi_r_count_addr = prueth->shram.va + TIMESYNC_FW_WC_HI_ROLLOVER_COUNT_OFFSET; |
1183 | |
1184 | local_irq_save(flags); |
1185 | do { |
1186 | iepcount_hi = icss_iep_get_count_hi(iep: emac->iep); |
1187 | iepcount_hi += readl(addr: fw_count_hi_addr); |
1188 | hi_rollover_count = readl(addr: fw_hi_r_count_addr); |
1189 | ptp_read_system_prets(sts); |
1190 | iepcount_lo = icss_iep_get_count_low(iep: emac->iep); |
1191 | ptp_read_system_postts(sts); |
1192 | |
1193 | iepcount_hi_r = icss_iep_get_count_hi(iep: emac->iep); |
1194 | iepcount_hi_r += readl(addr: fw_count_hi_addr); |
1195 | hi_rollover_count_r = readl(addr: fw_hi_r_count_addr); |
1196 | } while ((iepcount_hi_r != iepcount_hi) || |
1197 | (hi_rollover_count != hi_rollover_count_r)); |
1198 | local_irq_restore(flags); |
1199 | |
1200 | ts = ((u64)hi_rollover_count) << 23 | iepcount_hi; |
1201 | ts = ts * (u64)IEP_DEFAULT_CYCLE_TIME_NS + iepcount_lo; |
1202 | |
1203 | return ts; |
1204 | } |
1205 | |
1206 | static void prueth_iep_settime(void *clockops_data, u64 ns) |
1207 | { |
1208 | struct icssg_setclock_desc __iomem *sc_descp; |
1209 | struct prueth_emac *emac = clockops_data; |
1210 | struct icssg_setclock_desc sc_desc; |
1211 | u64 cyclecount; |
1212 | u32 cycletime; |
1213 | int timeout; |
1214 | |
1215 | if (!emac->fw_running) |
1216 | return; |
1217 | |
1218 | sc_descp = emac->prueth->shram.va + TIMESYNC_FW_WC_SETCLOCK_DESC_OFFSET; |
1219 | |
1220 | cycletime = IEP_DEFAULT_CYCLE_TIME_NS; |
1221 | cyclecount = ns / cycletime; |
1222 | |
1223 | memset(&sc_desc, 0, sizeof(sc_desc)); |
1224 | sc_desc.margin = cycletime - 1000; |
1225 | sc_desc.cyclecounter0_set = cyclecount & GENMASK(31, 0); |
1226 | sc_desc.cyclecounter1_set = (cyclecount & GENMASK(63, 32)) >> 32; |
1227 | sc_desc.iepcount_set = ns % cycletime; |
1228 | sc_desc.CMP0_current = cycletime - 4; //Count from 0 to (cycle time)-4 |
1229 | |
1230 | memcpy_toio(sc_descp, &sc_desc, sizeof(sc_desc)); |
1231 | |
1232 | writeb(val: 1, addr: &sc_descp->request); |
1233 | |
1234 | timeout = 5; /* fw should take 2-3 ms */ |
1235 | while (timeout--) { |
1236 | if (readb(addr: &sc_descp->acknowledgment)) |
1237 | return; |
1238 | |
1239 | usleep_range(min: 500, max: 1000); |
1240 | } |
1241 | |
1242 | dev_err(emac->prueth->dev, "settime timeout\n" ); |
1243 | } |
1244 | |
1245 | static int prueth_perout_enable(void *clockops_data, |
1246 | struct ptp_perout_request *req, int on, |
1247 | u64 *cmp) |
1248 | { |
1249 | struct prueth_emac *emac = clockops_data; |
1250 | u32 reduction_factor = 0, offset = 0; |
1251 | struct timespec64 ts; |
1252 | u64 ns_period; |
1253 | |
1254 | if (!on) |
1255 | return 0; |
1256 | |
1257 | /* Any firmware specific stuff for PPS/PEROUT handling */ |
1258 | ts.tv_sec = req->period.sec; |
1259 | ts.tv_nsec = req->period.nsec; |
1260 | ns_period = timespec64_to_ns(ts: &ts); |
1261 | |
1262 | /* f/w doesn't support period less than cycle time */ |
1263 | if (ns_period < IEP_DEFAULT_CYCLE_TIME_NS) |
1264 | return -ENXIO; |
1265 | |
1266 | reduction_factor = ns_period / IEP_DEFAULT_CYCLE_TIME_NS; |
1267 | offset = ns_period % IEP_DEFAULT_CYCLE_TIME_NS; |
1268 | |
1269 | /* f/w requires at least 1uS within a cycle so CMP |
1270 | * can trigger after SYNC is enabled |
1271 | */ |
1272 | if (offset < 5 * NSEC_PER_USEC) |
1273 | offset = 5 * NSEC_PER_USEC; |
1274 | |
1275 | /* if offset is close to cycle time then we will miss |
1276 | * the CMP event for last tick when IEP rolls over. |
1277 | * In normal mode, IEP tick is 4ns. |
1278 | * In slow compensation it could be 0ns or 8ns at |
1279 | * every slow compensation cycle. |
1280 | */ |
1281 | if (offset > IEP_DEFAULT_CYCLE_TIME_NS - 8) |
1282 | offset = IEP_DEFAULT_CYCLE_TIME_NS - 8; |
1283 | |
1284 | /* we're in shadow mode so need to set upper 32-bits */ |
1285 | *cmp = (u64)offset << 32; |
1286 | |
1287 | writel(val: reduction_factor, addr: emac->prueth->shram.va + |
1288 | TIMESYNC_FW_WC_SYNCOUT_REDUCTION_FACTOR_OFFSET); |
1289 | |
1290 | writel(val: 0, addr: emac->prueth->shram.va + |
1291 | TIMESYNC_FW_WC_SYNCOUT_START_TIME_CYCLECOUNT_OFFSET); |
1292 | |
1293 | return 0; |
1294 | } |
1295 | |
1296 | const struct icss_iep_clockops prueth_iep_clockops = { |
1297 | .settime = prueth_iep_settime, |
1298 | .gettime = prueth_iep_gettime, |
1299 | .perout_enable = prueth_perout_enable, |
1300 | }; |
1301 | |
1302 | /** |
1303 | * emac_ndo_open - EMAC device open |
1304 | * @ndev: network adapter device |
1305 | * |
1306 | * Called when system wants to start the interface. |
1307 | * |
1308 | * Return: 0 for a successful open, or appropriate error code |
1309 | */ |
1310 | static int emac_ndo_open(struct net_device *ndev) |
1311 | { |
1312 | struct prueth_emac *emac = netdev_priv(dev: ndev); |
1313 | int ret, i, num_data_chn = emac->tx_ch_num; |
1314 | struct prueth *prueth = emac->prueth; |
1315 | int slice = prueth_emac_slice(emac); |
1316 | struct device *dev = prueth->dev; |
1317 | int max_rx_flows; |
1318 | int rx_flow; |
1319 | |
1320 | /* clear SMEM and MSMC settings for all slices */ |
1321 | if (!prueth->emacs_initialized) { |
1322 | memset_io(prueth->msmcram.va, 0, prueth->msmcram.size); |
1323 | memset_io(prueth->shram.va, 0, ICSSG_CONFIG_OFFSET_SLICE1 * PRUETH_NUM_MACS); |
1324 | } |
1325 | |
1326 | /* set h/w MAC as user might have re-configured */ |
1327 | ether_addr_copy(dst: emac->mac_addr, src: ndev->dev_addr); |
1328 | |
1329 | icssg_class_set_mac_addr(miig_rt: prueth->miig_rt, slice, mac: emac->mac_addr); |
1330 | icssg_ft1_set_mac_addr(miig_rt: prueth->miig_rt, slice, mac_addr: emac->mac_addr); |
1331 | |
1332 | icssg_class_default(miig_rt: prueth->miig_rt, slice, allmulti: 0); |
1333 | |
1334 | /* Notify the stack of the actual queue counts. */ |
1335 | ret = netif_set_real_num_tx_queues(dev: ndev, txq: num_data_chn); |
1336 | if (ret) { |
1337 | dev_err(dev, "cannot set real number of tx queues\n" ); |
1338 | return ret; |
1339 | } |
1340 | |
1341 | init_completion(x: &emac->cmd_complete); |
1342 | ret = prueth_init_tx_chns(emac); |
1343 | if (ret) { |
1344 | dev_err(dev, "failed to init tx channel: %d\n" , ret); |
1345 | return ret; |
1346 | } |
1347 | |
1348 | max_rx_flows = PRUETH_MAX_RX_FLOWS; |
1349 | ret = prueth_init_rx_chns(emac, rx_chn: &emac->rx_chns, name: "rx" , |
1350 | max_rflows: max_rx_flows, PRUETH_MAX_RX_DESC); |
1351 | if (ret) { |
1352 | dev_err(dev, "failed to init rx channel: %d\n" , ret); |
1353 | goto cleanup_tx; |
1354 | } |
1355 | |
1356 | ret = prueth_ndev_add_tx_napi(emac); |
1357 | if (ret) |
1358 | goto cleanup_rx; |
1359 | |
1360 | /* we use only the highest priority flow for now i.e. @irq[3] */ |
1361 | rx_flow = PRUETH_RX_FLOW_DATA; |
1362 | ret = request_irq(irq: emac->rx_chns.irq[rx_flow], handler: prueth_rx_irq, |
1363 | IRQF_TRIGGER_HIGH, name: dev_name(dev), dev: emac); |
1364 | if (ret) { |
1365 | dev_err(dev, "unable to request RX IRQ\n" ); |
1366 | goto cleanup_napi; |
1367 | } |
1368 | |
1369 | /* reset and start PRU firmware */ |
1370 | ret = prueth_emac_start(prueth, emac); |
1371 | if (ret) |
1372 | goto free_rx_irq; |
1373 | |
1374 | icssg_mii_update_mtu(mii_rt: prueth->mii_rt, mii: slice, mtu: ndev->max_mtu); |
1375 | |
1376 | if (!prueth->emacs_initialized) { |
1377 | ret = icss_iep_init(iep: emac->iep, clkops: &prueth_iep_clockops, |
1378 | clockops_data: emac, IEP_DEFAULT_CYCLE_TIME_NS); |
1379 | } |
1380 | |
1381 | ret = request_threaded_irq(irq: emac->tx_ts_irq, NULL, thread_fn: prueth_tx_ts_irq, |
1382 | IRQF_ONESHOT, name: dev_name(dev), dev: emac); |
1383 | if (ret) |
1384 | goto stop; |
1385 | |
1386 | /* Prepare RX */ |
1387 | ret = prueth_prepare_rx_chan(emac, chn: &emac->rx_chns, PRUETH_MAX_PKT_SIZE); |
1388 | if (ret) |
1389 | goto free_tx_ts_irq; |
1390 | |
1391 | ret = k3_udma_glue_enable_rx_chn(rx_chn: emac->rx_chns.rx_chn); |
1392 | if (ret) |
1393 | goto reset_rx_chn; |
1394 | |
1395 | for (i = 0; i < emac->tx_ch_num; i++) { |
1396 | ret = k3_udma_glue_enable_tx_chn(tx_chn: emac->tx_chns[i].tx_chn); |
1397 | if (ret) |
1398 | goto reset_tx_chan; |
1399 | } |
1400 | |
1401 | /* Enable NAPI in Tx and Rx direction */ |
1402 | for (i = 0; i < emac->tx_ch_num; i++) |
1403 | napi_enable(n: &emac->tx_chns[i].napi_tx); |
1404 | napi_enable(n: &emac->napi_rx); |
1405 | |
1406 | /* start PHY */ |
1407 | phy_start(phydev: ndev->phydev); |
1408 | |
1409 | prueth->emacs_initialized++; |
1410 | |
1411 | queue_work(wq: system_long_wq, work: &emac->stats_work.work); |
1412 | |
1413 | return 0; |
1414 | |
1415 | reset_tx_chan: |
1416 | /* Since interface is not yet up, there is wouldn't be |
1417 | * any SKB for completion. So set false to free_skb |
1418 | */ |
1419 | prueth_reset_tx_chan(emac, ch_num: i, free_skb: false); |
1420 | reset_rx_chn: |
1421 | prueth_reset_rx_chan(chn: &emac->rx_chns, num_flows: max_rx_flows, disable: false); |
1422 | free_tx_ts_irq: |
1423 | free_irq(emac->tx_ts_irq, emac); |
1424 | stop: |
1425 | prueth_emac_stop(emac); |
1426 | free_rx_irq: |
1427 | free_irq(emac->rx_chns.irq[rx_flow], emac); |
1428 | cleanup_napi: |
1429 | prueth_ndev_del_tx_napi(emac, num: emac->tx_ch_num); |
1430 | cleanup_rx: |
1431 | prueth_cleanup_rx_chns(emac, rx_chn: &emac->rx_chns, max_rflows: max_rx_flows); |
1432 | cleanup_tx: |
1433 | prueth_cleanup_tx_chns(emac); |
1434 | |
1435 | return ret; |
1436 | } |
1437 | |
1438 | /** |
1439 | * emac_ndo_stop - EMAC device stop |
1440 | * @ndev: network adapter device |
1441 | * |
1442 | * Called when system wants to stop or down the interface. |
1443 | * |
1444 | * Return: Always 0 (Success) |
1445 | */ |
1446 | static int emac_ndo_stop(struct net_device *ndev) |
1447 | { |
1448 | struct prueth_emac *emac = netdev_priv(dev: ndev); |
1449 | struct prueth *prueth = emac->prueth; |
1450 | int rx_flow = PRUETH_RX_FLOW_DATA; |
1451 | int max_rx_flows; |
1452 | int ret, i; |
1453 | |
1454 | /* inform the upper layers. */ |
1455 | netif_tx_stop_all_queues(dev: ndev); |
1456 | |
1457 | /* block packets from wire */ |
1458 | if (ndev->phydev) |
1459 | phy_stop(phydev: ndev->phydev); |
1460 | |
1461 | icssg_class_disable(miig_rt: prueth->miig_rt, slice: prueth_emac_slice(emac)); |
1462 | |
1463 | atomic_set(v: &emac->tdown_cnt, i: emac->tx_ch_num); |
1464 | /* ensure new tdown_cnt value is visible */ |
1465 | smp_mb__after_atomic(); |
1466 | /* tear down and disable UDMA channels */ |
1467 | reinit_completion(x: &emac->tdown_complete); |
1468 | for (i = 0; i < emac->tx_ch_num; i++) |
1469 | k3_udma_glue_tdown_tx_chn(tx_chn: emac->tx_chns[i].tx_chn, sync: false); |
1470 | |
1471 | ret = wait_for_completion_timeout(x: &emac->tdown_complete, |
1472 | timeout: msecs_to_jiffies(m: 1000)); |
1473 | if (!ret) |
1474 | netdev_err(dev: ndev, format: "tx teardown timeout\n" ); |
1475 | |
1476 | prueth_reset_tx_chan(emac, ch_num: emac->tx_ch_num, free_skb: true); |
1477 | for (i = 0; i < emac->tx_ch_num; i++) |
1478 | napi_disable(n: &emac->tx_chns[i].napi_tx); |
1479 | |
1480 | max_rx_flows = PRUETH_MAX_RX_FLOWS; |
1481 | k3_udma_glue_tdown_rx_chn(rx_chn: emac->rx_chns.rx_chn, sync: true); |
1482 | |
1483 | prueth_reset_rx_chan(chn: &emac->rx_chns, num_flows: max_rx_flows, disable: true); |
1484 | |
1485 | napi_disable(n: &emac->napi_rx); |
1486 | |
1487 | cancel_work_sync(work: &emac->rx_mode_work); |
1488 | |
1489 | /* Destroying the queued work in ndo_stop() */ |
1490 | cancel_delayed_work_sync(dwork: &emac->stats_work); |
1491 | |
1492 | if (prueth->emacs_initialized == 1) |
1493 | icss_iep_exit(iep: emac->iep); |
1494 | |
1495 | /* stop PRUs */ |
1496 | prueth_emac_stop(emac); |
1497 | |
1498 | free_irq(emac->tx_ts_irq, emac); |
1499 | |
1500 | free_irq(emac->rx_chns.irq[rx_flow], emac); |
1501 | prueth_ndev_del_tx_napi(emac, num: emac->tx_ch_num); |
1502 | |
1503 | prueth_cleanup_rx_chns(emac, rx_chn: &emac->rx_chns, max_rflows: max_rx_flows); |
1504 | prueth_cleanup_tx_chns(emac); |
1505 | |
1506 | prueth->emacs_initialized--; |
1507 | |
1508 | return 0; |
1509 | } |
1510 | |
1511 | static void emac_ndo_tx_timeout(struct net_device *ndev, unsigned int txqueue) |
1512 | { |
1513 | ndev->stats.tx_errors++; |
1514 | } |
1515 | |
1516 | static void emac_ndo_set_rx_mode_work(struct work_struct *work) |
1517 | { |
1518 | struct prueth_emac *emac = container_of(work, struct prueth_emac, rx_mode_work); |
1519 | struct net_device *ndev = emac->ndev; |
1520 | bool promisc, allmulti; |
1521 | |
1522 | if (!netif_running(dev: ndev)) |
1523 | return; |
1524 | |
1525 | promisc = ndev->flags & IFF_PROMISC; |
1526 | allmulti = ndev->flags & IFF_ALLMULTI; |
1527 | emac_set_port_state(emac, state: ICSSG_EMAC_PORT_UC_FLOODING_DISABLE); |
1528 | emac_set_port_state(emac, state: ICSSG_EMAC_PORT_MC_FLOODING_DISABLE); |
1529 | |
1530 | if (promisc) { |
1531 | emac_set_port_state(emac, state: ICSSG_EMAC_PORT_UC_FLOODING_ENABLE); |
1532 | emac_set_port_state(emac, state: ICSSG_EMAC_PORT_MC_FLOODING_ENABLE); |
1533 | return; |
1534 | } |
1535 | |
1536 | if (allmulti) { |
1537 | emac_set_port_state(emac, state: ICSSG_EMAC_PORT_MC_FLOODING_ENABLE); |
1538 | return; |
1539 | } |
1540 | |
1541 | if (!netdev_mc_empty(ndev)) { |
1542 | emac_set_port_state(emac, state: ICSSG_EMAC_PORT_MC_FLOODING_ENABLE); |
1543 | return; |
1544 | } |
1545 | } |
1546 | |
1547 | /** |
1548 | * emac_ndo_set_rx_mode - EMAC set receive mode function |
1549 | * @ndev: The EMAC network adapter |
1550 | * |
1551 | * Called when system wants to set the receive mode of the device. |
1552 | * |
1553 | */ |
1554 | static void emac_ndo_set_rx_mode(struct net_device *ndev) |
1555 | { |
1556 | struct prueth_emac *emac = netdev_priv(dev: ndev); |
1557 | |
1558 | queue_work(wq: emac->cmd_wq, work: &emac->rx_mode_work); |
1559 | } |
1560 | |
1561 | static int emac_set_ts_config(struct net_device *ndev, struct ifreq *ifr) |
1562 | { |
1563 | struct prueth_emac *emac = netdev_priv(dev: ndev); |
1564 | struct hwtstamp_config config; |
1565 | |
1566 | if (copy_from_user(to: &config, from: ifr->ifr_data, n: sizeof(config))) |
1567 | return -EFAULT; |
1568 | |
1569 | switch (config.tx_type) { |
1570 | case HWTSTAMP_TX_OFF: |
1571 | emac->tx_ts_enabled = 0; |
1572 | break; |
1573 | case HWTSTAMP_TX_ON: |
1574 | emac->tx_ts_enabled = 1; |
1575 | break; |
1576 | default: |
1577 | return -ERANGE; |
1578 | } |
1579 | |
1580 | switch (config.rx_filter) { |
1581 | case HWTSTAMP_FILTER_NONE: |
1582 | emac->rx_ts_enabled = 0; |
1583 | break; |
1584 | case HWTSTAMP_FILTER_ALL: |
1585 | case HWTSTAMP_FILTER_SOME: |
1586 | case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: |
1587 | case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: |
1588 | case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: |
1589 | case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: |
1590 | case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: |
1591 | case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: |
1592 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: |
1593 | case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: |
1594 | case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: |
1595 | case HWTSTAMP_FILTER_PTP_V2_EVENT: |
1596 | case HWTSTAMP_FILTER_PTP_V2_SYNC: |
1597 | case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: |
1598 | case HWTSTAMP_FILTER_NTP_ALL: |
1599 | emac->rx_ts_enabled = 1; |
1600 | config.rx_filter = HWTSTAMP_FILTER_ALL; |
1601 | break; |
1602 | default: |
1603 | return -ERANGE; |
1604 | } |
1605 | |
1606 | return copy_to_user(to: ifr->ifr_data, from: &config, n: sizeof(config)) ? |
1607 | -EFAULT : 0; |
1608 | } |
1609 | |
1610 | static int emac_get_ts_config(struct net_device *ndev, struct ifreq *ifr) |
1611 | { |
1612 | struct prueth_emac *emac = netdev_priv(dev: ndev); |
1613 | struct hwtstamp_config config; |
1614 | |
1615 | config.flags = 0; |
1616 | config.tx_type = emac->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; |
1617 | config.rx_filter = emac->rx_ts_enabled ? HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE; |
1618 | |
1619 | return copy_to_user(to: ifr->ifr_data, from: &config, n: sizeof(config)) ? |
1620 | -EFAULT : 0; |
1621 | } |
1622 | |
1623 | static int emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) |
1624 | { |
1625 | switch (cmd) { |
1626 | case SIOCGHWTSTAMP: |
1627 | return emac_get_ts_config(ndev, ifr); |
1628 | case SIOCSHWTSTAMP: |
1629 | return emac_set_ts_config(ndev, ifr); |
1630 | default: |
1631 | break; |
1632 | } |
1633 | |
1634 | return phy_do_ioctl(dev: ndev, ifr, cmd); |
1635 | } |
1636 | |
1637 | static void emac_ndo_get_stats64(struct net_device *ndev, |
1638 | struct rtnl_link_stats64 *stats) |
1639 | { |
1640 | struct prueth_emac *emac = netdev_priv(dev: ndev); |
1641 | |
1642 | emac_update_hardware_stats(emac); |
1643 | |
1644 | stats->rx_packets = emac_get_stat_by_name(emac, stat_name: "rx_packets" ); |
1645 | stats->rx_bytes = emac_get_stat_by_name(emac, stat_name: "rx_bytes" ); |
1646 | stats->tx_packets = emac_get_stat_by_name(emac, stat_name: "tx_packets" ); |
1647 | stats->tx_bytes = emac_get_stat_by_name(emac, stat_name: "tx_bytes" ); |
1648 | stats->rx_crc_errors = emac_get_stat_by_name(emac, stat_name: "rx_crc_errors" ); |
1649 | stats->rx_over_errors = emac_get_stat_by_name(emac, stat_name: "rx_over_errors" ); |
1650 | stats->multicast = emac_get_stat_by_name(emac, stat_name: "rx_multicast_frames" ); |
1651 | |
1652 | stats->rx_errors = ndev->stats.rx_errors; |
1653 | stats->rx_dropped = ndev->stats.rx_dropped; |
1654 | stats->tx_errors = ndev->stats.tx_errors; |
1655 | stats->tx_dropped = ndev->stats.tx_dropped; |
1656 | } |
1657 | |
1658 | static int emac_ndo_get_phys_port_name(struct net_device *ndev, char *name, |
1659 | size_t len) |
1660 | { |
1661 | struct prueth_emac *emac = netdev_priv(dev: ndev); |
1662 | int ret; |
1663 | |
1664 | ret = snprintf(buf: name, size: len, fmt: "p%d" , emac->port_id); |
1665 | if (ret >= len) |
1666 | return -EINVAL; |
1667 | |
1668 | return 0; |
1669 | } |
1670 | |
1671 | static const struct net_device_ops emac_netdev_ops = { |
1672 | .ndo_open = emac_ndo_open, |
1673 | .ndo_stop = emac_ndo_stop, |
1674 | .ndo_start_xmit = emac_ndo_start_xmit, |
1675 | .ndo_set_mac_address = eth_mac_addr, |
1676 | .ndo_validate_addr = eth_validate_addr, |
1677 | .ndo_tx_timeout = emac_ndo_tx_timeout, |
1678 | .ndo_set_rx_mode = emac_ndo_set_rx_mode, |
1679 | .ndo_eth_ioctl = emac_ndo_ioctl, |
1680 | .ndo_get_stats64 = emac_ndo_get_stats64, |
1681 | .ndo_get_phys_port_name = emac_ndo_get_phys_port_name, |
1682 | }; |
1683 | |
1684 | /* get emac_port corresponding to eth_node name */ |
1685 | static int prueth_node_port(struct device_node *eth_node) |
1686 | { |
1687 | u32 port_id; |
1688 | int ret; |
1689 | |
1690 | ret = of_property_read_u32(np: eth_node, propname: "reg" , out_value: &port_id); |
1691 | if (ret) |
1692 | return ret; |
1693 | |
1694 | if (port_id == 0) |
1695 | return PRUETH_PORT_MII0; |
1696 | else if (port_id == 1) |
1697 | return PRUETH_PORT_MII1; |
1698 | else |
1699 | return PRUETH_PORT_INVALID; |
1700 | } |
1701 | |
1702 | /* get MAC instance corresponding to eth_node name */ |
1703 | static int prueth_node_mac(struct device_node *eth_node) |
1704 | { |
1705 | u32 port_id; |
1706 | int ret; |
1707 | |
1708 | ret = of_property_read_u32(np: eth_node, propname: "reg" , out_value: &port_id); |
1709 | if (ret) |
1710 | return ret; |
1711 | |
1712 | if (port_id == 0) |
1713 | return PRUETH_MAC0; |
1714 | else if (port_id == 1) |
1715 | return PRUETH_MAC1; |
1716 | else |
1717 | return PRUETH_MAC_INVALID; |
1718 | } |
1719 | |
1720 | static int prueth_netdev_init(struct prueth *prueth, |
1721 | struct device_node *eth_node) |
1722 | { |
1723 | int ret, num_tx_chn = PRUETH_MAX_TX_QUEUES; |
1724 | struct prueth_emac *emac; |
1725 | struct net_device *ndev; |
1726 | enum prueth_port port; |
1727 | const char *irq_name; |
1728 | enum prueth_mac mac; |
1729 | |
1730 | port = prueth_node_port(eth_node); |
1731 | if (port == PRUETH_PORT_INVALID) |
1732 | return -EINVAL; |
1733 | |
1734 | mac = prueth_node_mac(eth_node); |
1735 | if (mac == PRUETH_MAC_INVALID) |
1736 | return -EINVAL; |
1737 | |
1738 | ndev = alloc_etherdev_mq(sizeof(*emac), num_tx_chn); |
1739 | if (!ndev) |
1740 | return -ENOMEM; |
1741 | |
1742 | emac = netdev_priv(dev: ndev); |
1743 | emac->prueth = prueth; |
1744 | emac->ndev = ndev; |
1745 | emac->port_id = port; |
1746 | emac->cmd_wq = create_singlethread_workqueue("icssg_cmd_wq" ); |
1747 | if (!emac->cmd_wq) { |
1748 | ret = -ENOMEM; |
1749 | goto free_ndev; |
1750 | } |
1751 | INIT_WORK(&emac->rx_mode_work, emac_ndo_set_rx_mode_work); |
1752 | |
1753 | INIT_DELAYED_WORK(&emac->stats_work, emac_stats_work_handler); |
1754 | |
1755 | ret = pruss_request_mem_region(pruss: prueth->pruss, |
1756 | mem_id: port == PRUETH_PORT_MII0 ? |
1757 | PRUSS_MEM_DRAM0 : PRUSS_MEM_DRAM1, |
1758 | region: &emac->dram); |
1759 | if (ret) { |
1760 | dev_err(prueth->dev, "unable to get DRAM: %d\n" , ret); |
1761 | ret = -ENOMEM; |
1762 | goto free_wq; |
1763 | } |
1764 | |
1765 | emac->tx_ch_num = 1; |
1766 | |
1767 | irq_name = "tx_ts0" ; |
1768 | if (emac->port_id == PRUETH_PORT_MII1) |
1769 | irq_name = "tx_ts1" ; |
1770 | emac->tx_ts_irq = platform_get_irq_byname_optional(dev: prueth->pdev, name: irq_name); |
1771 | if (emac->tx_ts_irq < 0) { |
1772 | ret = dev_err_probe(dev: prueth->dev, err: emac->tx_ts_irq, fmt: "could not get tx_ts_irq\n" ); |
1773 | goto free; |
1774 | } |
1775 | |
1776 | SET_NETDEV_DEV(ndev, prueth->dev); |
1777 | spin_lock_init(&emac->lock); |
1778 | mutex_init(&emac->cmd_lock); |
1779 | |
1780 | emac->phy_node = of_parse_phandle(np: eth_node, phandle_name: "phy-handle" , index: 0); |
1781 | if (!emac->phy_node && !of_phy_is_fixed_link(np: eth_node)) { |
1782 | dev_err(prueth->dev, "couldn't find phy-handle\n" ); |
1783 | ret = -ENODEV; |
1784 | goto free; |
1785 | } else if (of_phy_is_fixed_link(np: eth_node)) { |
1786 | ret = of_phy_register_fixed_link(np: eth_node); |
1787 | if (ret) { |
1788 | ret = dev_err_probe(dev: prueth->dev, err: ret, |
1789 | fmt: "failed to register fixed-link phy\n" ); |
1790 | goto free; |
1791 | } |
1792 | |
1793 | emac->phy_node = eth_node; |
1794 | } |
1795 | |
1796 | ret = of_get_phy_mode(np: eth_node, interface: &emac->phy_if); |
1797 | if (ret) { |
1798 | dev_err(prueth->dev, "could not get phy-mode property\n" ); |
1799 | goto free; |
1800 | } |
1801 | |
1802 | if (emac->phy_if != PHY_INTERFACE_MODE_MII && |
1803 | !phy_interface_mode_is_rgmii(mode: emac->phy_if)) { |
1804 | dev_err(prueth->dev, "PHY mode unsupported %s\n" , phy_modes(emac->phy_if)); |
1805 | ret = -EINVAL; |
1806 | goto free; |
1807 | } |
1808 | |
1809 | /* AM65 SR2.0 has TX Internal delay always enabled by hardware |
1810 | * and it is not possible to disable TX Internal delay. The below |
1811 | * switch case block describes how we handle different phy modes |
1812 | * based on hardware restriction. |
1813 | */ |
1814 | switch (emac->phy_if) { |
1815 | case PHY_INTERFACE_MODE_RGMII_ID: |
1816 | emac->phy_if = PHY_INTERFACE_MODE_RGMII_RXID; |
1817 | break; |
1818 | case PHY_INTERFACE_MODE_RGMII_TXID: |
1819 | emac->phy_if = PHY_INTERFACE_MODE_RGMII; |
1820 | break; |
1821 | case PHY_INTERFACE_MODE_RGMII: |
1822 | case PHY_INTERFACE_MODE_RGMII_RXID: |
1823 | dev_err(prueth->dev, "RGMII mode without TX delay is not supported" ); |
1824 | ret = -EINVAL; |
1825 | goto free; |
1826 | default: |
1827 | break; |
1828 | } |
1829 | |
1830 | /* get mac address from DT and set private and netdev addr */ |
1831 | ret = of_get_ethdev_address(np: eth_node, dev: ndev); |
1832 | if (!is_valid_ether_addr(addr: ndev->dev_addr)) { |
1833 | eth_hw_addr_random(dev: ndev); |
1834 | dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n" , |
1835 | port, ndev->dev_addr); |
1836 | } |
1837 | ether_addr_copy(dst: emac->mac_addr, src: ndev->dev_addr); |
1838 | |
1839 | ndev->min_mtu = PRUETH_MIN_PKT_SIZE; |
1840 | ndev->max_mtu = PRUETH_MAX_MTU; |
1841 | ndev->netdev_ops = &emac_netdev_ops; |
1842 | ndev->ethtool_ops = &icssg_ethtool_ops; |
1843 | ndev->hw_features = NETIF_F_SG; |
1844 | ndev->features = ndev->hw_features; |
1845 | |
1846 | netif_napi_add(dev: ndev, napi: &emac->napi_rx, poll: emac_napi_rx_poll); |
1847 | prueth->emac[mac] = emac; |
1848 | |
1849 | return 0; |
1850 | |
1851 | free: |
1852 | pruss_release_mem_region(pruss: prueth->pruss, region: &emac->dram); |
1853 | free_wq: |
1854 | destroy_workqueue(wq: emac->cmd_wq); |
1855 | free_ndev: |
1856 | emac->ndev = NULL; |
1857 | prueth->emac[mac] = NULL; |
1858 | free_netdev(dev: ndev); |
1859 | |
1860 | return ret; |
1861 | } |
1862 | |
1863 | static void prueth_netdev_exit(struct prueth *prueth, |
1864 | struct device_node *eth_node) |
1865 | { |
1866 | struct prueth_emac *emac; |
1867 | enum prueth_mac mac; |
1868 | |
1869 | mac = prueth_node_mac(eth_node); |
1870 | if (mac == PRUETH_MAC_INVALID) |
1871 | return; |
1872 | |
1873 | emac = prueth->emac[mac]; |
1874 | if (!emac) |
1875 | return; |
1876 | |
1877 | if (of_phy_is_fixed_link(np: emac->phy_node)) |
1878 | of_phy_deregister_fixed_link(np: emac->phy_node); |
1879 | |
1880 | netif_napi_del(napi: &emac->napi_rx); |
1881 | |
1882 | pruss_release_mem_region(pruss: prueth->pruss, region: &emac->dram); |
1883 | destroy_workqueue(wq: emac->cmd_wq); |
1884 | free_netdev(dev: emac->ndev); |
1885 | prueth->emac[mac] = NULL; |
1886 | } |
1887 | |
1888 | static int prueth_get_cores(struct prueth *prueth, int slice) |
1889 | { |
1890 | struct device *dev = prueth->dev; |
1891 | enum pruss_pru_id pruss_id; |
1892 | struct device_node *np; |
1893 | int idx = -1, ret; |
1894 | |
1895 | np = dev->of_node; |
1896 | |
1897 | switch (slice) { |
1898 | case ICSS_SLICE0: |
1899 | idx = 0; |
1900 | break; |
1901 | case ICSS_SLICE1: |
1902 | idx = 3; |
1903 | break; |
1904 | default: |
1905 | return -EINVAL; |
1906 | } |
1907 | |
1908 | prueth->pru[slice] = pru_rproc_get(np, index: idx, pru_id: &pruss_id); |
1909 | if (IS_ERR(ptr: prueth->pru[slice])) { |
1910 | ret = PTR_ERR(ptr: prueth->pru[slice]); |
1911 | prueth->pru[slice] = NULL; |
1912 | return dev_err_probe(dev, err: ret, fmt: "unable to get PRU%d\n" , slice); |
1913 | } |
1914 | prueth->pru_id[slice] = pruss_id; |
1915 | |
1916 | idx++; |
1917 | prueth->rtu[slice] = pru_rproc_get(np, index: idx, NULL); |
1918 | if (IS_ERR(ptr: prueth->rtu[slice])) { |
1919 | ret = PTR_ERR(ptr: prueth->rtu[slice]); |
1920 | prueth->rtu[slice] = NULL; |
1921 | return dev_err_probe(dev, err: ret, fmt: "unable to get RTU%d\n" , slice); |
1922 | } |
1923 | |
1924 | idx++; |
1925 | prueth->txpru[slice] = pru_rproc_get(np, index: idx, NULL); |
1926 | if (IS_ERR(ptr: prueth->txpru[slice])) { |
1927 | ret = PTR_ERR(ptr: prueth->txpru[slice]); |
1928 | prueth->txpru[slice] = NULL; |
1929 | return dev_err_probe(dev, err: ret, fmt: "unable to get TX_PRU%d\n" , slice); |
1930 | } |
1931 | |
1932 | return 0; |
1933 | } |
1934 | |
1935 | static void prueth_put_cores(struct prueth *prueth, int slice) |
1936 | { |
1937 | if (prueth->txpru[slice]) |
1938 | pru_rproc_put(rproc: prueth->txpru[slice]); |
1939 | |
1940 | if (prueth->rtu[slice]) |
1941 | pru_rproc_put(rproc: prueth->rtu[slice]); |
1942 | |
1943 | if (prueth->pru[slice]) |
1944 | pru_rproc_put(rproc: prueth->pru[slice]); |
1945 | } |
1946 | |
1947 | static int prueth_probe(struct platform_device *pdev) |
1948 | { |
1949 | struct device_node *eth_node, *eth_ports_node; |
1950 | struct device_node *eth0_node = NULL; |
1951 | struct device_node *eth1_node = NULL; |
1952 | struct genpool_data_align gp_data = { |
1953 | .align = SZ_64K, |
1954 | }; |
1955 | struct device *dev = &pdev->dev; |
1956 | struct device_node *np; |
1957 | struct prueth *prueth; |
1958 | struct pruss *pruss; |
1959 | u32 msmc_ram_size; |
1960 | int i, ret; |
1961 | |
1962 | np = dev->of_node; |
1963 | |
1964 | prueth = devm_kzalloc(dev, size: sizeof(*prueth), GFP_KERNEL); |
1965 | if (!prueth) |
1966 | return -ENOMEM; |
1967 | |
1968 | dev_set_drvdata(dev, data: prueth); |
1969 | prueth->pdev = pdev; |
1970 | prueth->pdata = *(const struct prueth_pdata *)device_get_match_data(dev); |
1971 | |
1972 | prueth->dev = dev; |
1973 | eth_ports_node = of_get_child_by_name(node: np, name: "ethernet-ports" ); |
1974 | if (!eth_ports_node) |
1975 | return -ENOENT; |
1976 | |
1977 | for_each_child_of_node(eth_ports_node, eth_node) { |
1978 | u32 reg; |
1979 | |
1980 | if (strcmp(eth_node->name, "port" )) |
1981 | continue; |
1982 | ret = of_property_read_u32(np: eth_node, propname: "reg" , out_value: ®); |
1983 | if (ret < 0) { |
1984 | dev_err(dev, "%pOF error reading port_id %d\n" , |
1985 | eth_node, ret); |
1986 | } |
1987 | |
1988 | of_node_get(node: eth_node); |
1989 | |
1990 | if (reg == 0) { |
1991 | eth0_node = eth_node; |
1992 | if (!of_device_is_available(device: eth0_node)) { |
1993 | of_node_put(node: eth0_node); |
1994 | eth0_node = NULL; |
1995 | } |
1996 | } else if (reg == 1) { |
1997 | eth1_node = eth_node; |
1998 | if (!of_device_is_available(device: eth1_node)) { |
1999 | of_node_put(node: eth1_node); |
2000 | eth1_node = NULL; |
2001 | } |
2002 | } else { |
2003 | dev_err(dev, "port reg should be 0 or 1\n" ); |
2004 | } |
2005 | } |
2006 | |
2007 | of_node_put(node: eth_ports_node); |
2008 | |
2009 | /* At least one node must be present and available else we fail */ |
2010 | if (!eth0_node && !eth1_node) { |
2011 | dev_err(dev, "neither port0 nor port1 node available\n" ); |
2012 | return -ENODEV; |
2013 | } |
2014 | |
2015 | if (eth0_node == eth1_node) { |
2016 | dev_err(dev, "port0 and port1 can't have same reg\n" ); |
2017 | of_node_put(node: eth0_node); |
2018 | return -ENODEV; |
2019 | } |
2020 | |
2021 | prueth->eth_node[PRUETH_MAC0] = eth0_node; |
2022 | prueth->eth_node[PRUETH_MAC1] = eth1_node; |
2023 | |
2024 | prueth->miig_rt = syscon_regmap_lookup_by_phandle(np, property: "ti,mii-g-rt" ); |
2025 | if (IS_ERR(ptr: prueth->miig_rt)) { |
2026 | dev_err(dev, "couldn't get ti,mii-g-rt syscon regmap\n" ); |
2027 | return -ENODEV; |
2028 | } |
2029 | |
2030 | prueth->mii_rt = syscon_regmap_lookup_by_phandle(np, property: "ti,mii-rt" ); |
2031 | if (IS_ERR(ptr: prueth->mii_rt)) { |
2032 | dev_err(dev, "couldn't get ti,mii-rt syscon regmap\n" ); |
2033 | return -ENODEV; |
2034 | } |
2035 | |
2036 | if (eth0_node) { |
2037 | ret = prueth_get_cores(prueth, ICSS_SLICE0); |
2038 | if (ret) |
2039 | goto put_cores; |
2040 | } |
2041 | |
2042 | if (eth1_node) { |
2043 | ret = prueth_get_cores(prueth, ICSS_SLICE1); |
2044 | if (ret) |
2045 | goto put_cores; |
2046 | } |
2047 | |
2048 | pruss = pruss_get(rproc: eth0_node ? |
2049 | prueth->pru[ICSS_SLICE0] : prueth->pru[ICSS_SLICE1]); |
2050 | if (IS_ERR(ptr: pruss)) { |
2051 | ret = PTR_ERR(ptr: pruss); |
2052 | dev_err(dev, "unable to get pruss handle\n" ); |
2053 | goto put_cores; |
2054 | } |
2055 | |
2056 | prueth->pruss = pruss; |
2057 | |
2058 | ret = pruss_request_mem_region(pruss, mem_id: PRUSS_MEM_SHRD_RAM2, |
2059 | region: &prueth->shram); |
2060 | if (ret) { |
2061 | dev_err(dev, "unable to get PRUSS SHRD RAM2: %d\n" , ret); |
2062 | goto put_pruss; |
2063 | } |
2064 | |
2065 | prueth->sram_pool = of_gen_pool_get(np, propname: "sram" , index: 0); |
2066 | if (!prueth->sram_pool) { |
2067 | dev_err(dev, "unable to get SRAM pool\n" ); |
2068 | ret = -ENODEV; |
2069 | |
2070 | goto put_mem; |
2071 | } |
2072 | |
2073 | msmc_ram_size = MSMC_RAM_SIZE; |
2074 | |
2075 | /* NOTE: FW bug needs buffer base to be 64KB aligned */ |
2076 | prueth->msmcram.va = |
2077 | (void __iomem *)gen_pool_alloc_algo(pool: prueth->sram_pool, |
2078 | size: msmc_ram_size, |
2079 | algo: gen_pool_first_fit_align, |
2080 | data: &gp_data); |
2081 | |
2082 | if (!prueth->msmcram.va) { |
2083 | ret = -ENOMEM; |
2084 | dev_err(dev, "unable to allocate MSMC resource\n" ); |
2085 | goto put_mem; |
2086 | } |
2087 | prueth->msmcram.pa = gen_pool_virt_to_phys(pool: prueth->sram_pool, |
2088 | (unsigned long)prueth->msmcram.va); |
2089 | prueth->msmcram.size = msmc_ram_size; |
2090 | memset_io(prueth->msmcram.va, 0, msmc_ram_size); |
2091 | dev_dbg(dev, "sram: pa %llx va %p size %zx\n" , prueth->msmcram.pa, |
2092 | prueth->msmcram.va, prueth->msmcram.size); |
2093 | |
2094 | prueth->iep0 = icss_iep_get_idx(np, idx: 0); |
2095 | if (IS_ERR(ptr: prueth->iep0)) { |
2096 | ret = dev_err_probe(dev, err: PTR_ERR(ptr: prueth->iep0), fmt: "iep0 get failed\n" ); |
2097 | prueth->iep0 = NULL; |
2098 | goto free_pool; |
2099 | } |
2100 | |
2101 | prueth->iep1 = icss_iep_get_idx(np, idx: 1); |
2102 | if (IS_ERR(ptr: prueth->iep1)) { |
2103 | ret = dev_err_probe(dev, err: PTR_ERR(ptr: prueth->iep1), fmt: "iep1 get failed\n" ); |
2104 | goto put_iep0; |
2105 | } |
2106 | |
2107 | if (prueth->pdata.quirk_10m_link_issue) { |
2108 | /* Enable IEP1 for FW in 64bit mode as W/A for 10M FD link detect issue under TX |
2109 | * traffic. |
2110 | */ |
2111 | icss_iep_init_fw(iep: prueth->iep1); |
2112 | } |
2113 | |
2114 | /* setup netdev interfaces */ |
2115 | if (eth0_node) { |
2116 | ret = prueth_netdev_init(prueth, eth_node: eth0_node); |
2117 | if (ret) { |
2118 | dev_err_probe(dev, err: ret, fmt: "netdev init %s failed\n" , |
2119 | eth0_node->name); |
2120 | goto exit_iep; |
2121 | } |
2122 | |
2123 | if (of_find_property(np: eth0_node, name: "ti,half-duplex-capable" , NULL)) |
2124 | prueth->emac[PRUETH_MAC0]->half_duplex = 1; |
2125 | |
2126 | prueth->emac[PRUETH_MAC0]->iep = prueth->iep0; |
2127 | } |
2128 | |
2129 | if (eth1_node) { |
2130 | ret = prueth_netdev_init(prueth, eth_node: eth1_node); |
2131 | if (ret) { |
2132 | dev_err_probe(dev, err: ret, fmt: "netdev init %s failed\n" , |
2133 | eth1_node->name); |
2134 | goto netdev_exit; |
2135 | } |
2136 | |
2137 | if (of_find_property(np: eth1_node, name: "ti,half-duplex-capable" , NULL)) |
2138 | prueth->emac[PRUETH_MAC1]->half_duplex = 1; |
2139 | |
2140 | prueth->emac[PRUETH_MAC1]->iep = prueth->iep0; |
2141 | } |
2142 | |
2143 | /* register the network devices */ |
2144 | if (eth0_node) { |
2145 | ret = register_netdev(dev: prueth->emac[PRUETH_MAC0]->ndev); |
2146 | if (ret) { |
2147 | dev_err(dev, "can't register netdev for port MII0" ); |
2148 | goto netdev_exit; |
2149 | } |
2150 | |
2151 | prueth->registered_netdevs[PRUETH_MAC0] = prueth->emac[PRUETH_MAC0]->ndev; |
2152 | |
2153 | emac_phy_connect(emac: prueth->emac[PRUETH_MAC0]); |
2154 | phy_attached_info(phydev: prueth->emac[PRUETH_MAC0]->ndev->phydev); |
2155 | } |
2156 | |
2157 | if (eth1_node) { |
2158 | ret = register_netdev(dev: prueth->emac[PRUETH_MAC1]->ndev); |
2159 | if (ret) { |
2160 | dev_err(dev, "can't register netdev for port MII1" ); |
2161 | goto netdev_unregister; |
2162 | } |
2163 | |
2164 | prueth->registered_netdevs[PRUETH_MAC1] = prueth->emac[PRUETH_MAC1]->ndev; |
2165 | emac_phy_connect(emac: prueth->emac[PRUETH_MAC1]); |
2166 | phy_attached_info(phydev: prueth->emac[PRUETH_MAC1]->ndev->phydev); |
2167 | } |
2168 | |
2169 | dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n" , |
2170 | (!eth0_node || !eth1_node) ? "single" : "dual" ); |
2171 | |
2172 | if (eth1_node) |
2173 | of_node_put(node: eth1_node); |
2174 | if (eth0_node) |
2175 | of_node_put(node: eth0_node); |
2176 | return 0; |
2177 | |
2178 | netdev_unregister: |
2179 | for (i = 0; i < PRUETH_NUM_MACS; i++) { |
2180 | if (!prueth->registered_netdevs[i]) |
2181 | continue; |
2182 | if (prueth->emac[i]->ndev->phydev) { |
2183 | phy_disconnect(phydev: prueth->emac[i]->ndev->phydev); |
2184 | prueth->emac[i]->ndev->phydev = NULL; |
2185 | } |
2186 | unregister_netdev(dev: prueth->registered_netdevs[i]); |
2187 | } |
2188 | |
2189 | netdev_exit: |
2190 | for (i = 0; i < PRUETH_NUM_MACS; i++) { |
2191 | eth_node = prueth->eth_node[i]; |
2192 | if (!eth_node) |
2193 | continue; |
2194 | |
2195 | prueth_netdev_exit(prueth, eth_node); |
2196 | } |
2197 | |
2198 | exit_iep: |
2199 | if (prueth->pdata.quirk_10m_link_issue) |
2200 | icss_iep_exit_fw(iep: prueth->iep1); |
2201 | icss_iep_put(iep: prueth->iep1); |
2202 | |
2203 | put_iep0: |
2204 | icss_iep_put(iep: prueth->iep0); |
2205 | prueth->iep0 = NULL; |
2206 | prueth->iep1 = NULL; |
2207 | |
2208 | free_pool: |
2209 | gen_pool_free(pool: prueth->sram_pool, |
2210 | addr: (unsigned long)prueth->msmcram.va, size: msmc_ram_size); |
2211 | |
2212 | put_mem: |
2213 | pruss_release_mem_region(pruss: prueth->pruss, region: &prueth->shram); |
2214 | |
2215 | put_pruss: |
2216 | pruss_put(pruss: prueth->pruss); |
2217 | |
2218 | put_cores: |
2219 | if (eth1_node) { |
2220 | prueth_put_cores(prueth, ICSS_SLICE1); |
2221 | of_node_put(node: eth1_node); |
2222 | } |
2223 | |
2224 | if (eth0_node) { |
2225 | prueth_put_cores(prueth, ICSS_SLICE0); |
2226 | of_node_put(node: eth0_node); |
2227 | } |
2228 | |
2229 | return ret; |
2230 | } |
2231 | |
2232 | static void prueth_remove(struct platform_device *pdev) |
2233 | { |
2234 | struct prueth *prueth = platform_get_drvdata(pdev); |
2235 | struct device_node *eth_node; |
2236 | int i; |
2237 | |
2238 | for (i = 0; i < PRUETH_NUM_MACS; i++) { |
2239 | if (!prueth->registered_netdevs[i]) |
2240 | continue; |
2241 | phy_stop(phydev: prueth->emac[i]->ndev->phydev); |
2242 | phy_disconnect(phydev: prueth->emac[i]->ndev->phydev); |
2243 | prueth->emac[i]->ndev->phydev = NULL; |
2244 | unregister_netdev(dev: prueth->registered_netdevs[i]); |
2245 | } |
2246 | |
2247 | for (i = 0; i < PRUETH_NUM_MACS; i++) { |
2248 | eth_node = prueth->eth_node[i]; |
2249 | if (!eth_node) |
2250 | continue; |
2251 | |
2252 | prueth_netdev_exit(prueth, eth_node); |
2253 | } |
2254 | |
2255 | if (prueth->pdata.quirk_10m_link_issue) |
2256 | icss_iep_exit_fw(iep: prueth->iep1); |
2257 | |
2258 | icss_iep_put(iep: prueth->iep1); |
2259 | icss_iep_put(iep: prueth->iep0); |
2260 | |
2261 | gen_pool_free(pool: prueth->sram_pool, |
2262 | addr: (unsigned long)prueth->msmcram.va, |
2263 | MSMC_RAM_SIZE); |
2264 | |
2265 | pruss_release_mem_region(pruss: prueth->pruss, region: &prueth->shram); |
2266 | |
2267 | pruss_put(pruss: prueth->pruss); |
2268 | |
2269 | if (prueth->eth_node[PRUETH_MAC1]) |
2270 | prueth_put_cores(prueth, ICSS_SLICE1); |
2271 | |
2272 | if (prueth->eth_node[PRUETH_MAC0]) |
2273 | prueth_put_cores(prueth, ICSS_SLICE0); |
2274 | } |
2275 | |
2276 | #ifdef CONFIG_PM_SLEEP |
2277 | static int prueth_suspend(struct device *dev) |
2278 | { |
2279 | struct prueth *prueth = dev_get_drvdata(dev); |
2280 | struct net_device *ndev; |
2281 | int i, ret; |
2282 | |
2283 | for (i = 0; i < PRUETH_NUM_MACS; i++) { |
2284 | ndev = prueth->registered_netdevs[i]; |
2285 | |
2286 | if (!ndev) |
2287 | continue; |
2288 | |
2289 | if (netif_running(dev: ndev)) { |
2290 | netif_device_detach(dev: ndev); |
2291 | ret = emac_ndo_stop(ndev); |
2292 | if (ret < 0) { |
2293 | netdev_err(dev: ndev, format: "failed to stop: %d" , ret); |
2294 | return ret; |
2295 | } |
2296 | } |
2297 | } |
2298 | |
2299 | return 0; |
2300 | } |
2301 | |
2302 | static int prueth_resume(struct device *dev) |
2303 | { |
2304 | struct prueth *prueth = dev_get_drvdata(dev); |
2305 | struct net_device *ndev; |
2306 | int i, ret; |
2307 | |
2308 | for (i = 0; i < PRUETH_NUM_MACS; i++) { |
2309 | ndev = prueth->registered_netdevs[i]; |
2310 | |
2311 | if (!ndev) |
2312 | continue; |
2313 | |
2314 | if (netif_running(dev: ndev)) { |
2315 | ret = emac_ndo_open(ndev); |
2316 | if (ret < 0) { |
2317 | netdev_err(dev: ndev, format: "failed to start: %d" , ret); |
2318 | return ret; |
2319 | } |
2320 | netif_device_attach(dev: ndev); |
2321 | } |
2322 | } |
2323 | |
2324 | return 0; |
2325 | } |
2326 | #endif /* CONFIG_PM_SLEEP */ |
2327 | |
2328 | static const struct dev_pm_ops prueth_dev_pm_ops = { |
2329 | SET_SYSTEM_SLEEP_PM_OPS(prueth_suspend, prueth_resume) |
2330 | }; |
2331 | |
2332 | static const struct prueth_pdata am654_icssg_pdata = { |
2333 | .fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE, |
2334 | .quirk_10m_link_issue = 1, |
2335 | }; |
2336 | |
2337 | static const struct prueth_pdata am64x_icssg_pdata = { |
2338 | .fdqring_mode = K3_RINGACC_RING_MODE_RING, |
2339 | }; |
2340 | |
2341 | static const struct of_device_id prueth_dt_match[] = { |
2342 | { .compatible = "ti,am654-icssg-prueth" , .data = &am654_icssg_pdata }, |
2343 | { .compatible = "ti,am642-icssg-prueth" , .data = &am64x_icssg_pdata }, |
2344 | { /* sentinel */ } |
2345 | }; |
2346 | MODULE_DEVICE_TABLE(of, prueth_dt_match); |
2347 | |
2348 | static struct platform_driver prueth_driver = { |
2349 | .probe = prueth_probe, |
2350 | .remove_new = prueth_remove, |
2351 | .driver = { |
2352 | .name = "icssg-prueth" , |
2353 | .of_match_table = prueth_dt_match, |
2354 | .pm = &prueth_dev_pm_ops, |
2355 | }, |
2356 | }; |
2357 | module_platform_driver(prueth_driver); |
2358 | |
2359 | MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>" ); |
2360 | MODULE_AUTHOR("Md Danish Anwar <danishanwar@ti.com>" ); |
2361 | MODULE_DESCRIPTION("PRUSS ICSSG Ethernet Driver" ); |
2362 | MODULE_LICENSE("GPL" ); |
2363 | |