1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Texas Instruments Ethernet Switch Driver |
4 | * |
5 | * Copyright (C) 2019 Texas Instruments |
6 | */ |
7 | |
8 | #include <linux/io.h> |
9 | #include <linux/clk.h> |
10 | #include <linux/platform_device.h> |
11 | #include <linux/timer.h> |
12 | #include <linux/module.h> |
13 | #include <linux/irqreturn.h> |
14 | #include <linux/interrupt.h> |
15 | #include <linux/if_ether.h> |
16 | #include <linux/etherdevice.h> |
17 | #include <linux/net_tstamp.h> |
18 | #include <linux/phy.h> |
19 | #include <linux/phy/phy.h> |
20 | #include <linux/delay.h> |
21 | #include <linux/pinctrl/consumer.h> |
22 | #include <linux/pm_runtime.h> |
23 | #include <linux/gpio/consumer.h> |
24 | #include <linux/of.h> |
25 | #include <linux/of_mdio.h> |
26 | #include <linux/of_net.h> |
27 | #include <linux/of_platform.h> |
28 | #include <linux/if_vlan.h> |
29 | #include <linux/kmemleak.h> |
30 | #include <linux/sys_soc.h> |
31 | |
32 | #include <net/switchdev.h> |
33 | #include <net/page_pool/helpers.h> |
34 | #include <net/pkt_cls.h> |
35 | #include <net/devlink.h> |
36 | |
37 | #include "cpsw.h" |
38 | #include "cpsw_ale.h" |
39 | #include "cpsw_priv.h" |
40 | #include "cpsw_sl.h" |
41 | #include "cpsw_switchdev.h" |
42 | #include "cpts.h" |
43 | #include "davinci_cpdma.h" |
44 | |
45 | #include <net/pkt_sched.h> |
46 | |
47 | static int debug_level; |
48 | static int ale_ageout = CPSW_ALE_AGEOUT_DEFAULT; |
49 | static int rx_packet_max = CPSW_MAX_PACKET_SIZE; |
50 | static int descs_pool_size = CPSW_CPDMA_DESCS_POOL_SIZE_DEFAULT; |
51 | |
52 | struct cpsw_devlink { |
53 | struct cpsw_common *cpsw; |
54 | }; |
55 | |
56 | enum cpsw_devlink_param_id { |
57 | CPSW_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, |
58 | CPSW_DL_PARAM_SWITCH_MODE, |
59 | CPSW_DL_PARAM_ALE_BYPASS, |
60 | }; |
61 | |
62 | /* struct cpsw_common is not needed, kept here for compatibility |
63 | * reasons witrh the old driver |
64 | */ |
65 | static int cpsw_slave_index_priv(struct cpsw_common *cpsw, |
66 | struct cpsw_priv *priv) |
67 | { |
68 | if (priv->emac_port == HOST_PORT_NUM) |
69 | return -1; |
70 | |
71 | return priv->emac_port - 1; |
72 | } |
73 | |
74 | static bool cpsw_is_switch_en(struct cpsw_common *cpsw) |
75 | { |
76 | return !cpsw->data.dual_emac; |
77 | } |
78 | |
79 | static void cpsw_set_promiscious(struct net_device *ndev, bool enable) |
80 | { |
81 | struct cpsw_common *cpsw = ndev_to_cpsw(ndev); |
82 | bool enable_uni = false; |
83 | int i; |
84 | |
85 | if (cpsw_is_switch_en(cpsw)) |
86 | return; |
87 | |
88 | /* Enabling promiscuous mode for one interface will be |
89 | * common for both the interface as the interface shares |
90 | * the same hardware resource. |
91 | */ |
92 | for (i = 0; i < cpsw->data.slaves; i++) |
93 | if (cpsw->slaves[i].ndev && |
94 | (cpsw->slaves[i].ndev->flags & IFF_PROMISC)) |
95 | enable_uni = true; |
96 | |
97 | if (!enable && enable_uni) { |
98 | enable = enable_uni; |
99 | dev_dbg(cpsw->dev, "promiscuity not disabled as the other interface is still in promiscuity mode\n" ); |
100 | } |
101 | |
102 | if (enable) { |
103 | /* Enable unknown unicast, reg/unreg mcast */ |
104 | cpsw_ale_control_set(ale: cpsw->ale, HOST_PORT_NUM, |
105 | control: ALE_P0_UNI_FLOOD, value: 1); |
106 | |
107 | dev_dbg(cpsw->dev, "promiscuity enabled\n" ); |
108 | } else { |
109 | /* Disable unknown unicast */ |
110 | cpsw_ale_control_set(ale: cpsw->ale, HOST_PORT_NUM, |
111 | control: ALE_P0_UNI_FLOOD, value: 0); |
112 | dev_dbg(cpsw->dev, "promiscuity disabled\n" ); |
113 | } |
114 | } |
115 | |
116 | /** |
117 | * cpsw_set_mc - adds multicast entry to the table if it's not added or deletes |
118 | * if it's not deleted |
119 | * @ndev: device to sync |
120 | * @addr: address to be added or deleted |
121 | * @vid: vlan id, if vid < 0 set/unset address for real device |
122 | * @add: add address if the flag is set or remove otherwise |
123 | */ |
124 | static int cpsw_set_mc(struct net_device *ndev, const u8 *addr, |
125 | int vid, int add) |
126 | { |
127 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
128 | struct cpsw_common *cpsw = priv->cpsw; |
129 | int mask, flags, ret, slave_no; |
130 | |
131 | slave_no = cpsw_slave_index(cpsw, priv); |
132 | if (vid < 0) |
133 | vid = cpsw->slaves[slave_no].port_vlan; |
134 | |
135 | mask = ALE_PORT_HOST; |
136 | flags = vid ? ALE_VLAN : 0; |
137 | |
138 | if (add) |
139 | ret = cpsw_ale_add_mcast(ale: cpsw->ale, addr, port_mask: mask, flags, vid, mcast_state: 0); |
140 | else |
141 | ret = cpsw_ale_del_mcast(ale: cpsw->ale, addr, port_mask: 0, flags, vid); |
142 | |
143 | return ret; |
144 | } |
145 | |
146 | static int cpsw_update_vlan_mc(struct net_device *vdev, int vid, void *ctx) |
147 | { |
148 | struct addr_sync_ctx *sync_ctx = ctx; |
149 | struct netdev_hw_addr *ha; |
150 | int found = 0, ret = 0; |
151 | |
152 | if (!vdev || !(vdev->flags & IFF_UP)) |
153 | return 0; |
154 | |
155 | /* vlan address is relevant if its sync_cnt != 0 */ |
156 | netdev_for_each_mc_addr(ha, vdev) { |
157 | if (ether_addr_equal(addr1: ha->addr, addr2: sync_ctx->addr)) { |
158 | found = ha->sync_cnt; |
159 | break; |
160 | } |
161 | } |
162 | |
163 | if (found) |
164 | sync_ctx->consumed++; |
165 | |
166 | if (sync_ctx->flush) { |
167 | if (!found) |
168 | cpsw_set_mc(ndev: sync_ctx->ndev, addr: sync_ctx->addr, vid, add: 0); |
169 | return 0; |
170 | } |
171 | |
172 | if (found) |
173 | ret = cpsw_set_mc(ndev: sync_ctx->ndev, addr: sync_ctx->addr, vid, add: 1); |
174 | |
175 | return ret; |
176 | } |
177 | |
178 | static int cpsw_add_mc_addr(struct net_device *ndev, const u8 *addr, int num) |
179 | { |
180 | struct addr_sync_ctx sync_ctx; |
181 | int ret; |
182 | |
183 | sync_ctx.consumed = 0; |
184 | sync_ctx.addr = addr; |
185 | sync_ctx.ndev = ndev; |
186 | sync_ctx.flush = 0; |
187 | |
188 | ret = vlan_for_each(dev: ndev, action: cpsw_update_vlan_mc, arg: &sync_ctx); |
189 | if (sync_ctx.consumed < num && !ret) |
190 | ret = cpsw_set_mc(ndev, addr, vid: -1, add: 1); |
191 | |
192 | return ret; |
193 | } |
194 | |
195 | static int cpsw_del_mc_addr(struct net_device *ndev, const u8 *addr, int num) |
196 | { |
197 | struct addr_sync_ctx sync_ctx; |
198 | |
199 | sync_ctx.consumed = 0; |
200 | sync_ctx.addr = addr; |
201 | sync_ctx.ndev = ndev; |
202 | sync_ctx.flush = 1; |
203 | |
204 | vlan_for_each(dev: ndev, action: cpsw_update_vlan_mc, arg: &sync_ctx); |
205 | if (sync_ctx.consumed == num) |
206 | cpsw_set_mc(ndev, addr, vid: -1, add: 0); |
207 | |
208 | return 0; |
209 | } |
210 | |
211 | static int cpsw_purge_vlan_mc(struct net_device *vdev, int vid, void *ctx) |
212 | { |
213 | struct addr_sync_ctx *sync_ctx = ctx; |
214 | struct netdev_hw_addr *ha; |
215 | int found = 0; |
216 | |
217 | if (!vdev || !(vdev->flags & IFF_UP)) |
218 | return 0; |
219 | |
220 | /* vlan address is relevant if its sync_cnt != 0 */ |
221 | netdev_for_each_mc_addr(ha, vdev) { |
222 | if (ether_addr_equal(addr1: ha->addr, addr2: sync_ctx->addr)) { |
223 | found = ha->sync_cnt; |
224 | break; |
225 | } |
226 | } |
227 | |
228 | if (!found) |
229 | return 0; |
230 | |
231 | sync_ctx->consumed++; |
232 | cpsw_set_mc(ndev: sync_ctx->ndev, addr: sync_ctx->addr, vid, add: 0); |
233 | return 0; |
234 | } |
235 | |
236 | static int cpsw_purge_all_mc(struct net_device *ndev, const u8 *addr, int num) |
237 | { |
238 | struct addr_sync_ctx sync_ctx; |
239 | |
240 | sync_ctx.addr = addr; |
241 | sync_ctx.ndev = ndev; |
242 | sync_ctx.consumed = 0; |
243 | |
244 | vlan_for_each(dev: ndev, action: cpsw_purge_vlan_mc, arg: &sync_ctx); |
245 | if (sync_ctx.consumed < num) |
246 | cpsw_set_mc(ndev, addr, vid: -1, add: 0); |
247 | |
248 | return 0; |
249 | } |
250 | |
251 | static void cpsw_ndo_set_rx_mode(struct net_device *ndev) |
252 | { |
253 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
254 | struct cpsw_common *cpsw = priv->cpsw; |
255 | |
256 | if (ndev->flags & IFF_PROMISC) { |
257 | /* Enable promiscuous mode */ |
258 | cpsw_set_promiscious(ndev, enable: true); |
259 | cpsw_ale_set_allmulti(ale: cpsw->ale, IFF_ALLMULTI, port: priv->emac_port); |
260 | return; |
261 | } |
262 | |
263 | /* Disable promiscuous mode */ |
264 | cpsw_set_promiscious(ndev, enable: false); |
265 | |
266 | /* Restore allmulti on vlans if necessary */ |
267 | cpsw_ale_set_allmulti(ale: cpsw->ale, |
268 | allmulti: ndev->flags & IFF_ALLMULTI, port: priv->emac_port); |
269 | |
270 | /* add/remove mcast address either for real netdev or for vlan */ |
271 | __hw_addr_ref_sync_dev(list: &ndev->mc, dev: ndev, sync: cpsw_add_mc_addr, |
272 | unsync: cpsw_del_mc_addr); |
273 | } |
274 | |
275 | static unsigned int cpsw_rxbuf_total_len(unsigned int len) |
276 | { |
277 | len += CPSW_HEADROOM_NA; |
278 | len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); |
279 | |
280 | return SKB_DATA_ALIGN(len); |
281 | } |
282 | |
283 | static void cpsw_rx_handler(void *token, int len, int status) |
284 | { |
285 | struct page *new_page, *page = token; |
286 | void *pa = page_address(page); |
287 | int headroom = CPSW_HEADROOM_NA; |
288 | struct cpsw_meta_xdp *xmeta; |
289 | struct cpsw_common *cpsw; |
290 | struct net_device *ndev; |
291 | int port, ch, pkt_size; |
292 | struct cpsw_priv *priv; |
293 | struct page_pool *pool; |
294 | struct sk_buff *skb; |
295 | struct xdp_buff xdp; |
296 | int ret = 0; |
297 | dma_addr_t dma; |
298 | |
299 | xmeta = pa + CPSW_XMETA_OFFSET; |
300 | cpsw = ndev_to_cpsw(xmeta->ndev); |
301 | ndev = xmeta->ndev; |
302 | pkt_size = cpsw->rx_packet_max; |
303 | ch = xmeta->ch; |
304 | |
305 | if (status >= 0) { |
306 | port = CPDMA_RX_SOURCE_PORT(status); |
307 | if (port) |
308 | ndev = cpsw->slaves[--port].ndev; |
309 | } |
310 | |
311 | priv = netdev_priv(dev: ndev); |
312 | pool = cpsw->page_pool[ch]; |
313 | |
314 | if (unlikely(status < 0) || unlikely(!netif_running(ndev))) { |
315 | /* In dual emac mode check for all interfaces */ |
316 | if (cpsw->usage_count && status >= 0) { |
317 | /* The packet received is for the interface which |
318 | * is already down and the other interface is up |
319 | * and running, instead of freeing which results |
320 | * in reducing of the number of rx descriptor in |
321 | * DMA engine, requeue page back to cpdma. |
322 | */ |
323 | new_page = page; |
324 | goto requeue; |
325 | } |
326 | |
327 | /* the interface is going down, pages are purged */ |
328 | page_pool_recycle_direct(pool, page); |
329 | return; |
330 | } |
331 | |
332 | new_page = page_pool_dev_alloc_pages(pool); |
333 | if (unlikely(!new_page)) { |
334 | new_page = page; |
335 | ndev->stats.rx_dropped++; |
336 | goto requeue; |
337 | } |
338 | |
339 | if (priv->xdp_prog) { |
340 | int size = len; |
341 | |
342 | xdp_init_buff(xdp: &xdp, PAGE_SIZE, rxq: &priv->xdp_rxq[ch]); |
343 | if (status & CPDMA_RX_VLAN_ENCAP) { |
344 | headroom += CPSW_RX_VLAN_ENCAP_HDR_SIZE; |
345 | size -= CPSW_RX_VLAN_ENCAP_HDR_SIZE; |
346 | } |
347 | |
348 | xdp_prepare_buff(xdp: &xdp, hard_start: pa, headroom, data_len: size, meta_valid: false); |
349 | |
350 | ret = cpsw_run_xdp(priv, ch, xdp: &xdp, page, port: priv->emac_port, len: &len); |
351 | if (ret != CPSW_XDP_PASS) |
352 | goto requeue; |
353 | |
354 | headroom = xdp.data - xdp.data_hard_start; |
355 | |
356 | /* XDP prog can modify vlan tag, so can't use encap header */ |
357 | status &= ~CPDMA_RX_VLAN_ENCAP; |
358 | } |
359 | |
360 | /* pass skb to netstack if no XDP prog or returned XDP_PASS */ |
361 | skb = build_skb(data: pa, frag_size: cpsw_rxbuf_total_len(len: pkt_size)); |
362 | if (!skb) { |
363 | ndev->stats.rx_dropped++; |
364 | page_pool_recycle_direct(pool, page); |
365 | goto requeue; |
366 | } |
367 | |
368 | skb->offload_fwd_mark = priv->offload_fwd_mark; |
369 | skb_reserve(skb, len: headroom); |
370 | skb_put(skb, len); |
371 | skb->dev = ndev; |
372 | if (status & CPDMA_RX_VLAN_ENCAP) |
373 | cpsw_rx_vlan_encap(skb); |
374 | if (priv->rx_ts_enabled) |
375 | cpts_rx_timestamp(cpts: cpsw->cpts, skb); |
376 | skb->protocol = eth_type_trans(skb, dev: ndev); |
377 | |
378 | /* mark skb for recycling */ |
379 | skb_mark_for_recycle(skb); |
380 | netif_receive_skb(skb); |
381 | |
382 | ndev->stats.rx_bytes += len; |
383 | ndev->stats.rx_packets++; |
384 | |
385 | requeue: |
386 | xmeta = page_address(new_page) + CPSW_XMETA_OFFSET; |
387 | xmeta->ndev = ndev; |
388 | xmeta->ch = ch; |
389 | |
390 | dma = page_pool_get_dma_addr(page: new_page) + CPSW_HEADROOM_NA; |
391 | ret = cpdma_chan_submit_mapped(chan: cpsw->rxv[ch].ch, token: new_page, data: dma, |
392 | len: pkt_size, directed: 0); |
393 | if (ret < 0) { |
394 | WARN_ON(ret == -ENOMEM); |
395 | page_pool_recycle_direct(pool, page: new_page); |
396 | } |
397 | } |
398 | |
399 | static int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv, |
400 | unsigned short vid) |
401 | { |
402 | struct cpsw_common *cpsw = priv->cpsw; |
403 | int unreg_mcast_mask = 0; |
404 | int mcast_mask; |
405 | u32 port_mask; |
406 | int ret; |
407 | |
408 | port_mask = (1 << priv->emac_port) | ALE_PORT_HOST; |
409 | |
410 | mcast_mask = ALE_PORT_HOST; |
411 | if (priv->ndev->flags & IFF_ALLMULTI) |
412 | unreg_mcast_mask = mcast_mask; |
413 | |
414 | ret = cpsw_ale_add_vlan(ale: cpsw->ale, vid, port: port_mask, untag: 0, reg_mcast: port_mask, |
415 | unreg_mcast: unreg_mcast_mask); |
416 | if (ret != 0) |
417 | return ret; |
418 | |
419 | ret = cpsw_ale_add_ucast(ale: cpsw->ale, addr: priv->mac_addr, |
420 | HOST_PORT_NUM, ALE_VLAN, vid); |
421 | if (ret != 0) |
422 | goto clean_vid; |
423 | |
424 | ret = cpsw_ale_add_mcast(ale: cpsw->ale, addr: priv->ndev->broadcast, |
425 | port_mask: mcast_mask, ALE_VLAN, vid, mcast_state: 0); |
426 | if (ret != 0) |
427 | goto clean_vlan_ucast; |
428 | return 0; |
429 | |
430 | clean_vlan_ucast: |
431 | cpsw_ale_del_ucast(ale: cpsw->ale, addr: priv->mac_addr, |
432 | HOST_PORT_NUM, ALE_VLAN, vid); |
433 | clean_vid: |
434 | cpsw_ale_del_vlan(ale: cpsw->ale, vid, port: 0); |
435 | return ret; |
436 | } |
437 | |
438 | static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev, |
439 | __be16 proto, u16 vid) |
440 | { |
441 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
442 | struct cpsw_common *cpsw = priv->cpsw; |
443 | int ret, i; |
444 | |
445 | if (cpsw_is_switch_en(cpsw)) { |
446 | dev_dbg(cpsw->dev, ".ndo_vlan_rx_add_vid called in switch mode\n" ); |
447 | return 0; |
448 | } |
449 | |
450 | if (vid == cpsw->data.default_vlan) |
451 | return 0; |
452 | |
453 | ret = pm_runtime_resume_and_get(dev: cpsw->dev); |
454 | if (ret < 0) |
455 | return ret; |
456 | |
457 | /* In dual EMAC, reserved VLAN id should not be used for |
458 | * creating VLAN interfaces as this can break the dual |
459 | * EMAC port separation |
460 | */ |
461 | for (i = 0; i < cpsw->data.slaves; i++) { |
462 | if (cpsw->slaves[i].ndev && |
463 | vid == cpsw->slaves[i].port_vlan) { |
464 | ret = -EINVAL; |
465 | goto err; |
466 | } |
467 | } |
468 | |
469 | dev_dbg(priv->dev, "Adding vlanid %d to vlan filter\n" , vid); |
470 | ret = cpsw_add_vlan_ale_entry(priv, vid); |
471 | err: |
472 | pm_runtime_put(dev: cpsw->dev); |
473 | return ret; |
474 | } |
475 | |
476 | static int cpsw_restore_vlans(struct net_device *vdev, int vid, void *arg) |
477 | { |
478 | struct cpsw_priv *priv = arg; |
479 | |
480 | if (!vdev || !vid) |
481 | return 0; |
482 | |
483 | cpsw_ndo_vlan_rx_add_vid(ndev: priv->ndev, proto: 0, vid); |
484 | return 0; |
485 | } |
486 | |
487 | /* restore resources after port reset */ |
488 | static void cpsw_restore(struct cpsw_priv *priv) |
489 | { |
490 | struct cpsw_common *cpsw = priv->cpsw; |
491 | |
492 | /* restore vlan configurations */ |
493 | vlan_for_each(dev: priv->ndev, action: cpsw_restore_vlans, arg: priv); |
494 | |
495 | /* restore MQPRIO offload */ |
496 | cpsw_mqprio_resume(slave: &cpsw->slaves[priv->emac_port - 1], priv); |
497 | |
498 | /* restore CBS offload */ |
499 | cpsw_cbs_resume(slave: &cpsw->slaves[priv->emac_port - 1], priv); |
500 | |
501 | cpsw_qos_clsflower_resume(priv); |
502 | } |
503 | |
504 | static void cpsw_init_stp_ale_entry(struct cpsw_common *cpsw) |
505 | { |
506 | static const char stpa[] = {0x01, 0x80, 0xc2, 0x0, 0x0, 0x0}; |
507 | |
508 | cpsw_ale_add_mcast(ale: cpsw->ale, addr: stpa, |
509 | ALE_PORT_HOST, ALE_SUPER, vid: 0, |
510 | ALE_MCAST_BLOCK_LEARN_FWD); |
511 | } |
512 | |
513 | static void cpsw_init_host_port_switch(struct cpsw_common *cpsw) |
514 | { |
515 | int vlan = cpsw->data.default_vlan; |
516 | |
517 | writel(CPSW_FIFO_NORMAL_MODE, addr: &cpsw->host_port_regs->tx_in_ctl); |
518 | |
519 | writel(val: vlan, addr: &cpsw->host_port_regs->port_vlan); |
520 | |
521 | cpsw_ale_add_vlan(ale: cpsw->ale, vid: vlan, ALE_ALL_PORTS, |
522 | ALE_ALL_PORTS, ALE_ALL_PORTS, |
523 | ALE_PORT_1 | ALE_PORT_2); |
524 | |
525 | cpsw_init_stp_ale_entry(cpsw); |
526 | |
527 | cpsw_ale_control_set(ale: cpsw->ale, HOST_PORT_NUM, control: ALE_P0_UNI_FLOOD, value: 1); |
528 | dev_dbg(cpsw->dev, "Set P0_UNI_FLOOD\n" ); |
529 | cpsw_ale_control_set(ale: cpsw->ale, HOST_PORT_NUM, control: ALE_PORT_NOLEARN, value: 0); |
530 | } |
531 | |
532 | static void cpsw_init_host_port_dual_mac(struct cpsw_common *cpsw) |
533 | { |
534 | int vlan = cpsw->data.default_vlan; |
535 | |
536 | writel(CPSW_FIFO_DUAL_MAC_MODE, addr: &cpsw->host_port_regs->tx_in_ctl); |
537 | |
538 | cpsw_ale_control_set(ale: cpsw->ale, HOST_PORT_NUM, control: ALE_P0_UNI_FLOOD, value: 0); |
539 | dev_dbg(cpsw->dev, "unset P0_UNI_FLOOD\n" ); |
540 | |
541 | writel(val: vlan, addr: &cpsw->host_port_regs->port_vlan); |
542 | |
543 | cpsw_ale_add_vlan(ale: cpsw->ale, vid: vlan, ALE_ALL_PORTS, ALE_ALL_PORTS, reg_mcast: 0, unreg_mcast: 0); |
544 | /* learning make no sense in dual_mac mode */ |
545 | cpsw_ale_control_set(ale: cpsw->ale, HOST_PORT_NUM, control: ALE_PORT_NOLEARN, value: 1); |
546 | } |
547 | |
548 | static void cpsw_init_host_port(struct cpsw_priv *priv) |
549 | { |
550 | struct cpsw_common *cpsw = priv->cpsw; |
551 | u32 control_reg; |
552 | |
553 | /* soft reset the controller and initialize ale */ |
554 | soft_reset(module: "cpsw" , reg: &cpsw->regs->soft_reset); |
555 | cpsw_ale_start(ale: cpsw->ale); |
556 | |
557 | /* switch to vlan unaware mode */ |
558 | cpsw_ale_control_set(ale: cpsw->ale, HOST_PORT_NUM, control: ALE_VLAN_AWARE, |
559 | CPSW_ALE_VLAN_AWARE); |
560 | control_reg = readl(addr: &cpsw->regs->control); |
561 | control_reg |= CPSW_VLAN_AWARE | CPSW_RX_VLAN_ENCAP; |
562 | writel(val: control_reg, addr: &cpsw->regs->control); |
563 | |
564 | /* setup host port priority mapping */ |
565 | writel_relaxed(CPDMA_TX_PRIORITY_MAP, |
566 | &cpsw->host_port_regs->cpdma_tx_pri_map); |
567 | writel_relaxed(0, &cpsw->host_port_regs->cpdma_rx_chan_map); |
568 | |
569 | /* disable priority elevation */ |
570 | writel_relaxed(0, &cpsw->regs->ptype); |
571 | |
572 | /* enable statistics collection only on all ports */ |
573 | writel_relaxed(0x7, &cpsw->regs->stat_port_en); |
574 | |
575 | /* Enable internal fifo flow control */ |
576 | writel(val: 0x7, addr: &cpsw->regs->flow_control); |
577 | |
578 | if (cpsw_is_switch_en(cpsw)) |
579 | cpsw_init_host_port_switch(cpsw); |
580 | else |
581 | cpsw_init_host_port_dual_mac(cpsw); |
582 | |
583 | cpsw_ale_control_set(ale: cpsw->ale, HOST_PORT_NUM, |
584 | control: ALE_PORT_STATE, value: ALE_PORT_STATE_FORWARD); |
585 | } |
586 | |
587 | static void cpsw_port_add_dual_emac_def_ale_entries(struct cpsw_priv *priv, |
588 | struct cpsw_slave *slave) |
589 | { |
590 | u32 port_mask = 1 << priv->emac_port | ALE_PORT_HOST; |
591 | struct cpsw_common *cpsw = priv->cpsw; |
592 | u32 reg; |
593 | |
594 | reg = (cpsw->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN : |
595 | CPSW2_PORT_VLAN; |
596 | slave_write(slave, val: slave->port_vlan, offset: reg); |
597 | |
598 | cpsw_ale_add_vlan(ale: cpsw->ale, vid: slave->port_vlan, port: port_mask, |
599 | untag: port_mask, reg_mcast: port_mask, unreg_mcast: 0); |
600 | cpsw_ale_add_mcast(ale: cpsw->ale, addr: priv->ndev->broadcast, |
601 | ALE_PORT_HOST, ALE_VLAN, vid: slave->port_vlan, |
602 | ALE_MCAST_FWD); |
603 | cpsw_ale_add_ucast(ale: cpsw->ale, addr: priv->mac_addr, |
604 | HOST_PORT_NUM, ALE_VLAN | |
605 | ALE_SECURE, vid: slave->port_vlan); |
606 | cpsw_ale_control_set(ale: cpsw->ale, port: priv->emac_port, |
607 | control: ALE_PORT_DROP_UNKNOWN_VLAN, value: 1); |
608 | /* learning make no sense in dual_mac mode */ |
609 | cpsw_ale_control_set(ale: cpsw->ale, port: priv->emac_port, |
610 | control: ALE_PORT_NOLEARN, value: 1); |
611 | } |
612 | |
613 | static void cpsw_port_add_switch_def_ale_entries(struct cpsw_priv *priv, |
614 | struct cpsw_slave *slave) |
615 | { |
616 | u32 port_mask = 1 << priv->emac_port | ALE_PORT_HOST; |
617 | struct cpsw_common *cpsw = priv->cpsw; |
618 | u32 reg; |
619 | |
620 | cpsw_ale_control_set(ale: cpsw->ale, port: priv->emac_port, |
621 | control: ALE_PORT_DROP_UNKNOWN_VLAN, value: 0); |
622 | cpsw_ale_control_set(ale: cpsw->ale, port: priv->emac_port, |
623 | control: ALE_PORT_NOLEARN, value: 0); |
624 | /* disabling SA_UPDATE required to make stp work, without this setting |
625 | * Host MAC addresses will jump between ports. |
626 | * As per TRM MAC address can be defined as unicast supervisory (super) |
627 | * by setting both (ALE_BLOCKED | ALE_SECURE) which should prevent |
628 | * SA_UPDATE, but HW seems works incorrectly and setting ALE_SECURE |
629 | * causes STP packets to be dropped due to ingress filter |
630 | * if (source address found) and (secure) and |
631 | * (receive port number != port_number)) |
632 | * then discard the packet |
633 | */ |
634 | cpsw_ale_control_set(ale: cpsw->ale, port: priv->emac_port, |
635 | control: ALE_PORT_NO_SA_UPDATE, value: 1); |
636 | |
637 | cpsw_ale_add_mcast(ale: cpsw->ale, addr: priv->ndev->broadcast, |
638 | port_mask, ALE_VLAN, vid: slave->port_vlan, |
639 | ALE_MCAST_FWD_2); |
640 | cpsw_ale_add_ucast(ale: cpsw->ale, addr: priv->mac_addr, |
641 | HOST_PORT_NUM, ALE_VLAN, vid: slave->port_vlan); |
642 | |
643 | reg = (cpsw->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN : |
644 | CPSW2_PORT_VLAN; |
645 | slave_write(slave, val: slave->port_vlan, offset: reg); |
646 | } |
647 | |
648 | static void cpsw_adjust_link(struct net_device *ndev) |
649 | { |
650 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
651 | struct cpsw_common *cpsw = priv->cpsw; |
652 | struct cpsw_slave *slave; |
653 | struct phy_device *phy; |
654 | u32 mac_control = 0; |
655 | |
656 | slave = &cpsw->slaves[priv->emac_port - 1]; |
657 | phy = slave->phy; |
658 | |
659 | if (!phy) |
660 | return; |
661 | |
662 | if (phy->link) { |
663 | mac_control = CPSW_SL_CTL_GMII_EN; |
664 | |
665 | if (phy->speed == 1000) |
666 | mac_control |= CPSW_SL_CTL_GIG; |
667 | if (phy->duplex) |
668 | mac_control |= CPSW_SL_CTL_FULLDUPLEX; |
669 | |
670 | /* set speed_in input in case RMII mode is used in 100Mbps */ |
671 | if (phy->speed == 100) |
672 | mac_control |= CPSW_SL_CTL_IFCTL_A; |
673 | /* in band mode only works in 10Mbps RGMII mode */ |
674 | else if ((phy->speed == 10) && phy_interface_is_rgmii(phydev: phy)) |
675 | mac_control |= CPSW_SL_CTL_EXT_EN; /* In Band mode */ |
676 | |
677 | if (priv->rx_pause) |
678 | mac_control |= CPSW_SL_CTL_RX_FLOW_EN; |
679 | |
680 | if (priv->tx_pause) |
681 | mac_control |= CPSW_SL_CTL_TX_FLOW_EN; |
682 | |
683 | if (mac_control != slave->mac_control) |
684 | cpsw_sl_ctl_set(sl: slave->mac_sl, ctl_funcs: mac_control); |
685 | |
686 | /* enable forwarding */ |
687 | cpsw_ale_control_set(ale: cpsw->ale, port: priv->emac_port, |
688 | control: ALE_PORT_STATE, value: ALE_PORT_STATE_FORWARD); |
689 | |
690 | netif_tx_wake_all_queues(dev: ndev); |
691 | |
692 | if (priv->shp_cfg_speed && |
693 | priv->shp_cfg_speed != slave->phy->speed && |
694 | !cpsw_shp_is_off(priv)) |
695 | dev_warn(priv->dev, "Speed was changed, CBS shaper speeds are changed!" ); |
696 | } else { |
697 | netif_tx_stop_all_queues(dev: ndev); |
698 | |
699 | mac_control = 0; |
700 | /* disable forwarding */ |
701 | cpsw_ale_control_set(ale: cpsw->ale, port: priv->emac_port, |
702 | control: ALE_PORT_STATE, value: ALE_PORT_STATE_DISABLE); |
703 | |
704 | cpsw_sl_wait_for_idle(sl: slave->mac_sl, tmo: 100); |
705 | |
706 | cpsw_sl_ctl_reset(sl: slave->mac_sl); |
707 | } |
708 | |
709 | if (mac_control != slave->mac_control) |
710 | phy_print_status(phydev: phy); |
711 | |
712 | slave->mac_control = mac_control; |
713 | |
714 | if (phy->link && cpsw_need_resplit(cpsw)) |
715 | cpsw_split_res(cpsw); |
716 | } |
717 | |
718 | static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) |
719 | { |
720 | struct cpsw_common *cpsw = priv->cpsw; |
721 | struct phy_device *phy; |
722 | |
723 | cpsw_sl_reset(sl: slave->mac_sl, tmo: 100); |
724 | cpsw_sl_ctl_reset(sl: slave->mac_sl); |
725 | |
726 | /* setup priority mapping */ |
727 | cpsw_sl_reg_write(sl: slave->mac_sl, reg: CPSW_SL_RX_PRI_MAP, |
728 | RX_PRIORITY_MAPPING); |
729 | |
730 | switch (cpsw->version) { |
731 | case CPSW_VERSION_1: |
732 | slave_write(slave, TX_PRIORITY_MAPPING, CPSW1_TX_PRI_MAP); |
733 | /* Increase RX FIFO size to 5 for supporting fullduplex |
734 | * flow control mode |
735 | */ |
736 | slave_write(slave, |
737 | val: (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) | |
738 | CPSW_MAX_BLKS_RX, CPSW1_MAX_BLKS); |
739 | break; |
740 | case CPSW_VERSION_2: |
741 | case CPSW_VERSION_3: |
742 | case CPSW_VERSION_4: |
743 | slave_write(slave, TX_PRIORITY_MAPPING, CPSW2_TX_PRI_MAP); |
744 | /* Increase RX FIFO size to 5 for supporting fullduplex |
745 | * flow control mode |
746 | */ |
747 | slave_write(slave, |
748 | val: (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) | |
749 | CPSW_MAX_BLKS_RX, CPSW2_MAX_BLKS); |
750 | break; |
751 | } |
752 | |
753 | /* setup max packet size, and mac address */ |
754 | cpsw_sl_reg_write(sl: slave->mac_sl, reg: CPSW_SL_RX_MAXLEN, |
755 | val: cpsw->rx_packet_max); |
756 | cpsw_set_slave_mac(slave, priv); |
757 | |
758 | slave->mac_control = 0; /* no link yet */ |
759 | |
760 | if (cpsw_is_switch_en(cpsw)) |
761 | cpsw_port_add_switch_def_ale_entries(priv, slave); |
762 | else |
763 | cpsw_port_add_dual_emac_def_ale_entries(priv, slave); |
764 | |
765 | if (!slave->data->phy_node) |
766 | dev_err(priv->dev, "no phy found on slave %d\n" , |
767 | slave->slave_num); |
768 | phy = of_phy_connect(dev: priv->ndev, phy_np: slave->data->phy_node, |
769 | hndlr: &cpsw_adjust_link, flags: 0, iface: slave->data->phy_if); |
770 | if (!phy) { |
771 | dev_err(priv->dev, "phy \"%pOF\" not found on slave %d\n" , |
772 | slave->data->phy_node, |
773 | slave->slave_num); |
774 | return; |
775 | } |
776 | |
777 | phy->mac_managed_pm = true; |
778 | |
779 | slave->phy = phy; |
780 | |
781 | phy_attached_info(phydev: slave->phy); |
782 | |
783 | phy_start(phydev: slave->phy); |
784 | |
785 | /* Configure GMII_SEL register */ |
786 | phy_set_mode_ext(phy: slave->data->ifphy, mode: PHY_MODE_ETHERNET, |
787 | submode: slave->data->phy_if); |
788 | } |
789 | |
790 | static int cpsw_ndo_stop(struct net_device *ndev) |
791 | { |
792 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
793 | struct cpsw_common *cpsw = priv->cpsw; |
794 | struct cpsw_slave *slave; |
795 | |
796 | cpsw_info(priv, ifdown, "shutting down ndev\n" ); |
797 | slave = &cpsw->slaves[priv->emac_port - 1]; |
798 | if (slave->phy) |
799 | phy_stop(phydev: slave->phy); |
800 | |
801 | netif_tx_stop_all_queues(dev: priv->ndev); |
802 | |
803 | if (slave->phy) { |
804 | phy_disconnect(phydev: slave->phy); |
805 | slave->phy = NULL; |
806 | } |
807 | |
808 | __hw_addr_ref_unsync_dev(list: &ndev->mc, dev: ndev, unsync: cpsw_purge_all_mc); |
809 | |
810 | if (cpsw->usage_count <= 1) { |
811 | napi_disable(n: &cpsw->napi_rx); |
812 | napi_disable(n: &cpsw->napi_tx); |
813 | cpts_unregister(cpts: cpsw->cpts); |
814 | cpsw_intr_disable(cpsw); |
815 | cpdma_ctlr_stop(ctlr: cpsw->dma); |
816 | cpsw_ale_stop(ale: cpsw->ale); |
817 | cpsw_destroy_xdp_rxqs(cpsw); |
818 | } |
819 | |
820 | if (cpsw_need_resplit(cpsw)) |
821 | cpsw_split_res(cpsw); |
822 | |
823 | cpsw->usage_count--; |
824 | pm_runtime_put_sync(dev: cpsw->dev); |
825 | return 0; |
826 | } |
827 | |
828 | static int cpsw_ndo_open(struct net_device *ndev) |
829 | { |
830 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
831 | struct cpsw_common *cpsw = priv->cpsw; |
832 | int ret; |
833 | |
834 | dev_info(priv->dev, "starting ndev. mode: %s\n" , |
835 | cpsw_is_switch_en(cpsw) ? "switch" : "dual_mac" ); |
836 | ret = pm_runtime_resume_and_get(dev: cpsw->dev); |
837 | if (ret < 0) |
838 | return ret; |
839 | |
840 | /* Notify the stack of the actual queue counts. */ |
841 | ret = netif_set_real_num_tx_queues(dev: ndev, txq: cpsw->tx_ch_num); |
842 | if (ret) { |
843 | dev_err(priv->dev, "cannot set real number of tx queues\n" ); |
844 | goto pm_cleanup; |
845 | } |
846 | |
847 | ret = netif_set_real_num_rx_queues(dev: ndev, rxq: cpsw->rx_ch_num); |
848 | if (ret) { |
849 | dev_err(priv->dev, "cannot set real number of rx queues\n" ); |
850 | goto pm_cleanup; |
851 | } |
852 | |
853 | /* Initialize host and slave ports */ |
854 | if (!cpsw->usage_count) |
855 | cpsw_init_host_port(priv); |
856 | cpsw_slave_open(slave: &cpsw->slaves[priv->emac_port - 1], priv); |
857 | |
858 | /* initialize shared resources for every ndev */ |
859 | if (!cpsw->usage_count) { |
860 | /* create rxqs for both infs in dual mac as they use same pool |
861 | * and must be destroyed together when no users. |
862 | */ |
863 | ret = cpsw_create_xdp_rxqs(cpsw); |
864 | if (ret < 0) |
865 | goto err_cleanup; |
866 | |
867 | ret = cpsw_fill_rx_channels(priv); |
868 | if (ret < 0) |
869 | goto err_cleanup; |
870 | |
871 | if (cpsw->cpts) { |
872 | if (cpts_register(cpts: cpsw->cpts)) |
873 | dev_err(priv->dev, "error registering cpts device\n" ); |
874 | else |
875 | writel(val: 0x10, addr: &cpsw->wr_regs->misc_en); |
876 | } |
877 | |
878 | napi_enable(n: &cpsw->napi_rx); |
879 | napi_enable(n: &cpsw->napi_tx); |
880 | |
881 | if (cpsw->tx_irq_disabled) { |
882 | cpsw->tx_irq_disabled = false; |
883 | enable_irq(irq: cpsw->irqs_table[1]); |
884 | } |
885 | |
886 | if (cpsw->rx_irq_disabled) { |
887 | cpsw->rx_irq_disabled = false; |
888 | enable_irq(irq: cpsw->irqs_table[0]); |
889 | } |
890 | } |
891 | |
892 | cpsw_restore(priv); |
893 | |
894 | /* Enable Interrupt pacing if configured */ |
895 | if (cpsw->coal_intvl != 0) { |
896 | struct ethtool_coalesce coal; |
897 | |
898 | coal.rx_coalesce_usecs = cpsw->coal_intvl; |
899 | cpsw_set_coalesce(ndev, coal: &coal, NULL, NULL); |
900 | } |
901 | |
902 | cpdma_ctlr_start(ctlr: cpsw->dma); |
903 | cpsw_intr_enable(cpsw); |
904 | cpsw->usage_count++; |
905 | |
906 | return 0; |
907 | |
908 | err_cleanup: |
909 | cpsw_ndo_stop(ndev); |
910 | |
911 | pm_cleanup: |
912 | pm_runtime_put_sync(dev: cpsw->dev); |
913 | return ret; |
914 | } |
915 | |
916 | static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb, |
917 | struct net_device *ndev) |
918 | { |
919 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
920 | struct cpsw_common *cpsw = priv->cpsw; |
921 | struct cpts *cpts = cpsw->cpts; |
922 | struct netdev_queue *txq; |
923 | struct cpdma_chan *txch; |
924 | int ret, q_idx; |
925 | |
926 | if (skb_put_padto(skb, READ_ONCE(priv->tx_packet_min))) { |
927 | cpsw_err(priv, tx_err, "packet pad failed\n" ); |
928 | ndev->stats.tx_dropped++; |
929 | return NET_XMIT_DROP; |
930 | } |
931 | |
932 | if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && |
933 | priv->tx_ts_enabled && cpts_can_timestamp(cpts, skb)) |
934 | skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; |
935 | |
936 | q_idx = skb_get_queue_mapping(skb); |
937 | if (q_idx >= cpsw->tx_ch_num) |
938 | q_idx = q_idx % cpsw->tx_ch_num; |
939 | |
940 | txch = cpsw->txv[q_idx].ch; |
941 | txq = netdev_get_tx_queue(dev: ndev, index: q_idx); |
942 | skb_tx_timestamp(skb); |
943 | ret = cpdma_chan_submit(chan: txch, token: skb, data: skb->data, len: skb->len, |
944 | directed: priv->emac_port); |
945 | if (unlikely(ret != 0)) { |
946 | cpsw_err(priv, tx_err, "desc submit failed\n" ); |
947 | goto fail; |
948 | } |
949 | |
950 | /* If there is no more tx desc left free then we need to |
951 | * tell the kernel to stop sending us tx frames. |
952 | */ |
953 | if (unlikely(!cpdma_check_free_tx_desc(txch))) { |
954 | netif_tx_stop_queue(dev_queue: txq); |
955 | |
956 | /* Barrier, so that stop_queue visible to other cpus */ |
957 | smp_mb__after_atomic(); |
958 | |
959 | if (cpdma_check_free_tx_desc(chan: txch)) |
960 | netif_tx_wake_queue(dev_queue: txq); |
961 | } |
962 | |
963 | return NETDEV_TX_OK; |
964 | fail: |
965 | ndev->stats.tx_dropped++; |
966 | netif_tx_stop_queue(dev_queue: txq); |
967 | |
968 | /* Barrier, so that stop_queue visible to other cpus */ |
969 | smp_mb__after_atomic(); |
970 | |
971 | if (cpdma_check_free_tx_desc(chan: txch)) |
972 | netif_tx_wake_queue(dev_queue: txq); |
973 | |
974 | return NETDEV_TX_BUSY; |
975 | } |
976 | |
977 | static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) |
978 | { |
979 | struct sockaddr *addr = (struct sockaddr *)p; |
980 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
981 | struct cpsw_common *cpsw = priv->cpsw; |
982 | int ret, slave_no; |
983 | int flags = 0; |
984 | u16 vid = 0; |
985 | |
986 | slave_no = cpsw_slave_index(cpsw, priv); |
987 | if (!is_valid_ether_addr(addr: addr->sa_data)) |
988 | return -EADDRNOTAVAIL; |
989 | |
990 | ret = pm_runtime_resume_and_get(dev: cpsw->dev); |
991 | if (ret < 0) |
992 | return ret; |
993 | |
994 | vid = cpsw->slaves[slave_no].port_vlan; |
995 | flags = ALE_VLAN | ALE_SECURE; |
996 | |
997 | cpsw_ale_del_ucast(ale: cpsw->ale, addr: priv->mac_addr, HOST_PORT_NUM, |
998 | flags, vid); |
999 | cpsw_ale_add_ucast(ale: cpsw->ale, addr: addr->sa_data, HOST_PORT_NUM, |
1000 | flags, vid); |
1001 | |
1002 | ether_addr_copy(dst: priv->mac_addr, src: addr->sa_data); |
1003 | eth_hw_addr_set(dev: ndev, addr: priv->mac_addr); |
1004 | cpsw_set_slave_mac(slave: &cpsw->slaves[slave_no], priv); |
1005 | |
1006 | pm_runtime_put(dev: cpsw->dev); |
1007 | |
1008 | return 0; |
1009 | } |
1010 | |
1011 | static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, |
1012 | __be16 proto, u16 vid) |
1013 | { |
1014 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
1015 | struct cpsw_common *cpsw = priv->cpsw; |
1016 | int ret; |
1017 | int i; |
1018 | |
1019 | if (cpsw_is_switch_en(cpsw)) { |
1020 | dev_dbg(cpsw->dev, "ndo del vlan is called in switch mode\n" ); |
1021 | return 0; |
1022 | } |
1023 | |
1024 | if (vid == cpsw->data.default_vlan) |
1025 | return 0; |
1026 | |
1027 | ret = pm_runtime_resume_and_get(dev: cpsw->dev); |
1028 | if (ret < 0) |
1029 | return ret; |
1030 | |
1031 | /* reset the return code as pm_runtime_get_sync() can return |
1032 | * non zero values as well. |
1033 | */ |
1034 | ret = 0; |
1035 | for (i = 0; i < cpsw->data.slaves; i++) { |
1036 | if (cpsw->slaves[i].ndev && |
1037 | vid == cpsw->slaves[i].port_vlan) { |
1038 | ret = -EINVAL; |
1039 | goto err; |
1040 | } |
1041 | } |
1042 | |
1043 | dev_dbg(priv->dev, "removing vlanid %d from vlan filter\n" , vid); |
1044 | ret = cpsw_ale_del_vlan(ale: cpsw->ale, vid, port: 0); |
1045 | if (ret) |
1046 | dev_err(priv->dev, "cpsw_ale_del_vlan() failed: ret %d\n" , ret); |
1047 | ret = cpsw_ale_del_ucast(ale: cpsw->ale, addr: priv->mac_addr, |
1048 | HOST_PORT_NUM, ALE_VLAN, vid); |
1049 | if (ret) |
1050 | dev_err(priv->dev, "cpsw_ale_del_ucast() failed: ret %d\n" , |
1051 | ret); |
1052 | ret = cpsw_ale_del_mcast(ale: cpsw->ale, addr: priv->ndev->broadcast, |
1053 | port_mask: 0, ALE_VLAN, vid); |
1054 | if (ret) |
1055 | dev_err(priv->dev, "cpsw_ale_del_mcast failed. ret %d\n" , |
1056 | ret); |
1057 | cpsw_ale_flush_multicast(ale: cpsw->ale, ALE_PORT_HOST, vid); |
1058 | ret = 0; |
1059 | err: |
1060 | pm_runtime_put(dev: cpsw->dev); |
1061 | return ret; |
1062 | } |
1063 | |
1064 | static int cpsw_ndo_get_phys_port_name(struct net_device *ndev, char *name, |
1065 | size_t len) |
1066 | { |
1067 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
1068 | int err; |
1069 | |
1070 | err = snprintf(buf: name, size: len, fmt: "p%d" , priv->emac_port); |
1071 | |
1072 | if (err >= len) |
1073 | return -EINVAL; |
1074 | |
1075 | return 0; |
1076 | } |
1077 | |
1078 | #ifdef CONFIG_NET_POLL_CONTROLLER |
1079 | static void cpsw_ndo_poll_controller(struct net_device *ndev) |
1080 | { |
1081 | struct cpsw_common *cpsw = ndev_to_cpsw(ndev); |
1082 | |
1083 | cpsw_intr_disable(cpsw); |
1084 | cpsw_rx_interrupt(irq: cpsw->irqs_table[0], dev_id: cpsw); |
1085 | cpsw_tx_interrupt(irq: cpsw->irqs_table[1], dev_id: cpsw); |
1086 | cpsw_intr_enable(cpsw); |
1087 | } |
1088 | #endif |
1089 | |
1090 | static int cpsw_ndo_xdp_xmit(struct net_device *ndev, int n, |
1091 | struct xdp_frame **frames, u32 flags) |
1092 | { |
1093 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
1094 | struct xdp_frame *xdpf; |
1095 | int i, nxmit = 0; |
1096 | |
1097 | if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) |
1098 | return -EINVAL; |
1099 | |
1100 | for (i = 0; i < n; i++) { |
1101 | xdpf = frames[i]; |
1102 | if (xdpf->len < READ_ONCE(priv->tx_packet_min)) |
1103 | break; |
1104 | |
1105 | if (cpsw_xdp_tx_frame(priv, xdpf, NULL, port: priv->emac_port)) |
1106 | break; |
1107 | nxmit++; |
1108 | } |
1109 | |
1110 | return nxmit; |
1111 | } |
1112 | |
1113 | static int cpsw_get_port_parent_id(struct net_device *ndev, |
1114 | struct netdev_phys_item_id *ppid) |
1115 | { |
1116 | struct cpsw_common *cpsw = ndev_to_cpsw(ndev); |
1117 | |
1118 | ppid->id_len = sizeof(cpsw->base_mac); |
1119 | memcpy(&ppid->id, &cpsw->base_mac, ppid->id_len); |
1120 | |
1121 | return 0; |
1122 | } |
1123 | |
1124 | static const struct net_device_ops cpsw_netdev_ops = { |
1125 | .ndo_open = cpsw_ndo_open, |
1126 | .ndo_stop = cpsw_ndo_stop, |
1127 | .ndo_start_xmit = cpsw_ndo_start_xmit, |
1128 | .ndo_set_mac_address = cpsw_ndo_set_mac_address, |
1129 | .ndo_eth_ioctl = cpsw_ndo_ioctl, |
1130 | .ndo_validate_addr = eth_validate_addr, |
1131 | .ndo_tx_timeout = cpsw_ndo_tx_timeout, |
1132 | .ndo_set_rx_mode = cpsw_ndo_set_rx_mode, |
1133 | .ndo_set_tx_maxrate = cpsw_ndo_set_tx_maxrate, |
1134 | #ifdef CONFIG_NET_POLL_CONTROLLER |
1135 | .ndo_poll_controller = cpsw_ndo_poll_controller, |
1136 | #endif |
1137 | .ndo_vlan_rx_add_vid = cpsw_ndo_vlan_rx_add_vid, |
1138 | .ndo_vlan_rx_kill_vid = cpsw_ndo_vlan_rx_kill_vid, |
1139 | .ndo_setup_tc = cpsw_ndo_setup_tc, |
1140 | .ndo_get_phys_port_name = cpsw_ndo_get_phys_port_name, |
1141 | .ndo_bpf = cpsw_ndo_bpf, |
1142 | .ndo_xdp_xmit = cpsw_ndo_xdp_xmit, |
1143 | .ndo_get_port_parent_id = cpsw_get_port_parent_id, |
1144 | }; |
1145 | |
1146 | static void cpsw_get_drvinfo(struct net_device *ndev, |
1147 | struct ethtool_drvinfo *info) |
1148 | { |
1149 | struct cpsw_common *cpsw = ndev_to_cpsw(ndev); |
1150 | struct platform_device *pdev; |
1151 | |
1152 | pdev = to_platform_device(cpsw->dev); |
1153 | strscpy(info->driver, "cpsw-switch" , sizeof(info->driver)); |
1154 | strscpy(info->version, "2.0" , sizeof(info->version)); |
1155 | strscpy(info->bus_info, pdev->name, sizeof(info->bus_info)); |
1156 | } |
1157 | |
1158 | static int cpsw_set_pauseparam(struct net_device *ndev, |
1159 | struct ethtool_pauseparam *pause) |
1160 | { |
1161 | struct cpsw_common *cpsw = ndev_to_cpsw(ndev); |
1162 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
1163 | int slave_no; |
1164 | |
1165 | slave_no = cpsw_slave_index(cpsw, priv); |
1166 | if (!cpsw->slaves[slave_no].phy) |
1167 | return -EINVAL; |
1168 | |
1169 | if (!phy_validate_pause(phydev: cpsw->slaves[slave_no].phy, pp: pause)) |
1170 | return -EINVAL; |
1171 | |
1172 | priv->rx_pause = pause->rx_pause ? true : false; |
1173 | priv->tx_pause = pause->tx_pause ? true : false; |
1174 | |
1175 | phy_set_asym_pause(phydev: cpsw->slaves[slave_no].phy, |
1176 | rx: priv->rx_pause, tx: priv->tx_pause); |
1177 | |
1178 | return 0; |
1179 | } |
1180 | |
1181 | static int cpsw_set_channels(struct net_device *ndev, |
1182 | struct ethtool_channels *chs) |
1183 | { |
1184 | return cpsw_set_channels_common(ndev, chs, rx_handler: cpsw_rx_handler); |
1185 | } |
1186 | |
1187 | static const struct ethtool_ops cpsw_ethtool_ops = { |
1188 | .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS, |
1189 | .get_drvinfo = cpsw_get_drvinfo, |
1190 | .get_msglevel = cpsw_get_msglevel, |
1191 | .set_msglevel = cpsw_set_msglevel, |
1192 | .get_link = ethtool_op_get_link, |
1193 | .get_ts_info = cpsw_get_ts_info, |
1194 | .get_coalesce = cpsw_get_coalesce, |
1195 | .set_coalesce = cpsw_set_coalesce, |
1196 | .get_sset_count = cpsw_get_sset_count, |
1197 | .get_strings = cpsw_get_strings, |
1198 | .get_ethtool_stats = cpsw_get_ethtool_stats, |
1199 | .get_pauseparam = cpsw_get_pauseparam, |
1200 | .set_pauseparam = cpsw_set_pauseparam, |
1201 | .get_wol = cpsw_get_wol, |
1202 | .set_wol = cpsw_set_wol, |
1203 | .get_regs_len = cpsw_get_regs_len, |
1204 | .get_regs = cpsw_get_regs, |
1205 | .begin = cpsw_ethtool_op_begin, |
1206 | .complete = cpsw_ethtool_op_complete, |
1207 | .get_channels = cpsw_get_channels, |
1208 | .set_channels = cpsw_set_channels, |
1209 | .get_link_ksettings = cpsw_get_link_ksettings, |
1210 | .set_link_ksettings = cpsw_set_link_ksettings, |
1211 | .get_eee = cpsw_get_eee, |
1212 | .set_eee = cpsw_set_eee, |
1213 | .nway_reset = cpsw_nway_reset, |
1214 | .get_ringparam = cpsw_get_ringparam, |
1215 | .set_ringparam = cpsw_set_ringparam, |
1216 | }; |
1217 | |
1218 | static int cpsw_probe_dt(struct cpsw_common *cpsw) |
1219 | { |
1220 | struct device_node *node = cpsw->dev->of_node, *tmp_node, *port_np; |
1221 | struct cpsw_platform_data *data = &cpsw->data; |
1222 | struct device *dev = cpsw->dev; |
1223 | int ret; |
1224 | u32 prop; |
1225 | |
1226 | if (!node) |
1227 | return -EINVAL; |
1228 | |
1229 | tmp_node = of_get_child_by_name(node, name: "ethernet-ports" ); |
1230 | if (!tmp_node) |
1231 | return -ENOENT; |
1232 | data->slaves = of_get_child_count(np: tmp_node); |
1233 | if (data->slaves != CPSW_SLAVE_PORTS_NUM) { |
1234 | of_node_put(node: tmp_node); |
1235 | return -ENOENT; |
1236 | } |
1237 | |
1238 | data->active_slave = 0; |
1239 | data->channels = CPSW_MAX_QUEUES; |
1240 | data->dual_emac = true; |
1241 | data->bd_ram_size = CPSW_BD_RAM_SIZE; |
1242 | data->mac_control = 0; |
1243 | |
1244 | data->slave_data = devm_kcalloc(dev, CPSW_SLAVE_PORTS_NUM, |
1245 | size: sizeof(struct cpsw_slave_data), |
1246 | GFP_KERNEL); |
1247 | if (!data->slave_data) { |
1248 | of_node_put(node: tmp_node); |
1249 | return -ENOMEM; |
1250 | } |
1251 | |
1252 | /* Populate all the child nodes here... |
1253 | */ |
1254 | ret = devm_of_platform_populate(dev); |
1255 | /* We do not want to force this, as in some cases may not have child */ |
1256 | if (ret) |
1257 | dev_warn(dev, "Doesn't have any child node\n" ); |
1258 | |
1259 | for_each_child_of_node(tmp_node, port_np) { |
1260 | struct cpsw_slave_data *slave_data; |
1261 | u32 port_id; |
1262 | |
1263 | ret = of_property_read_u32(np: port_np, propname: "reg" , out_value: &port_id); |
1264 | if (ret < 0) { |
1265 | dev_err(dev, "%pOF error reading port_id %d\n" , |
1266 | port_np, ret); |
1267 | goto err_node_put; |
1268 | } |
1269 | |
1270 | if (!port_id || port_id > CPSW_SLAVE_PORTS_NUM) { |
1271 | dev_err(dev, "%pOF has invalid port_id %u\n" , |
1272 | port_np, port_id); |
1273 | ret = -EINVAL; |
1274 | goto err_node_put; |
1275 | } |
1276 | |
1277 | slave_data = &data->slave_data[port_id - 1]; |
1278 | |
1279 | slave_data->disabled = !of_device_is_available(device: port_np); |
1280 | if (slave_data->disabled) |
1281 | continue; |
1282 | |
1283 | slave_data->slave_node = port_np; |
1284 | slave_data->ifphy = devm_of_phy_get(dev, np: port_np, NULL); |
1285 | if (IS_ERR(ptr: slave_data->ifphy)) { |
1286 | ret = PTR_ERR(ptr: slave_data->ifphy); |
1287 | dev_err(dev, "%pOF: Error retrieving port phy: %d\n" , |
1288 | port_np, ret); |
1289 | goto err_node_put; |
1290 | } |
1291 | |
1292 | if (of_phy_is_fixed_link(np: port_np)) { |
1293 | ret = of_phy_register_fixed_link(np: port_np); |
1294 | if (ret) { |
1295 | dev_err_probe(dev, err: ret, fmt: "%pOF failed to register fixed-link phy\n" , |
1296 | port_np); |
1297 | goto err_node_put; |
1298 | } |
1299 | slave_data->phy_node = of_node_get(node: port_np); |
1300 | } else { |
1301 | slave_data->phy_node = |
1302 | of_parse_phandle(np: port_np, phandle_name: "phy-handle" , index: 0); |
1303 | } |
1304 | |
1305 | if (!slave_data->phy_node) { |
1306 | dev_err(dev, "%pOF no phy found\n" , port_np); |
1307 | ret = -ENODEV; |
1308 | goto err_node_put; |
1309 | } |
1310 | |
1311 | ret = of_get_phy_mode(np: port_np, interface: &slave_data->phy_if); |
1312 | if (ret) { |
1313 | dev_err(dev, "%pOF read phy-mode err %d\n" , |
1314 | port_np, ret); |
1315 | goto err_node_put; |
1316 | } |
1317 | |
1318 | ret = of_get_mac_address(np: port_np, mac: slave_data->mac_addr); |
1319 | if (ret) { |
1320 | ret = ti_cm_get_macid(dev, slave: port_id - 1, |
1321 | mac_addr: slave_data->mac_addr); |
1322 | if (ret) |
1323 | goto err_node_put; |
1324 | } |
1325 | |
1326 | if (of_property_read_u32(np: port_np, propname: "ti,dual-emac-pvid" , |
1327 | out_value: &prop)) { |
1328 | dev_err(dev, "%pOF Missing dual_emac_res_vlan in DT.\n" , |
1329 | port_np); |
1330 | slave_data->dual_emac_res_vlan = port_id; |
1331 | dev_err(dev, "%pOF Using %d as Reserved VLAN\n" , |
1332 | port_np, slave_data->dual_emac_res_vlan); |
1333 | } else { |
1334 | slave_data->dual_emac_res_vlan = prop; |
1335 | } |
1336 | } |
1337 | |
1338 | of_node_put(node: tmp_node); |
1339 | return 0; |
1340 | |
1341 | err_node_put: |
1342 | of_node_put(node: port_np); |
1343 | of_node_put(node: tmp_node); |
1344 | return ret; |
1345 | } |
1346 | |
1347 | static void cpsw_remove_dt(struct cpsw_common *cpsw) |
1348 | { |
1349 | struct cpsw_platform_data *data = &cpsw->data; |
1350 | int i = 0; |
1351 | |
1352 | for (i = 0; i < cpsw->data.slaves; i++) { |
1353 | struct cpsw_slave_data *slave_data = &data->slave_data[i]; |
1354 | struct device_node *port_np = slave_data->phy_node; |
1355 | |
1356 | if (port_np) { |
1357 | if (of_phy_is_fixed_link(np: port_np)) |
1358 | of_phy_deregister_fixed_link(np: port_np); |
1359 | |
1360 | of_node_put(node: port_np); |
1361 | } |
1362 | } |
1363 | } |
1364 | |
1365 | static int cpsw_create_ports(struct cpsw_common *cpsw) |
1366 | { |
1367 | struct cpsw_platform_data *data = &cpsw->data; |
1368 | struct net_device *ndev, *napi_ndev = NULL; |
1369 | struct device *dev = cpsw->dev; |
1370 | struct cpsw_priv *priv; |
1371 | int ret = 0, i = 0; |
1372 | |
1373 | for (i = 0; i < cpsw->data.slaves; i++) { |
1374 | struct cpsw_slave_data *slave_data = &data->slave_data[i]; |
1375 | |
1376 | if (slave_data->disabled) |
1377 | continue; |
1378 | |
1379 | ndev = devm_alloc_etherdev_mqs(dev, sizeof_priv: sizeof(struct cpsw_priv), |
1380 | CPSW_MAX_QUEUES, |
1381 | CPSW_MAX_QUEUES); |
1382 | if (!ndev) { |
1383 | dev_err(dev, "error allocating net_device\n" ); |
1384 | return -ENOMEM; |
1385 | } |
1386 | |
1387 | priv = netdev_priv(dev: ndev); |
1388 | priv->cpsw = cpsw; |
1389 | priv->ndev = ndev; |
1390 | priv->dev = dev; |
1391 | priv->msg_enable = netif_msg_init(debug_value: debug_level, CPSW_DEBUG); |
1392 | priv->emac_port = i + 1; |
1393 | priv->tx_packet_min = CPSW_MIN_PACKET_SIZE; |
1394 | |
1395 | if (is_valid_ether_addr(addr: slave_data->mac_addr)) { |
1396 | ether_addr_copy(dst: priv->mac_addr, src: slave_data->mac_addr); |
1397 | dev_info(cpsw->dev, "Detected MACID = %pM\n" , |
1398 | priv->mac_addr); |
1399 | } else { |
1400 | eth_random_addr(addr: slave_data->mac_addr); |
1401 | dev_info(cpsw->dev, "Random MACID = %pM\n" , |
1402 | priv->mac_addr); |
1403 | } |
1404 | eth_hw_addr_set(dev: ndev, addr: slave_data->mac_addr); |
1405 | ether_addr_copy(dst: priv->mac_addr, src: slave_data->mac_addr); |
1406 | |
1407 | cpsw->slaves[i].ndev = ndev; |
1408 | |
1409 | ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | |
1410 | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_NETNS_LOCAL | NETIF_F_HW_TC; |
1411 | |
1412 | ndev->xdp_features = NETDEV_XDP_ACT_BASIC | |
1413 | NETDEV_XDP_ACT_REDIRECT | |
1414 | NETDEV_XDP_ACT_NDO_XMIT; |
1415 | |
1416 | ndev->netdev_ops = &cpsw_netdev_ops; |
1417 | ndev->ethtool_ops = &cpsw_ethtool_ops; |
1418 | SET_NETDEV_DEV(ndev, dev); |
1419 | |
1420 | if (!napi_ndev) { |
1421 | /* CPSW Host port CPDMA interface is shared between |
1422 | * ports and there is only one TX and one RX IRQs |
1423 | * available for all possible TX and RX channels |
1424 | * accordingly. |
1425 | */ |
1426 | netif_napi_add(dev: ndev, napi: &cpsw->napi_rx, |
1427 | poll: cpsw->quirk_irq ? cpsw_rx_poll : cpsw_rx_mq_poll); |
1428 | netif_napi_add_tx(dev: ndev, napi: &cpsw->napi_tx, |
1429 | poll: cpsw->quirk_irq ? |
1430 | cpsw_tx_poll : cpsw_tx_mq_poll); |
1431 | } |
1432 | |
1433 | napi_ndev = ndev; |
1434 | } |
1435 | |
1436 | return ret; |
1437 | } |
1438 | |
1439 | static void cpsw_unregister_ports(struct cpsw_common *cpsw) |
1440 | { |
1441 | int i = 0; |
1442 | |
1443 | for (i = 0; i < cpsw->data.slaves; i++) { |
1444 | if (!cpsw->slaves[i].ndev) |
1445 | continue; |
1446 | |
1447 | unregister_netdev(dev: cpsw->slaves[i].ndev); |
1448 | } |
1449 | } |
1450 | |
1451 | static int cpsw_register_ports(struct cpsw_common *cpsw) |
1452 | { |
1453 | int ret = 0, i = 0; |
1454 | |
1455 | for (i = 0; i < cpsw->data.slaves; i++) { |
1456 | if (!cpsw->slaves[i].ndev) |
1457 | continue; |
1458 | |
1459 | /* register the network device */ |
1460 | ret = register_netdev(dev: cpsw->slaves[i].ndev); |
1461 | if (ret) { |
1462 | dev_err(cpsw->dev, |
1463 | "cpsw: err registering net device%d\n" , i); |
1464 | cpsw->slaves[i].ndev = NULL; |
1465 | break; |
1466 | } |
1467 | } |
1468 | |
1469 | if (ret) |
1470 | cpsw_unregister_ports(cpsw); |
1471 | return ret; |
1472 | } |
1473 | |
1474 | bool cpsw_port_dev_check(const struct net_device *ndev) |
1475 | { |
1476 | if (ndev->netdev_ops == &cpsw_netdev_ops) { |
1477 | struct cpsw_common *cpsw = ndev_to_cpsw(ndev); |
1478 | |
1479 | return !cpsw->data.dual_emac; |
1480 | } |
1481 | |
1482 | return false; |
1483 | } |
1484 | |
1485 | static void cpsw_port_offload_fwd_mark_update(struct cpsw_common *cpsw) |
1486 | { |
1487 | int set_val = 0; |
1488 | int i; |
1489 | |
1490 | if (!cpsw->ale_bypass && |
1491 | (cpsw->br_members == (ALE_PORT_1 | ALE_PORT_2))) |
1492 | set_val = 1; |
1493 | |
1494 | dev_dbg(cpsw->dev, "set offload_fwd_mark %d\n" , set_val); |
1495 | |
1496 | for (i = 0; i < cpsw->data.slaves; i++) { |
1497 | struct net_device *sl_ndev = cpsw->slaves[i].ndev; |
1498 | struct cpsw_priv *priv = netdev_priv(dev: sl_ndev); |
1499 | |
1500 | priv->offload_fwd_mark = set_val; |
1501 | } |
1502 | } |
1503 | |
1504 | static int cpsw_netdevice_port_link(struct net_device *ndev, |
1505 | struct net_device *br_ndev, |
1506 | struct netlink_ext_ack *extack) |
1507 | { |
1508 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
1509 | struct cpsw_common *cpsw = priv->cpsw; |
1510 | int err; |
1511 | |
1512 | if (!cpsw->br_members) { |
1513 | cpsw->hw_bridge_dev = br_ndev; |
1514 | } else { |
1515 | /* This is adding the port to a second bridge, this is |
1516 | * unsupported |
1517 | */ |
1518 | if (cpsw->hw_bridge_dev != br_ndev) |
1519 | return -EOPNOTSUPP; |
1520 | } |
1521 | |
1522 | err = switchdev_bridge_port_offload(brport_dev: ndev, dev: ndev, NULL, NULL, NULL, |
1523 | tx_fwd_offload: false, extack); |
1524 | if (err) |
1525 | return err; |
1526 | |
1527 | cpsw->br_members |= BIT(priv->emac_port); |
1528 | |
1529 | cpsw_port_offload_fwd_mark_update(cpsw); |
1530 | |
1531 | return NOTIFY_DONE; |
1532 | } |
1533 | |
1534 | static void cpsw_netdevice_port_unlink(struct net_device *ndev) |
1535 | { |
1536 | struct cpsw_priv *priv = netdev_priv(dev: ndev); |
1537 | struct cpsw_common *cpsw = priv->cpsw; |
1538 | |
1539 | switchdev_bridge_port_unoffload(brport_dev: ndev, NULL, NULL, NULL); |
1540 | |
1541 | cpsw->br_members &= ~BIT(priv->emac_port); |
1542 | |
1543 | cpsw_port_offload_fwd_mark_update(cpsw); |
1544 | |
1545 | if (!cpsw->br_members) |
1546 | cpsw->hw_bridge_dev = NULL; |
1547 | } |
1548 | |
1549 | /* netdev notifier */ |
1550 | static int cpsw_netdevice_event(struct notifier_block *unused, |
1551 | unsigned long event, void *ptr) |
1552 | { |
1553 | struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(info: ptr); |
1554 | struct net_device *ndev = netdev_notifier_info_to_dev(info: ptr); |
1555 | struct netdev_notifier_changeupper_info *info; |
1556 | int ret = NOTIFY_DONE; |
1557 | |
1558 | if (!cpsw_port_dev_check(ndev)) |
1559 | return NOTIFY_DONE; |
1560 | |
1561 | switch (event) { |
1562 | case NETDEV_CHANGEUPPER: |
1563 | info = ptr; |
1564 | |
1565 | if (netif_is_bridge_master(dev: info->upper_dev)) { |
1566 | if (info->linking) |
1567 | ret = cpsw_netdevice_port_link(ndev, |
1568 | br_ndev: info->upper_dev, |
1569 | extack); |
1570 | else |
1571 | cpsw_netdevice_port_unlink(ndev); |
1572 | } |
1573 | break; |
1574 | default: |
1575 | return NOTIFY_DONE; |
1576 | } |
1577 | |
1578 | return notifier_from_errno(err: ret); |
1579 | } |
1580 | |
1581 | static struct notifier_block cpsw_netdevice_nb __read_mostly = { |
1582 | .notifier_call = cpsw_netdevice_event, |
1583 | }; |
1584 | |
1585 | static int cpsw_register_notifiers(struct cpsw_common *cpsw) |
1586 | { |
1587 | int ret = 0; |
1588 | |
1589 | ret = register_netdevice_notifier(nb: &cpsw_netdevice_nb); |
1590 | if (ret) { |
1591 | dev_err(cpsw->dev, "can't register netdevice notifier\n" ); |
1592 | return ret; |
1593 | } |
1594 | |
1595 | ret = cpsw_switchdev_register_notifiers(cpsw); |
1596 | if (ret) |
1597 | unregister_netdevice_notifier(nb: &cpsw_netdevice_nb); |
1598 | |
1599 | return ret; |
1600 | } |
1601 | |
1602 | static void cpsw_unregister_notifiers(struct cpsw_common *cpsw) |
1603 | { |
1604 | cpsw_switchdev_unregister_notifiers(cpsw); |
1605 | unregister_netdevice_notifier(nb: &cpsw_netdevice_nb); |
1606 | } |
1607 | |
1608 | static const struct devlink_ops cpsw_devlink_ops = { |
1609 | }; |
1610 | |
1611 | static int cpsw_dl_switch_mode_get(struct devlink *dl, u32 id, |
1612 | struct devlink_param_gset_ctx *ctx) |
1613 | { |
1614 | struct cpsw_devlink *dl_priv = devlink_priv(devlink: dl); |
1615 | struct cpsw_common *cpsw = dl_priv->cpsw; |
1616 | |
1617 | dev_dbg(cpsw->dev, "%s id:%u\n" , __func__, id); |
1618 | |
1619 | if (id != CPSW_DL_PARAM_SWITCH_MODE) |
1620 | return -EOPNOTSUPP; |
1621 | |
1622 | ctx->val.vbool = !cpsw->data.dual_emac; |
1623 | |
1624 | return 0; |
1625 | } |
1626 | |
1627 | static int cpsw_dl_switch_mode_set(struct devlink *dl, u32 id, |
1628 | struct devlink_param_gset_ctx *ctx) |
1629 | { |
1630 | struct cpsw_devlink *dl_priv = devlink_priv(devlink: dl); |
1631 | struct cpsw_common *cpsw = dl_priv->cpsw; |
1632 | int vlan = cpsw->data.default_vlan; |
1633 | bool switch_en = ctx->val.vbool; |
1634 | bool if_running = false; |
1635 | int i; |
1636 | |
1637 | dev_dbg(cpsw->dev, "%s id:%u\n" , __func__, id); |
1638 | |
1639 | if (id != CPSW_DL_PARAM_SWITCH_MODE) |
1640 | return -EOPNOTSUPP; |
1641 | |
1642 | if (switch_en == !cpsw->data.dual_emac) |
1643 | return 0; |
1644 | |
1645 | if (!switch_en && cpsw->br_members) { |
1646 | dev_err(cpsw->dev, "Remove ports from BR before disabling switch mode\n" ); |
1647 | return -EINVAL; |
1648 | } |
1649 | |
1650 | rtnl_lock(); |
1651 | |
1652 | for (i = 0; i < cpsw->data.slaves; i++) { |
1653 | struct cpsw_slave *slave = &cpsw->slaves[i]; |
1654 | struct net_device *sl_ndev = slave->ndev; |
1655 | |
1656 | if (!sl_ndev || !netif_running(dev: sl_ndev)) |
1657 | continue; |
1658 | |
1659 | if_running = true; |
1660 | } |
1661 | |
1662 | if (!if_running) { |
1663 | /* all ndevs are down */ |
1664 | cpsw->data.dual_emac = !switch_en; |
1665 | for (i = 0; i < cpsw->data.slaves; i++) { |
1666 | struct cpsw_slave *slave = &cpsw->slaves[i]; |
1667 | struct net_device *sl_ndev = slave->ndev; |
1668 | |
1669 | if (!sl_ndev) |
1670 | continue; |
1671 | |
1672 | if (switch_en) |
1673 | vlan = cpsw->data.default_vlan; |
1674 | else |
1675 | vlan = slave->data->dual_emac_res_vlan; |
1676 | slave->port_vlan = vlan; |
1677 | } |
1678 | goto exit; |
1679 | } |
1680 | |
1681 | if (switch_en) { |
1682 | dev_info(cpsw->dev, "Enable switch mode\n" ); |
1683 | |
1684 | /* enable bypass - no forwarding; all traffic goes to Host */ |
1685 | cpsw_ale_control_set(ale: cpsw->ale, port: 0, control: ALE_BYPASS, value: 1); |
1686 | |
1687 | /* clean up ALE table */ |
1688 | cpsw_ale_control_set(ale: cpsw->ale, port: 0, control: ALE_CLEAR, value: 1); |
1689 | cpsw_ale_control_get(ale: cpsw->ale, port: 0, control: ALE_AGEOUT); |
1690 | |
1691 | cpsw_init_host_port_switch(cpsw); |
1692 | |
1693 | for (i = 0; i < cpsw->data.slaves; i++) { |
1694 | struct cpsw_slave *slave = &cpsw->slaves[i]; |
1695 | struct net_device *sl_ndev = slave->ndev; |
1696 | struct cpsw_priv *priv; |
1697 | |
1698 | if (!sl_ndev) |
1699 | continue; |
1700 | |
1701 | priv = netdev_priv(dev: sl_ndev); |
1702 | slave->port_vlan = vlan; |
1703 | WRITE_ONCE(priv->tx_packet_min, CPSW_MIN_PACKET_SIZE_VLAN); |
1704 | if (netif_running(dev: sl_ndev)) |
1705 | cpsw_port_add_switch_def_ale_entries(priv, |
1706 | slave); |
1707 | } |
1708 | |
1709 | cpsw_ale_control_set(ale: cpsw->ale, port: 0, control: ALE_BYPASS, value: 0); |
1710 | cpsw->data.dual_emac = false; |
1711 | } else { |
1712 | dev_info(cpsw->dev, "Disable switch mode\n" ); |
1713 | |
1714 | /* enable bypass - no forwarding; all traffic goes to Host */ |
1715 | cpsw_ale_control_set(ale: cpsw->ale, port: 0, control: ALE_BYPASS, value: 1); |
1716 | |
1717 | cpsw_ale_control_set(ale: cpsw->ale, port: 0, control: ALE_CLEAR, value: 1); |
1718 | cpsw_ale_control_get(ale: cpsw->ale, port: 0, control: ALE_AGEOUT); |
1719 | |
1720 | cpsw_init_host_port_dual_mac(cpsw); |
1721 | |
1722 | for (i = 0; i < cpsw->data.slaves; i++) { |
1723 | struct cpsw_slave *slave = &cpsw->slaves[i]; |
1724 | struct net_device *sl_ndev = slave->ndev; |
1725 | struct cpsw_priv *priv; |
1726 | |
1727 | if (!sl_ndev) |
1728 | continue; |
1729 | |
1730 | priv = netdev_priv(dev: slave->ndev); |
1731 | slave->port_vlan = slave->data->dual_emac_res_vlan; |
1732 | WRITE_ONCE(priv->tx_packet_min, CPSW_MIN_PACKET_SIZE); |
1733 | cpsw_port_add_dual_emac_def_ale_entries(priv, slave); |
1734 | } |
1735 | |
1736 | cpsw_ale_control_set(ale: cpsw->ale, port: 0, control: ALE_BYPASS, value: 0); |
1737 | cpsw->data.dual_emac = true; |
1738 | } |
1739 | exit: |
1740 | rtnl_unlock(); |
1741 | |
1742 | return 0; |
1743 | } |
1744 | |
1745 | static int cpsw_dl_ale_ctrl_get(struct devlink *dl, u32 id, |
1746 | struct devlink_param_gset_ctx *ctx) |
1747 | { |
1748 | struct cpsw_devlink *dl_priv = devlink_priv(devlink: dl); |
1749 | struct cpsw_common *cpsw = dl_priv->cpsw; |
1750 | |
1751 | dev_dbg(cpsw->dev, "%s id:%u\n" , __func__, id); |
1752 | |
1753 | switch (id) { |
1754 | case CPSW_DL_PARAM_ALE_BYPASS: |
1755 | ctx->val.vbool = cpsw_ale_control_get(ale: cpsw->ale, port: 0, control: ALE_BYPASS); |
1756 | break; |
1757 | default: |
1758 | return -EOPNOTSUPP; |
1759 | } |
1760 | |
1761 | return 0; |
1762 | } |
1763 | |
1764 | static int cpsw_dl_ale_ctrl_set(struct devlink *dl, u32 id, |
1765 | struct devlink_param_gset_ctx *ctx) |
1766 | { |
1767 | struct cpsw_devlink *dl_priv = devlink_priv(devlink: dl); |
1768 | struct cpsw_common *cpsw = dl_priv->cpsw; |
1769 | int ret = -EOPNOTSUPP; |
1770 | |
1771 | dev_dbg(cpsw->dev, "%s id:%u\n" , __func__, id); |
1772 | |
1773 | switch (id) { |
1774 | case CPSW_DL_PARAM_ALE_BYPASS: |
1775 | ret = cpsw_ale_control_set(ale: cpsw->ale, port: 0, control: ALE_BYPASS, |
1776 | value: ctx->val.vbool); |
1777 | if (!ret) { |
1778 | cpsw->ale_bypass = ctx->val.vbool; |
1779 | cpsw_port_offload_fwd_mark_update(cpsw); |
1780 | } |
1781 | break; |
1782 | default: |
1783 | return -EOPNOTSUPP; |
1784 | } |
1785 | |
1786 | return 0; |
1787 | } |
1788 | |
1789 | static const struct devlink_param cpsw_devlink_params[] = { |
1790 | DEVLINK_PARAM_DRIVER(CPSW_DL_PARAM_SWITCH_MODE, |
1791 | "switch_mode" , DEVLINK_PARAM_TYPE_BOOL, |
1792 | BIT(DEVLINK_PARAM_CMODE_RUNTIME), |
1793 | cpsw_dl_switch_mode_get, cpsw_dl_switch_mode_set, |
1794 | NULL), |
1795 | DEVLINK_PARAM_DRIVER(CPSW_DL_PARAM_ALE_BYPASS, |
1796 | "ale_bypass" , DEVLINK_PARAM_TYPE_BOOL, |
1797 | BIT(DEVLINK_PARAM_CMODE_RUNTIME), |
1798 | cpsw_dl_ale_ctrl_get, cpsw_dl_ale_ctrl_set, NULL), |
1799 | }; |
1800 | |
1801 | static int cpsw_register_devlink(struct cpsw_common *cpsw) |
1802 | { |
1803 | struct device *dev = cpsw->dev; |
1804 | struct cpsw_devlink *dl_priv; |
1805 | int ret = 0; |
1806 | |
1807 | cpsw->devlink = devlink_alloc(ops: &cpsw_devlink_ops, priv_size: sizeof(*dl_priv), dev); |
1808 | if (!cpsw->devlink) |
1809 | return -ENOMEM; |
1810 | |
1811 | dl_priv = devlink_priv(devlink: cpsw->devlink); |
1812 | dl_priv->cpsw = cpsw; |
1813 | |
1814 | ret = devlink_params_register(devlink: cpsw->devlink, params: cpsw_devlink_params, |
1815 | ARRAY_SIZE(cpsw_devlink_params)); |
1816 | if (ret) { |
1817 | dev_err(dev, "DL params reg fail ret:%d\n" , ret); |
1818 | goto dl_unreg; |
1819 | } |
1820 | |
1821 | devlink_register(devlink: cpsw->devlink); |
1822 | return ret; |
1823 | |
1824 | dl_unreg: |
1825 | devlink_free(devlink: cpsw->devlink); |
1826 | return ret; |
1827 | } |
1828 | |
1829 | static void cpsw_unregister_devlink(struct cpsw_common *cpsw) |
1830 | { |
1831 | devlink_unregister(devlink: cpsw->devlink); |
1832 | devlink_params_unregister(devlink: cpsw->devlink, params: cpsw_devlink_params, |
1833 | ARRAY_SIZE(cpsw_devlink_params)); |
1834 | devlink_free(devlink: cpsw->devlink); |
1835 | } |
1836 | |
1837 | static const struct of_device_id cpsw_of_mtable[] = { |
1838 | { .compatible = "ti,cpsw-switch" }, |
1839 | { .compatible = "ti,am335x-cpsw-switch" }, |
1840 | { .compatible = "ti,am4372-cpsw-switch" }, |
1841 | { .compatible = "ti,dra7-cpsw-switch" }, |
1842 | { /* sentinel */ }, |
1843 | }; |
1844 | MODULE_DEVICE_TABLE(of, cpsw_of_mtable); |
1845 | |
1846 | static const struct soc_device_attribute cpsw_soc_devices[] = { |
1847 | { .family = "AM33xx" , .revision = "ES1.0" }, |
1848 | { /* sentinel */ } |
1849 | }; |
1850 | |
1851 | static int cpsw_probe(struct platform_device *pdev) |
1852 | { |
1853 | const struct soc_device_attribute *soc; |
1854 | struct device *dev = &pdev->dev; |
1855 | struct cpsw_common *cpsw; |
1856 | struct resource *ss_res; |
1857 | struct gpio_descs *mode; |
1858 | void __iomem *ss_regs; |
1859 | int ret = 0, ch; |
1860 | struct clk *clk; |
1861 | int irq; |
1862 | |
1863 | cpsw = devm_kzalloc(dev, size: sizeof(struct cpsw_common), GFP_KERNEL); |
1864 | if (!cpsw) |
1865 | return -ENOMEM; |
1866 | |
1867 | cpsw_slave_index = cpsw_slave_index_priv; |
1868 | |
1869 | cpsw->dev = dev; |
1870 | |
1871 | cpsw->slaves = devm_kcalloc(dev, |
1872 | CPSW_SLAVE_PORTS_NUM, |
1873 | size: sizeof(struct cpsw_slave), |
1874 | GFP_KERNEL); |
1875 | if (!cpsw->slaves) |
1876 | return -ENOMEM; |
1877 | |
1878 | mode = devm_gpiod_get_array_optional(dev, con_id: "mode" , flags: GPIOD_OUT_LOW); |
1879 | if (IS_ERR(ptr: mode)) { |
1880 | ret = PTR_ERR(ptr: mode); |
1881 | dev_err(dev, "gpio request failed, ret %d\n" , ret); |
1882 | return ret; |
1883 | } |
1884 | |
1885 | clk = devm_clk_get(dev, id: "fck" ); |
1886 | if (IS_ERR(ptr: clk)) { |
1887 | ret = PTR_ERR(ptr: clk); |
1888 | dev_err(dev, "fck is not found %d\n" , ret); |
1889 | return ret; |
1890 | } |
1891 | cpsw->bus_freq_mhz = clk_get_rate(clk) / 1000000; |
1892 | |
1893 | ss_regs = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &ss_res); |
1894 | if (IS_ERR(ptr: ss_regs)) { |
1895 | ret = PTR_ERR(ptr: ss_regs); |
1896 | return ret; |
1897 | } |
1898 | cpsw->regs = ss_regs; |
1899 | |
1900 | irq = platform_get_irq_byname(pdev, "rx" ); |
1901 | if (irq < 0) |
1902 | return irq; |
1903 | cpsw->irqs_table[0] = irq; |
1904 | |
1905 | irq = platform_get_irq_byname(pdev, "tx" ); |
1906 | if (irq < 0) |
1907 | return irq; |
1908 | cpsw->irqs_table[1] = irq; |
1909 | |
1910 | irq = platform_get_irq_byname(pdev, "misc" ); |
1911 | if (irq <= 0) |
1912 | return irq; |
1913 | cpsw->misc_irq = irq; |
1914 | |
1915 | platform_set_drvdata(pdev, data: cpsw); |
1916 | /* This may be required here for child devices. */ |
1917 | pm_runtime_enable(dev); |
1918 | |
1919 | /* Need to enable clocks with runtime PM api to access module |
1920 | * registers |
1921 | */ |
1922 | ret = pm_runtime_resume_and_get(dev); |
1923 | if (ret < 0) { |
1924 | pm_runtime_disable(dev); |
1925 | return ret; |
1926 | } |
1927 | |
1928 | ret = cpsw_probe_dt(cpsw); |
1929 | if (ret) |
1930 | goto clean_dt_ret; |
1931 | |
1932 | soc = soc_device_match(matches: cpsw_soc_devices); |
1933 | if (soc) |
1934 | cpsw->quirk_irq = true; |
1935 | |
1936 | cpsw->rx_packet_max = rx_packet_max; |
1937 | cpsw->descs_pool_size = descs_pool_size; |
1938 | eth_random_addr(addr: cpsw->base_mac); |
1939 | |
1940 | ret = cpsw_init_common(cpsw, ss_regs, ale_ageout, |
1941 | desc_mem_phys: (u32 __force)ss_res->start + CPSW2_BD_OFFSET, |
1942 | descs_pool_size); |
1943 | if (ret) |
1944 | goto clean_dt_ret; |
1945 | |
1946 | cpsw->wr_regs = cpsw->version == CPSW_VERSION_1 ? |
1947 | ss_regs + CPSW1_WR_OFFSET : |
1948 | ss_regs + CPSW2_WR_OFFSET; |
1949 | |
1950 | ch = cpsw->quirk_irq ? 0 : 7; |
1951 | cpsw->txv[0].ch = cpdma_chan_create(ctlr: cpsw->dma, chan_num: ch, handler: cpsw_tx_handler, rx_type: 0); |
1952 | if (IS_ERR(ptr: cpsw->txv[0].ch)) { |
1953 | dev_err(dev, "error initializing tx dma channel\n" ); |
1954 | ret = PTR_ERR(ptr: cpsw->txv[0].ch); |
1955 | goto clean_cpts; |
1956 | } |
1957 | |
1958 | cpsw->rxv[0].ch = cpdma_chan_create(ctlr: cpsw->dma, chan_num: 0, handler: cpsw_rx_handler, rx_type: 1); |
1959 | if (IS_ERR(ptr: cpsw->rxv[0].ch)) { |
1960 | dev_err(dev, "error initializing rx dma channel\n" ); |
1961 | ret = PTR_ERR(ptr: cpsw->rxv[0].ch); |
1962 | goto clean_cpts; |
1963 | } |
1964 | cpsw_split_res(cpsw); |
1965 | |
1966 | /* setup netdevs */ |
1967 | ret = cpsw_create_ports(cpsw); |
1968 | if (ret) |
1969 | goto clean_unregister_netdev; |
1970 | |
1971 | /* Grab RX and TX IRQs. Note that we also have RX_THRESHOLD and |
1972 | * MISC IRQs which are always kept disabled with this driver so |
1973 | * we will not request them. |
1974 | * |
1975 | * If anyone wants to implement support for those, make sure to |
1976 | * first request and append them to irqs_table array. |
1977 | */ |
1978 | |
1979 | ret = devm_request_irq(dev, irq: cpsw->irqs_table[0], handler: cpsw_rx_interrupt, |
1980 | irqflags: 0, devname: dev_name(dev), dev_id: cpsw); |
1981 | if (ret < 0) { |
1982 | dev_err(dev, "error attaching irq (%d)\n" , ret); |
1983 | goto clean_unregister_netdev; |
1984 | } |
1985 | |
1986 | ret = devm_request_irq(dev, irq: cpsw->irqs_table[1], handler: cpsw_tx_interrupt, |
1987 | irqflags: 0, devname: dev_name(dev), dev_id: cpsw); |
1988 | if (ret < 0) { |
1989 | dev_err(dev, "error attaching irq (%d)\n" , ret); |
1990 | goto clean_unregister_netdev; |
1991 | } |
1992 | |
1993 | if (!cpsw->cpts) |
1994 | goto skip_cpts; |
1995 | |
1996 | ret = devm_request_irq(dev, irq: cpsw->misc_irq, handler: cpsw_misc_interrupt, |
1997 | irqflags: 0, devname: dev_name(dev: &pdev->dev), dev_id: cpsw); |
1998 | if (ret < 0) { |
1999 | dev_err(dev, "error attaching misc irq (%d)\n" , ret); |
2000 | goto clean_unregister_netdev; |
2001 | } |
2002 | |
2003 | /* Enable misc CPTS evnt_pend IRQ */ |
2004 | cpts_set_irqpoll(cpts: cpsw->cpts, en: false); |
2005 | |
2006 | skip_cpts: |
2007 | ret = cpsw_register_notifiers(cpsw); |
2008 | if (ret) |
2009 | goto clean_unregister_netdev; |
2010 | |
2011 | ret = cpsw_register_devlink(cpsw); |
2012 | if (ret) |
2013 | goto clean_unregister_notifiers; |
2014 | |
2015 | ret = cpsw_register_ports(cpsw); |
2016 | if (ret) |
2017 | goto clean_unregister_notifiers; |
2018 | |
2019 | dev_notice(dev, "initialized (regs %pa, pool size %d) hw_ver:%08X %d.%d (%d)\n" , |
2020 | &ss_res->start, descs_pool_size, |
2021 | cpsw->version, CPSW_MAJOR_VERSION(cpsw->version), |
2022 | CPSW_MINOR_VERSION(cpsw->version), |
2023 | CPSW_RTL_VERSION(cpsw->version)); |
2024 | |
2025 | pm_runtime_put(dev); |
2026 | |
2027 | return 0; |
2028 | |
2029 | clean_unregister_notifiers: |
2030 | cpsw_unregister_notifiers(cpsw); |
2031 | clean_unregister_netdev: |
2032 | cpsw_unregister_ports(cpsw); |
2033 | clean_cpts: |
2034 | cpts_release(cpts: cpsw->cpts); |
2035 | cpdma_ctlr_destroy(ctlr: cpsw->dma); |
2036 | clean_dt_ret: |
2037 | cpsw_remove_dt(cpsw); |
2038 | pm_runtime_put_sync(dev); |
2039 | pm_runtime_disable(dev); |
2040 | return ret; |
2041 | } |
2042 | |
2043 | static void cpsw_remove(struct platform_device *pdev) |
2044 | { |
2045 | struct cpsw_common *cpsw = platform_get_drvdata(pdev); |
2046 | int ret; |
2047 | |
2048 | ret = pm_runtime_resume_and_get(dev: &pdev->dev); |
2049 | if (ret < 0) { |
2050 | /* Note, if this error path is taken, we're leaking some |
2051 | * resources. |
2052 | */ |
2053 | dev_err(&pdev->dev, "Failed to resume device (%pe)\n" , |
2054 | ERR_PTR(ret)); |
2055 | return; |
2056 | } |
2057 | |
2058 | cpsw_unregister_notifiers(cpsw); |
2059 | cpsw_unregister_devlink(cpsw); |
2060 | cpsw_unregister_ports(cpsw); |
2061 | |
2062 | cpts_release(cpts: cpsw->cpts); |
2063 | cpdma_ctlr_destroy(ctlr: cpsw->dma); |
2064 | cpsw_remove_dt(cpsw); |
2065 | pm_runtime_put_sync(dev: &pdev->dev); |
2066 | pm_runtime_disable(dev: &pdev->dev); |
2067 | } |
2068 | |
2069 | static int __maybe_unused cpsw_suspend(struct device *dev) |
2070 | { |
2071 | struct cpsw_common *cpsw = dev_get_drvdata(dev); |
2072 | int i; |
2073 | |
2074 | rtnl_lock(); |
2075 | |
2076 | for (i = 0; i < cpsw->data.slaves; i++) { |
2077 | struct net_device *ndev = cpsw->slaves[i].ndev; |
2078 | |
2079 | if (!(ndev && netif_running(dev: ndev))) |
2080 | continue; |
2081 | |
2082 | cpsw_ndo_stop(ndev); |
2083 | } |
2084 | |
2085 | rtnl_unlock(); |
2086 | |
2087 | /* Select sleep pin state */ |
2088 | pinctrl_pm_select_sleep_state(dev); |
2089 | |
2090 | return 0; |
2091 | } |
2092 | |
2093 | static int __maybe_unused cpsw_resume(struct device *dev) |
2094 | { |
2095 | struct cpsw_common *cpsw = dev_get_drvdata(dev); |
2096 | int i; |
2097 | |
2098 | /* Select default pin state */ |
2099 | pinctrl_pm_select_default_state(dev); |
2100 | |
2101 | /* shut up ASSERT_RTNL() warning in netif_set_real_num_tx/rx_queues */ |
2102 | rtnl_lock(); |
2103 | |
2104 | for (i = 0; i < cpsw->data.slaves; i++) { |
2105 | struct net_device *ndev = cpsw->slaves[i].ndev; |
2106 | |
2107 | if (!(ndev && netif_running(dev: ndev))) |
2108 | continue; |
2109 | |
2110 | cpsw_ndo_open(ndev); |
2111 | } |
2112 | |
2113 | rtnl_unlock(); |
2114 | |
2115 | return 0; |
2116 | } |
2117 | |
2118 | static SIMPLE_DEV_PM_OPS(cpsw_pm_ops, cpsw_suspend, cpsw_resume); |
2119 | |
2120 | static struct platform_driver cpsw_driver = { |
2121 | .driver = { |
2122 | .name = "cpsw-switch" , |
2123 | .pm = &cpsw_pm_ops, |
2124 | .of_match_table = cpsw_of_mtable, |
2125 | }, |
2126 | .probe = cpsw_probe, |
2127 | .remove_new = cpsw_remove, |
2128 | }; |
2129 | |
2130 | module_platform_driver(cpsw_driver); |
2131 | |
2132 | MODULE_LICENSE("GPL" ); |
2133 | MODULE_DESCRIPTION("TI CPSW switchdev Ethernet driver" ); |
2134 | |