1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /* Copyright (c) 2019-2020 Marvell International Ltd. All rights reserved */ |
3 | |
4 | #include <linux/etherdevice.h> |
5 | #include <linux/if_bridge.h> |
6 | #include <linux/ethtool.h> |
7 | #include <linux/list.h> |
8 | |
9 | #include "prestera.h" |
10 | #include "prestera_hw.h" |
11 | #include "prestera_acl.h" |
12 | #include "prestera_counter.h" |
13 | #include "prestera_router_hw.h" |
14 | |
15 | #define PRESTERA_SWITCH_INIT_TIMEOUT_MS (30 * 1000) |
16 | |
17 | #define PRESTERA_MIN_MTU 64 |
18 | |
19 | #define PRESTERA_MSG_CHUNK_SIZE 1024 |
20 | |
21 | enum prestera_cmd_type_t { |
22 | PRESTERA_CMD_TYPE_SWITCH_INIT = 0x1, |
23 | PRESTERA_CMD_TYPE_SWITCH_ATTR_SET = 0x2, |
24 | |
25 | PRESTERA_CMD_TYPE_PORT_ATTR_SET = 0x100, |
26 | PRESTERA_CMD_TYPE_PORT_ATTR_GET = 0x101, |
27 | PRESTERA_CMD_TYPE_PORT_INFO_GET = 0x110, |
28 | |
29 | PRESTERA_CMD_TYPE_VLAN_CREATE = 0x200, |
30 | PRESTERA_CMD_TYPE_VLAN_DELETE = 0x201, |
31 | PRESTERA_CMD_TYPE_VLAN_PORT_SET = 0x202, |
32 | PRESTERA_CMD_TYPE_VLAN_PVID_SET = 0x203, |
33 | |
34 | PRESTERA_CMD_TYPE_FDB_ADD = 0x300, |
35 | PRESTERA_CMD_TYPE_FDB_DELETE = 0x301, |
36 | PRESTERA_CMD_TYPE_FDB_FLUSH_PORT = 0x310, |
37 | PRESTERA_CMD_TYPE_FDB_FLUSH_VLAN = 0x311, |
38 | PRESTERA_CMD_TYPE_FDB_FLUSH_PORT_VLAN = 0x312, |
39 | |
40 | PRESTERA_CMD_TYPE_BRIDGE_CREATE = 0x400, |
41 | PRESTERA_CMD_TYPE_BRIDGE_DELETE = 0x401, |
42 | PRESTERA_CMD_TYPE_BRIDGE_PORT_ADD = 0x402, |
43 | PRESTERA_CMD_TYPE_BRIDGE_PORT_DELETE = 0x403, |
44 | |
45 | PRESTERA_CMD_TYPE_COUNTER_GET = 0x510, |
46 | PRESTERA_CMD_TYPE_COUNTER_ABORT = 0x511, |
47 | PRESTERA_CMD_TYPE_COUNTER_TRIGGER = 0x512, |
48 | PRESTERA_CMD_TYPE_COUNTER_BLOCK_GET = 0x513, |
49 | PRESTERA_CMD_TYPE_COUNTER_BLOCK_RELEASE = 0x514, |
50 | PRESTERA_CMD_TYPE_COUNTER_CLEAR = 0x515, |
51 | |
52 | PRESTERA_CMD_TYPE_VTCAM_CREATE = 0x540, |
53 | PRESTERA_CMD_TYPE_VTCAM_DESTROY = 0x541, |
54 | PRESTERA_CMD_TYPE_VTCAM_RULE_ADD = 0x550, |
55 | PRESTERA_CMD_TYPE_VTCAM_RULE_DELETE = 0x551, |
56 | PRESTERA_CMD_TYPE_VTCAM_IFACE_BIND = 0x560, |
57 | PRESTERA_CMD_TYPE_VTCAM_IFACE_UNBIND = 0x561, |
58 | |
59 | PRESTERA_CMD_TYPE_ROUTER_RIF_CREATE = 0x600, |
60 | PRESTERA_CMD_TYPE_ROUTER_RIF_DELETE = 0x601, |
61 | PRESTERA_CMD_TYPE_ROUTER_LPM_ADD = 0x610, |
62 | PRESTERA_CMD_TYPE_ROUTER_LPM_DELETE = 0x611, |
63 | PRESTERA_CMD_TYPE_ROUTER_NH_GRP_SET = 0x622, |
64 | PRESTERA_CMD_TYPE_ROUTER_NH_GRP_BLK_GET = 0x645, |
65 | PRESTERA_CMD_TYPE_ROUTER_NH_GRP_ADD = 0x623, |
66 | PRESTERA_CMD_TYPE_ROUTER_NH_GRP_DELETE = 0x624, |
67 | PRESTERA_CMD_TYPE_ROUTER_VR_CREATE = 0x630, |
68 | PRESTERA_CMD_TYPE_ROUTER_VR_DELETE = 0x631, |
69 | |
70 | PRESTERA_CMD_TYPE_FLOOD_DOMAIN_CREATE = 0x700, |
71 | PRESTERA_CMD_TYPE_FLOOD_DOMAIN_DESTROY = 0x701, |
72 | PRESTERA_CMD_TYPE_FLOOD_DOMAIN_PORTS_SET = 0x702, |
73 | PRESTERA_CMD_TYPE_FLOOD_DOMAIN_PORTS_RESET = 0x703, |
74 | |
75 | PRESTERA_CMD_TYPE_MDB_CREATE = 0x704, |
76 | PRESTERA_CMD_TYPE_MDB_DESTROY = 0x705, |
77 | |
78 | PRESTERA_CMD_TYPE_RXTX_INIT = 0x800, |
79 | |
80 | PRESTERA_CMD_TYPE_LAG_MEMBER_ADD = 0x900, |
81 | PRESTERA_CMD_TYPE_LAG_MEMBER_DELETE = 0x901, |
82 | PRESTERA_CMD_TYPE_LAG_MEMBER_ENABLE = 0x902, |
83 | PRESTERA_CMD_TYPE_LAG_MEMBER_DISABLE = 0x903, |
84 | |
85 | PRESTERA_CMD_TYPE_STP_PORT_SET = 0x1000, |
86 | |
87 | PRESTERA_CMD_TYPE_SPAN_GET = 0x1100, |
88 | PRESTERA_CMD_TYPE_SPAN_INGRESS_BIND = 0x1101, |
89 | PRESTERA_CMD_TYPE_SPAN_INGRESS_UNBIND = 0x1102, |
90 | PRESTERA_CMD_TYPE_SPAN_RELEASE = 0x1103, |
91 | PRESTERA_CMD_TYPE_SPAN_EGRESS_BIND = 0x1104, |
92 | PRESTERA_CMD_TYPE_SPAN_EGRESS_UNBIND = 0x1105, |
93 | |
94 | PRESTERA_CMD_TYPE_POLICER_CREATE = 0x1500, |
95 | PRESTERA_CMD_TYPE_POLICER_RELEASE = 0x1501, |
96 | PRESTERA_CMD_TYPE_POLICER_SET = 0x1502, |
97 | |
98 | PRESTERA_CMD_TYPE_CPU_CODE_COUNTERS_GET = 0x2000, |
99 | |
100 | PRESTERA_CMD_TYPE_ACK = 0x10000, |
101 | PRESTERA_CMD_TYPE_MAX |
102 | }; |
103 | |
104 | enum { |
105 | PRESTERA_CMD_PORT_ATTR_ADMIN_STATE = 1, |
106 | PRESTERA_CMD_PORT_ATTR_MTU = 3, |
107 | PRESTERA_CMD_PORT_ATTR_MAC = 4, |
108 | PRESTERA_CMD_PORT_ATTR_SPEED = 5, |
109 | PRESTERA_CMD_PORT_ATTR_ACCEPT_FRAME_TYPE = 6, |
110 | PRESTERA_CMD_PORT_ATTR_LEARNING = 7, |
111 | PRESTERA_CMD_PORT_ATTR_FLOOD = 8, |
112 | PRESTERA_CMD_PORT_ATTR_CAPABILITY = 9, |
113 | PRESTERA_CMD_PORT_ATTR_LOCKED = 10, |
114 | PRESTERA_CMD_PORT_ATTR_PHY_MODE = 12, |
115 | PRESTERA_CMD_PORT_ATTR_TYPE = 13, |
116 | PRESTERA_CMD_PORT_ATTR_STATS = 17, |
117 | PRESTERA_CMD_PORT_ATTR_MAC_AUTONEG_RESTART = 18, |
118 | PRESTERA_CMD_PORT_ATTR_PHY_AUTONEG_RESTART = 19, |
119 | PRESTERA_CMD_PORT_ATTR_MAC_MODE = 22, |
120 | }; |
121 | |
122 | enum { |
123 | PRESTERA_CMD_SWITCH_ATTR_MAC = 1, |
124 | PRESTERA_CMD_SWITCH_ATTR_AGEING = 2, |
125 | }; |
126 | |
127 | enum { |
128 | PRESTERA_CMD_ACK_OK, |
129 | PRESTERA_CMD_ACK_FAILED, |
130 | |
131 | PRESTERA_CMD_ACK_MAX |
132 | }; |
133 | |
134 | enum { |
135 | PRESTERA_PORT_TP_NA, |
136 | PRESTERA_PORT_TP_MDI, |
137 | PRESTERA_PORT_TP_MDIX, |
138 | PRESTERA_PORT_TP_AUTO, |
139 | }; |
140 | |
141 | enum { |
142 | PRESTERA_PORT_FLOOD_TYPE_UC = 0, |
143 | PRESTERA_PORT_FLOOD_TYPE_MC = 1, |
144 | }; |
145 | |
146 | enum { |
147 | PRESTERA_PORT_GOOD_OCTETS_RCV_CNT, |
148 | PRESTERA_PORT_BAD_OCTETS_RCV_CNT, |
149 | PRESTERA_PORT_MAC_TRANSMIT_ERR_CNT, |
150 | PRESTERA_PORT_BRDC_PKTS_RCV_CNT, |
151 | PRESTERA_PORT_MC_PKTS_RCV_CNT, |
152 | PRESTERA_PORT_PKTS_64L_CNT, |
153 | PRESTERA_PORT_PKTS_65TO127L_CNT, |
154 | PRESTERA_PORT_PKTS_128TO255L_CNT, |
155 | PRESTERA_PORT_PKTS_256TO511L_CNT, |
156 | PRESTERA_PORT_PKTS_512TO1023L_CNT, |
157 | PRESTERA_PORT_PKTS_1024TOMAXL_CNT, |
158 | PRESTERA_PORT_EXCESSIVE_COLLISIONS_CNT, |
159 | PRESTERA_PORT_MC_PKTS_SENT_CNT, |
160 | PRESTERA_PORT_BRDC_PKTS_SENT_CNT, |
161 | PRESTERA_PORT_FC_SENT_CNT, |
162 | PRESTERA_PORT_GOOD_FC_RCV_CNT, |
163 | PRESTERA_PORT_DROP_EVENTS_CNT, |
164 | PRESTERA_PORT_UNDERSIZE_PKTS_CNT, |
165 | PRESTERA_PORT_FRAGMENTS_PKTS_CNT, |
166 | PRESTERA_PORT_OVERSIZE_PKTS_CNT, |
167 | PRESTERA_PORT_JABBER_PKTS_CNT, |
168 | PRESTERA_PORT_MAC_RCV_ERROR_CNT, |
169 | PRESTERA_PORT_BAD_CRC_CNT, |
170 | PRESTERA_PORT_COLLISIONS_CNT, |
171 | PRESTERA_PORT_LATE_COLLISIONS_CNT, |
172 | PRESTERA_PORT_GOOD_UC_PKTS_RCV_CNT, |
173 | PRESTERA_PORT_GOOD_UC_PKTS_SENT_CNT, |
174 | PRESTERA_PORT_MULTIPLE_PKTS_SENT_CNT, |
175 | PRESTERA_PORT_DEFERRED_PKTS_SENT_CNT, |
176 | PRESTERA_PORT_GOOD_OCTETS_SENT_CNT, |
177 | |
178 | PRESTERA_PORT_CNT_MAX |
179 | }; |
180 | |
181 | enum { |
182 | PRESTERA_FC_NONE, |
183 | PRESTERA_FC_SYMMETRIC, |
184 | PRESTERA_FC_ASYMMETRIC, |
185 | PRESTERA_FC_SYMM_ASYMM, |
186 | }; |
187 | |
188 | enum { |
189 | PRESTERA_POLICER_MODE_SR_TCM |
190 | }; |
191 | |
192 | enum { |
193 | PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT = 0, |
194 | PRESTERA_HW_FDB_ENTRY_TYPE_LAG = 1, |
195 | PRESTERA_HW_FDB_ENTRY_TYPE_MAX = 2, |
196 | }; |
197 | |
198 | struct prestera_fw_event_handler { |
199 | struct list_head list; |
200 | struct rcu_head rcu; |
201 | enum prestera_event_type type; |
202 | prestera_event_cb_t func; |
203 | void *arg; |
204 | }; |
205 | |
206 | enum { |
207 | PRESTERA_HW_FLOOD_DOMAIN_PORT_TYPE_REG_PORT = 0, |
208 | PRESTERA_HW_FLOOD_DOMAIN_PORT_TYPE_LAG = 1, |
209 | PRESTERA_HW_FLOOD_DOMAIN_PORT_TYPE_MAX = 2, |
210 | }; |
211 | |
212 | struct prestera_msg_cmd { |
213 | __le32 type; |
214 | }; |
215 | |
216 | struct prestera_msg_ret { |
217 | struct prestera_msg_cmd cmd; |
218 | __le32 status; |
219 | }; |
220 | |
221 | struct prestera_msg_common_req { |
222 | struct prestera_msg_cmd cmd; |
223 | }; |
224 | |
225 | struct prestera_msg_common_resp { |
226 | struct prestera_msg_ret ret; |
227 | }; |
228 | |
229 | struct prestera_msg_switch_attr_req { |
230 | struct prestera_msg_cmd cmd; |
231 | __le32 attr; |
232 | union { |
233 | __le32 ageing_timeout_ms; |
234 | struct { |
235 | u8 mac[ETH_ALEN]; |
236 | u8 __pad[2]; |
237 | }; |
238 | } param; |
239 | }; |
240 | |
241 | struct prestera_msg_switch_init_resp { |
242 | struct prestera_msg_ret ret; |
243 | __le32 port_count; |
244 | __le32 mtu_max; |
245 | __le32 size_tbl_router_nexthop; |
246 | u8 switch_id; |
247 | u8 lag_max; |
248 | u8 lag_member_max; |
249 | }; |
250 | |
251 | struct prestera_msg_event_port_param { |
252 | union { |
253 | struct { |
254 | __le32 mode; |
255 | __le32 speed; |
256 | u8 oper; |
257 | u8 duplex; |
258 | u8 fc; |
259 | u8 fec; |
260 | } mac; |
261 | struct { |
262 | __le64 lmode_bmap; |
263 | u8 mdix; |
264 | u8 fc; |
265 | u8 __pad[2]; |
266 | } __packed phy; /* make sure always 12 bytes size */ |
267 | }; |
268 | }; |
269 | |
270 | struct prestera_msg_port_cap_param { |
271 | __le64 link_mode; |
272 | u8 type; |
273 | u8 fec; |
274 | u8 fc; |
275 | u8 transceiver; |
276 | }; |
277 | |
278 | struct prestera_msg_port_flood_param { |
279 | u8 type; |
280 | u8 enable; |
281 | u8 __pad[2]; |
282 | }; |
283 | |
284 | union prestera_msg_port_param { |
285 | __le32 mtu; |
286 | __le32 speed; |
287 | __le32 link_mode; |
288 | u8 admin_state; |
289 | u8 oper_state; |
290 | u8 mac[ETH_ALEN]; |
291 | u8 accept_frm_type; |
292 | u8 learning; |
293 | u8 flood; |
294 | u8 type; |
295 | u8 duplex; |
296 | u8 fec; |
297 | u8 fc; |
298 | u8 br_locked; |
299 | union { |
300 | struct { |
301 | u8 admin; |
302 | u8 fc; |
303 | u8 ap_enable; |
304 | u8 __reserved[5]; |
305 | union { |
306 | struct { |
307 | __le32 mode; |
308 | __le32 speed; |
309 | u8 inband; |
310 | u8 duplex; |
311 | u8 fec; |
312 | u8 fec_supp; |
313 | } reg_mode; |
314 | struct { |
315 | __le32 mode; |
316 | __le32 speed; |
317 | u8 fec; |
318 | u8 fec_supp; |
319 | u8 __pad[2]; |
320 | } ap_modes[PRESTERA_AP_PORT_MAX]; |
321 | }; |
322 | } mac; |
323 | struct { |
324 | __le64 modes; |
325 | __le32 mode; |
326 | u8 admin; |
327 | u8 adv_enable; |
328 | u8 mdix; |
329 | u8 __pad; |
330 | } phy; |
331 | } link; |
332 | |
333 | struct prestera_msg_port_cap_param cap; |
334 | struct prestera_msg_port_flood_param flood_ext; |
335 | struct prestera_msg_event_port_param link_evt; |
336 | }; |
337 | |
338 | struct prestera_msg_port_attr_req { |
339 | struct prestera_msg_cmd cmd; |
340 | __le32 attr; |
341 | __le32 port; |
342 | __le32 dev; |
343 | union prestera_msg_port_param param; |
344 | }; |
345 | |
346 | struct prestera_msg_port_attr_resp { |
347 | struct prestera_msg_ret ret; |
348 | union prestera_msg_port_param param; |
349 | }; |
350 | |
351 | struct prestera_msg_port_stats_resp { |
352 | struct prestera_msg_ret ret; |
353 | __le64 stats[PRESTERA_PORT_CNT_MAX]; |
354 | }; |
355 | |
356 | struct prestera_msg_port_info_req { |
357 | struct prestera_msg_cmd cmd; |
358 | __le32 port; |
359 | }; |
360 | |
361 | struct prestera_msg_port_info_resp { |
362 | struct prestera_msg_ret ret; |
363 | __le32 hw_id; |
364 | __le32 dev_id; |
365 | __le16 fp_id; |
366 | u8 pad[2]; |
367 | }; |
368 | |
369 | struct prestera_msg_vlan_req { |
370 | struct prestera_msg_cmd cmd; |
371 | __le32 port; |
372 | __le32 dev; |
373 | __le16 vid; |
374 | u8 is_member; |
375 | u8 is_tagged; |
376 | }; |
377 | |
378 | struct prestera_msg_fdb_req { |
379 | struct prestera_msg_cmd cmd; |
380 | __le32 flush_mode; |
381 | union { |
382 | struct { |
383 | __le32 port; |
384 | __le32 dev; |
385 | }; |
386 | __le16 lag_id; |
387 | } dest; |
388 | __le16 vid; |
389 | u8 dest_type; |
390 | u8 dynamic; |
391 | u8 mac[ETH_ALEN]; |
392 | u8 __pad[2]; |
393 | }; |
394 | |
395 | struct prestera_msg_bridge_req { |
396 | struct prestera_msg_cmd cmd; |
397 | __le32 port; |
398 | __le32 dev; |
399 | __le16 bridge; |
400 | u8 pad[2]; |
401 | }; |
402 | |
403 | struct prestera_msg_bridge_resp { |
404 | struct prestera_msg_ret ret; |
405 | __le16 bridge; |
406 | u8 pad[2]; |
407 | }; |
408 | |
409 | struct prestera_msg_vtcam_create_req { |
410 | struct prestera_msg_cmd cmd; |
411 | __le32 keymask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX]; |
412 | u8 direction; |
413 | u8 lookup; |
414 | u8 pad[2]; |
415 | }; |
416 | |
417 | struct prestera_msg_vtcam_destroy_req { |
418 | struct prestera_msg_cmd cmd; |
419 | __le32 vtcam_id; |
420 | }; |
421 | |
422 | struct prestera_msg_vtcam_rule_add_req { |
423 | struct prestera_msg_cmd cmd; |
424 | __le32 key[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX]; |
425 | __le32 keymask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX]; |
426 | __le32 vtcam_id; |
427 | __le32 prio; |
428 | __le32 n_act; |
429 | }; |
430 | |
431 | struct prestera_msg_vtcam_rule_del_req { |
432 | struct prestera_msg_cmd cmd; |
433 | __le32 vtcam_id; |
434 | __le32 id; |
435 | }; |
436 | |
437 | struct prestera_msg_vtcam_bind_req { |
438 | struct prestera_msg_cmd cmd; |
439 | union { |
440 | struct { |
441 | __le32 hw_id; |
442 | __le32 dev_id; |
443 | } port; |
444 | __le32 index; |
445 | }; |
446 | __le32 vtcam_id; |
447 | __le16 pcl_id; |
448 | __le16 type; |
449 | }; |
450 | |
451 | struct prestera_msg_vtcam_resp { |
452 | struct prestera_msg_ret ret; |
453 | __le32 vtcam_id; |
454 | __le32 rule_id; |
455 | }; |
456 | |
457 | struct prestera_msg_acl_action { |
458 | __le32 id; |
459 | __le32 __reserved; |
460 | union { |
461 | struct { |
462 | __le32 index; |
463 | } jump; |
464 | struct { |
465 | __le32 id; |
466 | } police; |
467 | struct { |
468 | __le32 id; |
469 | } count; |
470 | __le32 reserved[6]; |
471 | }; |
472 | }; |
473 | |
474 | struct prestera_msg_counter_req { |
475 | struct prestera_msg_cmd cmd; |
476 | __le32 client; |
477 | __le32 block_id; |
478 | __le32 num_counters; |
479 | }; |
480 | |
481 | struct prestera_msg_counter_stats { |
482 | __le64 packets; |
483 | __le64 bytes; |
484 | }; |
485 | |
486 | struct prestera_msg_counter_resp { |
487 | struct prestera_msg_ret ret; |
488 | __le32 block_id; |
489 | __le32 offset; |
490 | __le32 num_counters; |
491 | __le32 done; |
492 | struct prestera_msg_counter_stats stats[]; |
493 | }; |
494 | |
495 | struct prestera_msg_span_req { |
496 | struct prestera_msg_cmd cmd; |
497 | __le32 port; |
498 | __le32 dev; |
499 | u8 id; |
500 | u8 pad[3]; |
501 | }; |
502 | |
503 | struct prestera_msg_span_resp { |
504 | struct prestera_msg_ret ret; |
505 | u8 id; |
506 | u8 pad[3]; |
507 | }; |
508 | |
509 | struct prestera_msg_stp_req { |
510 | struct prestera_msg_cmd cmd; |
511 | __le32 port; |
512 | __le32 dev; |
513 | __le16 vid; |
514 | u8 state; |
515 | u8 __pad; |
516 | }; |
517 | |
518 | struct prestera_msg_rxtx_req { |
519 | struct prestera_msg_cmd cmd; |
520 | u8 use_sdma; |
521 | u8 pad[3]; |
522 | }; |
523 | |
524 | struct prestera_msg_rxtx_resp { |
525 | struct prestera_msg_ret ret; |
526 | __le32 map_addr; |
527 | }; |
528 | |
529 | struct prestera_msg_iface { |
530 | union { |
531 | struct { |
532 | __le32 dev; |
533 | __le32 port; |
534 | }; |
535 | __le16 lag_id; |
536 | }; |
537 | __le16 vr_id; |
538 | __le16 vid; |
539 | u8 type; |
540 | u8 __pad[3]; |
541 | }; |
542 | |
543 | struct prestera_msg_ip_addr { |
544 | union { |
545 | __be32 ipv4; |
546 | __be32 ipv6[4]; |
547 | } u; |
548 | u8 v; /* e.g. PRESTERA_IPV4 */ |
549 | u8 __pad[3]; |
550 | }; |
551 | |
552 | struct prestera_msg_nh { |
553 | struct prestera_msg_iface oif; |
554 | __le32 hw_id; |
555 | u8 mac[ETH_ALEN]; |
556 | u8 is_active; |
557 | u8 pad; |
558 | }; |
559 | |
560 | struct prestera_msg_rif_req { |
561 | struct prestera_msg_cmd cmd; |
562 | struct prestera_msg_iface iif; |
563 | __le32 mtu; |
564 | __le16 rif_id; |
565 | __le16 __reserved; |
566 | u8 mac[ETH_ALEN]; |
567 | u8 __pad[2]; |
568 | }; |
569 | |
570 | struct prestera_msg_rif_resp { |
571 | struct prestera_msg_ret ret; |
572 | __le16 rif_id; |
573 | u8 __pad[2]; |
574 | }; |
575 | |
576 | struct prestera_msg_lpm_req { |
577 | struct prestera_msg_cmd cmd; |
578 | struct prestera_msg_ip_addr dst; |
579 | __le32 grp_id; |
580 | __le32 dst_len; |
581 | __le16 vr_id; |
582 | u8 __pad[2]; |
583 | }; |
584 | |
585 | struct prestera_msg_nh_req { |
586 | struct prestera_msg_cmd cmd; |
587 | struct prestera_msg_nh nh[PRESTERA_NHGR_SIZE_MAX]; |
588 | __le32 size; |
589 | __le32 grp_id; |
590 | }; |
591 | |
592 | struct prestera_msg_nh_chunk_req { |
593 | struct prestera_msg_cmd cmd; |
594 | __le32 offset; |
595 | }; |
596 | |
597 | struct prestera_msg_nh_chunk_resp { |
598 | struct prestera_msg_ret ret; |
599 | u8 hw_state[PRESTERA_MSG_CHUNK_SIZE]; |
600 | }; |
601 | |
602 | struct prestera_msg_nh_grp_req { |
603 | struct prestera_msg_cmd cmd; |
604 | __le32 grp_id; |
605 | __le32 size; |
606 | }; |
607 | |
608 | struct prestera_msg_nh_grp_resp { |
609 | struct prestera_msg_ret ret; |
610 | __le32 grp_id; |
611 | }; |
612 | |
613 | struct prestera_msg_vr_req { |
614 | struct prestera_msg_cmd cmd; |
615 | __le16 vr_id; |
616 | u8 __pad[2]; |
617 | }; |
618 | |
619 | struct prestera_msg_vr_resp { |
620 | struct prestera_msg_ret ret; |
621 | __le16 vr_id; |
622 | u8 __pad[2]; |
623 | }; |
624 | |
625 | struct prestera_msg_lag_req { |
626 | struct prestera_msg_cmd cmd; |
627 | __le32 port; |
628 | __le32 dev; |
629 | __le16 lag_id; |
630 | u8 pad[2]; |
631 | }; |
632 | |
633 | struct prestera_msg_cpu_code_counter_req { |
634 | struct prestera_msg_cmd cmd; |
635 | u8 counter_type; |
636 | u8 code; |
637 | u8 pad[2]; |
638 | }; |
639 | |
640 | struct mvsw_msg_cpu_code_counter_ret { |
641 | struct prestera_msg_ret ret; |
642 | __le64 packet_count; |
643 | }; |
644 | |
645 | struct prestera_msg_policer_req { |
646 | struct prestera_msg_cmd cmd; |
647 | __le32 id; |
648 | union { |
649 | struct { |
650 | __le64 cir; |
651 | __le32 cbs; |
652 | } __packed sr_tcm; /* make sure always 12 bytes size */ |
653 | __le32 reserved[6]; |
654 | }; |
655 | u8 mode; |
656 | u8 type; |
657 | u8 pad[2]; |
658 | }; |
659 | |
660 | struct prestera_msg_policer_resp { |
661 | struct prestera_msg_ret ret; |
662 | __le32 id; |
663 | }; |
664 | |
665 | struct prestera_msg_event { |
666 | __le16 type; |
667 | __le16 id; |
668 | }; |
669 | |
670 | struct prestera_msg_event_port { |
671 | struct prestera_msg_event id; |
672 | __le32 port_id; |
673 | struct prestera_msg_event_port_param param; |
674 | }; |
675 | |
676 | union prestera_msg_event_fdb_param { |
677 | u8 mac[ETH_ALEN]; |
678 | }; |
679 | |
680 | struct prestera_msg_event_fdb { |
681 | struct prestera_msg_event id; |
682 | __le32 vid; |
683 | union { |
684 | __le32 port_id; |
685 | __le16 lag_id; |
686 | } dest; |
687 | union prestera_msg_event_fdb_param param; |
688 | u8 dest_type; |
689 | }; |
690 | |
691 | struct prestera_msg_flood_domain_create_req { |
692 | struct prestera_msg_cmd cmd; |
693 | }; |
694 | |
695 | struct prestera_msg_flood_domain_create_resp { |
696 | struct prestera_msg_ret ret; |
697 | __le32 flood_domain_idx; |
698 | }; |
699 | |
700 | struct prestera_msg_flood_domain_destroy_req { |
701 | struct prestera_msg_cmd cmd; |
702 | __le32 flood_domain_idx; |
703 | }; |
704 | |
705 | struct prestera_msg_flood_domain_ports_set_req { |
706 | struct prestera_msg_cmd cmd; |
707 | __le32 flood_domain_idx; |
708 | __le32 ports_num; |
709 | }; |
710 | |
711 | struct prestera_msg_flood_domain_ports_reset_req { |
712 | struct prestera_msg_cmd cmd; |
713 | __le32 flood_domain_idx; |
714 | }; |
715 | |
716 | struct prestera_msg_flood_domain_port { |
717 | union { |
718 | struct { |
719 | __le32 port_num; |
720 | __le32 dev_num; |
721 | }; |
722 | __le16 lag_id; |
723 | }; |
724 | __le16 vid; |
725 | __le16 port_type; |
726 | }; |
727 | |
728 | struct prestera_msg_mdb_create_req { |
729 | struct prestera_msg_cmd cmd; |
730 | __le32 flood_domain_idx; |
731 | __le16 vid; |
732 | u8 mac[ETH_ALEN]; |
733 | }; |
734 | |
735 | struct prestera_msg_mdb_destroy_req { |
736 | struct prestera_msg_cmd cmd; |
737 | __le32 flood_domain_idx; |
738 | __le16 vid; |
739 | u8 mac[ETH_ALEN]; |
740 | }; |
741 | |
742 | static void prestera_hw_build_tests(void) |
743 | { |
744 | /* check requests */ |
745 | BUILD_BUG_ON(sizeof(struct prestera_msg_common_req) != 4); |
746 | BUILD_BUG_ON(sizeof(struct prestera_msg_switch_attr_req) != 16); |
747 | BUILD_BUG_ON(sizeof(struct prestera_msg_port_attr_req) != 144); |
748 | BUILD_BUG_ON(sizeof(struct prestera_msg_port_info_req) != 8); |
749 | BUILD_BUG_ON(sizeof(struct prestera_msg_vlan_req) != 16); |
750 | BUILD_BUG_ON(sizeof(struct prestera_msg_fdb_req) != 28); |
751 | BUILD_BUG_ON(sizeof(struct prestera_msg_bridge_req) != 16); |
752 | BUILD_BUG_ON(sizeof(struct prestera_msg_span_req) != 16); |
753 | BUILD_BUG_ON(sizeof(struct prestera_msg_stp_req) != 16); |
754 | BUILD_BUG_ON(sizeof(struct prestera_msg_rxtx_req) != 8); |
755 | BUILD_BUG_ON(sizeof(struct prestera_msg_lag_req) != 16); |
756 | BUILD_BUG_ON(sizeof(struct prestera_msg_cpu_code_counter_req) != 8); |
757 | BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_create_req) != 84); |
758 | BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_destroy_req) != 8); |
759 | BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_rule_add_req) != 168); |
760 | BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_rule_del_req) != 12); |
761 | BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_bind_req) != 20); |
762 | BUILD_BUG_ON(sizeof(struct prestera_msg_acl_action) != 32); |
763 | BUILD_BUG_ON(sizeof(struct prestera_msg_counter_req) != 16); |
764 | BUILD_BUG_ON(sizeof(struct prestera_msg_counter_stats) != 16); |
765 | BUILD_BUG_ON(sizeof(struct prestera_msg_rif_req) != 36); |
766 | BUILD_BUG_ON(sizeof(struct prestera_msg_vr_req) != 8); |
767 | BUILD_BUG_ON(sizeof(struct prestera_msg_lpm_req) != 36); |
768 | BUILD_BUG_ON(sizeof(struct prestera_msg_policer_req) != 36); |
769 | BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_create_req) != 4); |
770 | BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_destroy_req) != 8); |
771 | BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_ports_set_req) != 12); |
772 | BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_ports_reset_req) != 8); |
773 | BUILD_BUG_ON(sizeof(struct prestera_msg_mdb_create_req) != 16); |
774 | BUILD_BUG_ON(sizeof(struct prestera_msg_mdb_destroy_req) != 16); |
775 | BUILD_BUG_ON(sizeof(struct prestera_msg_nh_req) != 124); |
776 | BUILD_BUG_ON(sizeof(struct prestera_msg_nh_chunk_req) != 8); |
777 | BUILD_BUG_ON(sizeof(struct prestera_msg_nh_grp_req) != 12); |
778 | |
779 | /* structure that are part of req/resp fw messages */ |
780 | BUILD_BUG_ON(sizeof(struct prestera_msg_iface) != 16); |
781 | BUILD_BUG_ON(sizeof(struct prestera_msg_ip_addr) != 20); |
782 | BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_port) != 12); |
783 | BUILD_BUG_ON(sizeof(struct prestera_msg_nh) != 28); |
784 | |
785 | /* check responses */ |
786 | BUILD_BUG_ON(sizeof(struct prestera_msg_common_resp) != 8); |
787 | BUILD_BUG_ON(sizeof(struct prestera_msg_switch_init_resp) != 24); |
788 | BUILD_BUG_ON(sizeof(struct prestera_msg_port_attr_resp) != 136); |
789 | BUILD_BUG_ON(sizeof(struct prestera_msg_port_stats_resp) != 248); |
790 | BUILD_BUG_ON(sizeof(struct prestera_msg_port_info_resp) != 20); |
791 | BUILD_BUG_ON(sizeof(struct prestera_msg_bridge_resp) != 12); |
792 | BUILD_BUG_ON(sizeof(struct prestera_msg_span_resp) != 12); |
793 | BUILD_BUG_ON(sizeof(struct prestera_msg_rxtx_resp) != 12); |
794 | BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_resp) != 16); |
795 | BUILD_BUG_ON(sizeof(struct prestera_msg_counter_resp) != 24); |
796 | BUILD_BUG_ON(sizeof(struct prestera_msg_rif_resp) != 12); |
797 | BUILD_BUG_ON(sizeof(struct prestera_msg_vr_resp) != 12); |
798 | BUILD_BUG_ON(sizeof(struct prestera_msg_policer_resp) != 12); |
799 | BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_create_resp) != 12); |
800 | BUILD_BUG_ON(sizeof(struct prestera_msg_nh_chunk_resp) != 1032); |
801 | BUILD_BUG_ON(sizeof(struct prestera_msg_nh_grp_resp) != 12); |
802 | |
803 | /* check events */ |
804 | BUILD_BUG_ON(sizeof(struct prestera_msg_event_port) != 20); |
805 | BUILD_BUG_ON(sizeof(struct prestera_msg_event_fdb) != 20); |
806 | } |
807 | |
808 | static u8 prestera_hw_mdix_to_eth(u8 mode); |
809 | static void prestera_hw_remote_fc_to_eth(u8 fc, bool *pause, bool *asym_pause); |
810 | |
811 | static int __prestera_cmd_ret(struct prestera_switch *sw, |
812 | enum prestera_cmd_type_t type, |
813 | struct prestera_msg_cmd *cmd, size_t clen, |
814 | struct prestera_msg_ret *ret, size_t rlen, |
815 | int waitms) |
816 | { |
817 | struct prestera_device *dev = sw->dev; |
818 | int err; |
819 | |
820 | cmd->type = __cpu_to_le32(type); |
821 | |
822 | err = dev->send_req(dev, 0, cmd, clen, ret, rlen, waitms); |
823 | if (err) |
824 | return err; |
825 | |
826 | if (ret->cmd.type != __cpu_to_le32(PRESTERA_CMD_TYPE_ACK)) |
827 | return -EBADE; |
828 | if (ret->status != __cpu_to_le32(PRESTERA_CMD_ACK_OK)) |
829 | return -EINVAL; |
830 | |
831 | return 0; |
832 | } |
833 | |
834 | static int prestera_cmd_ret(struct prestera_switch *sw, |
835 | enum prestera_cmd_type_t type, |
836 | struct prestera_msg_cmd *cmd, size_t clen, |
837 | struct prestera_msg_ret *ret, size_t rlen) |
838 | { |
839 | return __prestera_cmd_ret(sw, type, cmd, clen, ret, rlen, waitms: 0); |
840 | } |
841 | |
842 | static int prestera_cmd_ret_wait(struct prestera_switch *sw, |
843 | enum prestera_cmd_type_t type, |
844 | struct prestera_msg_cmd *cmd, size_t clen, |
845 | struct prestera_msg_ret *ret, size_t rlen, |
846 | int waitms) |
847 | { |
848 | return __prestera_cmd_ret(sw, type, cmd, clen, ret, rlen, waitms); |
849 | } |
850 | |
851 | static int prestera_cmd(struct prestera_switch *sw, |
852 | enum prestera_cmd_type_t type, |
853 | struct prestera_msg_cmd *cmd, size_t clen) |
854 | { |
855 | struct prestera_msg_common_resp resp; |
856 | |
857 | return prestera_cmd_ret(sw, type, cmd, clen, ret: &resp.ret, rlen: sizeof(resp)); |
858 | } |
859 | |
860 | static int prestera_fw_parse_port_evt(void *msg, struct prestera_event *evt) |
861 | { |
862 | struct prestera_msg_event_port *hw_evt; |
863 | |
864 | hw_evt = (struct prestera_msg_event_port *)msg; |
865 | |
866 | evt->port_evt.port_id = __le32_to_cpu(hw_evt->port_id); |
867 | |
868 | if (evt->id == PRESTERA_PORT_EVENT_MAC_STATE_CHANGED) { |
869 | evt->port_evt.data.mac.oper = hw_evt->param.mac.oper; |
870 | evt->port_evt.data.mac.mode = |
871 | __le32_to_cpu(hw_evt->param.mac.mode); |
872 | evt->port_evt.data.mac.speed = |
873 | __le32_to_cpu(hw_evt->param.mac.speed); |
874 | evt->port_evt.data.mac.duplex = hw_evt->param.mac.duplex; |
875 | evt->port_evt.data.mac.fc = hw_evt->param.mac.fc; |
876 | evt->port_evt.data.mac.fec = hw_evt->param.mac.fec; |
877 | } else { |
878 | return -EINVAL; |
879 | } |
880 | |
881 | return 0; |
882 | } |
883 | |
884 | static int prestera_fw_parse_fdb_evt(void *msg, struct prestera_event *evt) |
885 | { |
886 | struct prestera_msg_event_fdb *hw_evt = msg; |
887 | |
888 | switch (hw_evt->dest_type) { |
889 | case PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT: |
890 | evt->fdb_evt.type = PRESTERA_FDB_ENTRY_TYPE_REG_PORT; |
891 | evt->fdb_evt.dest.port_id = __le32_to_cpu(hw_evt->dest.port_id); |
892 | break; |
893 | case PRESTERA_HW_FDB_ENTRY_TYPE_LAG: |
894 | evt->fdb_evt.type = PRESTERA_FDB_ENTRY_TYPE_LAG; |
895 | evt->fdb_evt.dest.lag_id = __le16_to_cpu(hw_evt->dest.lag_id); |
896 | break; |
897 | default: |
898 | return -EINVAL; |
899 | } |
900 | |
901 | evt->fdb_evt.vid = __le32_to_cpu(hw_evt->vid); |
902 | |
903 | ether_addr_copy(dst: evt->fdb_evt.data.mac, src: hw_evt->param.mac); |
904 | |
905 | return 0; |
906 | } |
907 | |
908 | static struct prestera_fw_evt_parser { |
909 | int (*func)(void *msg, struct prestera_event *evt); |
910 | } fw_event_parsers[PRESTERA_EVENT_TYPE_MAX] = { |
911 | [PRESTERA_EVENT_TYPE_PORT] = { .func = prestera_fw_parse_port_evt }, |
912 | [PRESTERA_EVENT_TYPE_FDB] = { .func = prestera_fw_parse_fdb_evt }, |
913 | }; |
914 | |
915 | static struct prestera_fw_event_handler * |
916 | __find_event_handler(const struct prestera_switch *sw, |
917 | enum prestera_event_type type) |
918 | { |
919 | struct prestera_fw_event_handler *eh; |
920 | |
921 | list_for_each_entry_rcu(eh, &sw->event_handlers, list) { |
922 | if (eh->type == type) |
923 | return eh; |
924 | } |
925 | |
926 | return NULL; |
927 | } |
928 | |
929 | static int prestera_find_event_handler(const struct prestera_switch *sw, |
930 | enum prestera_event_type type, |
931 | struct prestera_fw_event_handler *eh) |
932 | { |
933 | struct prestera_fw_event_handler *tmp; |
934 | int err = 0; |
935 | |
936 | rcu_read_lock(); |
937 | tmp = __find_event_handler(sw, type); |
938 | if (tmp) |
939 | *eh = *tmp; |
940 | else |
941 | err = -ENOENT; |
942 | rcu_read_unlock(); |
943 | |
944 | return err; |
945 | } |
946 | |
947 | static int prestera_evt_recv(struct prestera_device *dev, void *buf, size_t size) |
948 | { |
949 | struct prestera_switch *sw = dev->priv; |
950 | struct prestera_msg_event *msg = buf; |
951 | struct prestera_fw_event_handler eh; |
952 | struct prestera_event evt; |
953 | u16 msg_type; |
954 | int err; |
955 | |
956 | msg_type = __le16_to_cpu(msg->type); |
957 | if (msg_type >= PRESTERA_EVENT_TYPE_MAX) |
958 | return -EINVAL; |
959 | if (!fw_event_parsers[msg_type].func) |
960 | return -ENOENT; |
961 | |
962 | err = prestera_find_event_handler(sw, type: msg_type, eh: &eh); |
963 | if (err) |
964 | return err; |
965 | |
966 | evt.id = __le16_to_cpu(msg->id); |
967 | |
968 | err = fw_event_parsers[msg_type].func(buf, &evt); |
969 | if (err) |
970 | return err; |
971 | |
972 | eh.func(sw, &evt, eh.arg); |
973 | |
974 | return 0; |
975 | } |
976 | |
977 | static void prestera_pkt_recv(struct prestera_device *dev) |
978 | { |
979 | struct prestera_switch *sw = dev->priv; |
980 | struct prestera_fw_event_handler eh; |
981 | struct prestera_event ev; |
982 | int err; |
983 | |
984 | ev.id = PRESTERA_RXTX_EVENT_RCV_PKT; |
985 | |
986 | err = prestera_find_event_handler(sw, type: PRESTERA_EVENT_TYPE_RXTX, eh: &eh); |
987 | if (err) |
988 | return; |
989 | |
990 | eh.func(sw, &ev, eh.arg); |
991 | } |
992 | |
993 | static u8 prestera_hw_mdix_to_eth(u8 mode) |
994 | { |
995 | switch (mode) { |
996 | case PRESTERA_PORT_TP_MDI: |
997 | return ETH_TP_MDI; |
998 | case PRESTERA_PORT_TP_MDIX: |
999 | return ETH_TP_MDI_X; |
1000 | case PRESTERA_PORT_TP_AUTO: |
1001 | return ETH_TP_MDI_AUTO; |
1002 | default: |
1003 | return ETH_TP_MDI_INVALID; |
1004 | } |
1005 | } |
1006 | |
1007 | static u8 prestera_hw_mdix_from_eth(u8 mode) |
1008 | { |
1009 | switch (mode) { |
1010 | case ETH_TP_MDI: |
1011 | return PRESTERA_PORT_TP_MDI; |
1012 | case ETH_TP_MDI_X: |
1013 | return PRESTERA_PORT_TP_MDIX; |
1014 | case ETH_TP_MDI_AUTO: |
1015 | return PRESTERA_PORT_TP_AUTO; |
1016 | default: |
1017 | return PRESTERA_PORT_TP_NA; |
1018 | } |
1019 | } |
1020 | |
1021 | int prestera_hw_port_info_get(const struct prestera_port *port, |
1022 | u32 *dev_id, u32 *hw_id, u16 *fp_id) |
1023 | { |
1024 | struct prestera_msg_port_info_req req = { |
1025 | .port = __cpu_to_le32(port->id), |
1026 | }; |
1027 | struct prestera_msg_port_info_resp resp; |
1028 | int err; |
1029 | |
1030 | err = prestera_cmd_ret(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_INFO_GET, |
1031 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
1032 | if (err) |
1033 | return err; |
1034 | |
1035 | *dev_id = __le32_to_cpu(resp.dev_id); |
1036 | *hw_id = __le32_to_cpu(resp.hw_id); |
1037 | *fp_id = __le16_to_cpu(resp.fp_id); |
1038 | |
1039 | return 0; |
1040 | } |
1041 | |
1042 | int prestera_hw_switch_mac_set(struct prestera_switch *sw, const char *mac) |
1043 | { |
1044 | struct prestera_msg_switch_attr_req req = { |
1045 | .attr = __cpu_to_le32(PRESTERA_CMD_SWITCH_ATTR_MAC), |
1046 | }; |
1047 | |
1048 | ether_addr_copy(dst: req.param.mac, src: mac); |
1049 | |
1050 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_SWITCH_ATTR_SET, |
1051 | cmd: &req.cmd, clen: sizeof(req)); |
1052 | } |
1053 | |
1054 | int prestera_hw_switch_init(struct prestera_switch *sw) |
1055 | { |
1056 | struct prestera_msg_switch_init_resp resp; |
1057 | struct prestera_msg_common_req req; |
1058 | int err; |
1059 | |
1060 | INIT_LIST_HEAD(list: &sw->event_handlers); |
1061 | |
1062 | prestera_hw_build_tests(); |
1063 | |
1064 | err = prestera_cmd_ret_wait(sw, type: PRESTERA_CMD_TYPE_SWITCH_INIT, |
1065 | cmd: &req.cmd, clen: sizeof(req), |
1066 | ret: &resp.ret, rlen: sizeof(resp), |
1067 | PRESTERA_SWITCH_INIT_TIMEOUT_MS); |
1068 | if (err) |
1069 | return err; |
1070 | |
1071 | sw->dev->recv_msg = prestera_evt_recv; |
1072 | sw->dev->recv_pkt = prestera_pkt_recv; |
1073 | sw->port_count = __le32_to_cpu(resp.port_count); |
1074 | sw->mtu_min = PRESTERA_MIN_MTU; |
1075 | sw->mtu_max = __le32_to_cpu(resp.mtu_max); |
1076 | sw->id = resp.switch_id; |
1077 | sw->lag_member_max = resp.lag_member_max; |
1078 | sw->lag_max = resp.lag_max; |
1079 | sw->size_tbl_router_nexthop = |
1080 | __le32_to_cpu(resp.size_tbl_router_nexthop); |
1081 | |
1082 | return 0; |
1083 | } |
1084 | |
1085 | void prestera_hw_switch_fini(struct prestera_switch *sw) |
1086 | { |
1087 | WARN_ON(!list_empty(&sw->event_handlers)); |
1088 | } |
1089 | |
1090 | int prestera_hw_switch_ageing_set(struct prestera_switch *sw, u32 ageing_ms) |
1091 | { |
1092 | struct prestera_msg_switch_attr_req req = { |
1093 | .attr = __cpu_to_le32(PRESTERA_CMD_SWITCH_ATTR_AGEING), |
1094 | .param = { |
1095 | .ageing_timeout_ms = __cpu_to_le32(ageing_ms), |
1096 | }, |
1097 | }; |
1098 | |
1099 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_SWITCH_ATTR_SET, |
1100 | cmd: &req.cmd, clen: sizeof(req)); |
1101 | } |
1102 | |
1103 | int prestera_hw_port_mac_mode_get(const struct prestera_port *port, |
1104 | u32 *mode, u32 *speed, u8 *duplex, u8 *fec) |
1105 | { |
1106 | struct prestera_msg_port_attr_resp resp; |
1107 | struct prestera_msg_port_attr_req req = { |
1108 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_MAC_MODE), |
1109 | .port = __cpu_to_le32(port->hw_id), |
1110 | .dev = __cpu_to_le32(port->dev_id) |
1111 | }; |
1112 | int err; |
1113 | |
1114 | err = prestera_cmd_ret(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_GET, |
1115 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
1116 | if (err) |
1117 | return err; |
1118 | |
1119 | if (mode) |
1120 | *mode = __le32_to_cpu(resp.param.link_evt.mac.mode); |
1121 | |
1122 | if (speed) |
1123 | *speed = __le32_to_cpu(resp.param.link_evt.mac.speed); |
1124 | |
1125 | if (duplex) |
1126 | *duplex = resp.param.link_evt.mac.duplex; |
1127 | |
1128 | if (fec) |
1129 | *fec = resp.param.link_evt.mac.fec; |
1130 | |
1131 | return err; |
1132 | } |
1133 | |
1134 | int prestera_hw_port_mac_mode_set(const struct prestera_port *port, |
1135 | bool admin, u32 mode, u8 inband, |
1136 | u32 speed, u8 duplex, u8 fec) |
1137 | { |
1138 | struct prestera_msg_port_attr_req req = { |
1139 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_MAC_MODE), |
1140 | .port = __cpu_to_le32(port->hw_id), |
1141 | .dev = __cpu_to_le32(port->dev_id), |
1142 | .param = { |
1143 | .link = { |
1144 | .mac = { |
1145 | .admin = admin, |
1146 | .reg_mode.mode = __cpu_to_le32(mode), |
1147 | .reg_mode.inband = inband, |
1148 | .reg_mode.speed = __cpu_to_le32(speed), |
1149 | .reg_mode.duplex = duplex, |
1150 | .reg_mode.fec = fec |
1151 | } |
1152 | } |
1153 | } |
1154 | }; |
1155 | |
1156 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_SET, |
1157 | cmd: &req.cmd, clen: sizeof(req)); |
1158 | } |
1159 | |
1160 | int prestera_hw_port_phy_mode_get(const struct prestera_port *port, |
1161 | u8 *mdix, u64 *lmode_bmap, |
1162 | bool *fc_pause, bool *fc_asym) |
1163 | { |
1164 | struct prestera_msg_port_attr_resp resp; |
1165 | struct prestera_msg_port_attr_req req = { |
1166 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_PHY_MODE), |
1167 | .port = __cpu_to_le32(port->hw_id), |
1168 | .dev = __cpu_to_le32(port->dev_id) |
1169 | }; |
1170 | int err; |
1171 | |
1172 | err = prestera_cmd_ret(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_GET, |
1173 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
1174 | if (err) |
1175 | return err; |
1176 | |
1177 | if (mdix) |
1178 | *mdix = prestera_hw_mdix_to_eth(mode: resp.param.link_evt.phy.mdix); |
1179 | |
1180 | if (lmode_bmap) |
1181 | *lmode_bmap = __le64_to_cpu(resp.param.link_evt.phy.lmode_bmap); |
1182 | |
1183 | if (fc_pause && fc_asym) |
1184 | prestera_hw_remote_fc_to_eth(fc: resp.param.link_evt.phy.fc, |
1185 | pause: fc_pause, asym_pause: fc_asym); |
1186 | |
1187 | return err; |
1188 | } |
1189 | |
1190 | int prestera_hw_port_phy_mode_set(const struct prestera_port *port, |
1191 | bool admin, bool adv, u32 mode, u64 modes, |
1192 | u8 mdix) |
1193 | { |
1194 | struct prestera_msg_port_attr_req req = { |
1195 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_PHY_MODE), |
1196 | .port = __cpu_to_le32(port->hw_id), |
1197 | .dev = __cpu_to_le32(port->dev_id), |
1198 | .param = { |
1199 | .link = { |
1200 | .phy = { |
1201 | .admin = admin, |
1202 | .adv_enable = adv ? 1 : 0, |
1203 | .mode = __cpu_to_le32(mode), |
1204 | .modes = __cpu_to_le64(modes), |
1205 | } |
1206 | } |
1207 | } |
1208 | }; |
1209 | |
1210 | req.param.link.phy.mdix = prestera_hw_mdix_from_eth(mode: mdix); |
1211 | |
1212 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_SET, |
1213 | cmd: &req.cmd, clen: sizeof(req)); |
1214 | } |
1215 | |
1216 | int prestera_hw_port_mtu_set(const struct prestera_port *port, u32 mtu) |
1217 | { |
1218 | struct prestera_msg_port_attr_req req = { |
1219 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_MTU), |
1220 | .port = __cpu_to_le32(port->hw_id), |
1221 | .dev = __cpu_to_le32(port->dev_id), |
1222 | .param = { |
1223 | .mtu = __cpu_to_le32(mtu), |
1224 | } |
1225 | }; |
1226 | |
1227 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_SET, |
1228 | cmd: &req.cmd, clen: sizeof(req)); |
1229 | } |
1230 | |
1231 | int prestera_hw_port_mac_set(const struct prestera_port *port, const char *mac) |
1232 | { |
1233 | struct prestera_msg_port_attr_req req = { |
1234 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_MAC), |
1235 | .port = __cpu_to_le32(port->hw_id), |
1236 | .dev = __cpu_to_le32(port->dev_id), |
1237 | }; |
1238 | |
1239 | ether_addr_copy(dst: req.param.mac, src: mac); |
1240 | |
1241 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_SET, |
1242 | cmd: &req.cmd, clen: sizeof(req)); |
1243 | } |
1244 | |
1245 | int prestera_hw_port_accept_frm_type(struct prestera_port *port, |
1246 | enum prestera_accept_frm_type type) |
1247 | { |
1248 | struct prestera_msg_port_attr_req req = { |
1249 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_ACCEPT_FRAME_TYPE), |
1250 | .port = __cpu_to_le32(port->hw_id), |
1251 | .dev = __cpu_to_le32(port->dev_id), |
1252 | .param = { |
1253 | .accept_frm_type = type, |
1254 | } |
1255 | }; |
1256 | |
1257 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_SET, |
1258 | cmd: &req.cmd, clen: sizeof(req)); |
1259 | } |
1260 | |
1261 | int prestera_hw_port_cap_get(const struct prestera_port *port, |
1262 | struct prestera_port_caps *caps) |
1263 | { |
1264 | struct prestera_msg_port_attr_req req = { |
1265 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_CAPABILITY), |
1266 | .port = __cpu_to_le32(port->hw_id), |
1267 | .dev = __cpu_to_le32(port->dev_id), |
1268 | }; |
1269 | struct prestera_msg_port_attr_resp resp; |
1270 | int err; |
1271 | |
1272 | err = prestera_cmd_ret(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_GET, |
1273 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
1274 | if (err) |
1275 | return err; |
1276 | |
1277 | caps->supp_link_modes = __le64_to_cpu(resp.param.cap.link_mode); |
1278 | caps->transceiver = resp.param.cap.transceiver; |
1279 | caps->supp_fec = resp.param.cap.fec; |
1280 | caps->type = resp.param.cap.type; |
1281 | |
1282 | return err; |
1283 | } |
1284 | |
1285 | static void prestera_hw_remote_fc_to_eth(u8 fc, bool *pause, bool *asym_pause) |
1286 | { |
1287 | switch (fc) { |
1288 | case PRESTERA_FC_SYMMETRIC: |
1289 | *pause = true; |
1290 | *asym_pause = false; |
1291 | break; |
1292 | case PRESTERA_FC_ASYMMETRIC: |
1293 | *pause = false; |
1294 | *asym_pause = true; |
1295 | break; |
1296 | case PRESTERA_FC_SYMM_ASYMM: |
1297 | *pause = true; |
1298 | *asym_pause = true; |
1299 | break; |
1300 | default: |
1301 | *pause = false; |
1302 | *asym_pause = false; |
1303 | } |
1304 | } |
1305 | |
1306 | int prestera_hw_vtcam_create(struct prestera_switch *sw, |
1307 | u8 lookup, const u32 *keymask, u32 *vtcam_id, |
1308 | enum prestera_hw_vtcam_direction_t dir) |
1309 | { |
1310 | int err; |
1311 | struct prestera_msg_vtcam_resp resp; |
1312 | struct prestera_msg_vtcam_create_req req = { |
1313 | .lookup = lookup, |
1314 | .direction = dir, |
1315 | }; |
1316 | |
1317 | if (keymask) |
1318 | memcpy(req.keymask, keymask, sizeof(req.keymask)); |
1319 | else |
1320 | memset(req.keymask, 0, sizeof(req.keymask)); |
1321 | |
1322 | err = prestera_cmd_ret(sw, type: PRESTERA_CMD_TYPE_VTCAM_CREATE, |
1323 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
1324 | if (err) |
1325 | return err; |
1326 | |
1327 | *vtcam_id = __le32_to_cpu(resp.vtcam_id); |
1328 | return 0; |
1329 | } |
1330 | |
1331 | int prestera_hw_vtcam_destroy(struct prestera_switch *sw, u32 vtcam_id) |
1332 | { |
1333 | struct prestera_msg_vtcam_destroy_req req = { |
1334 | .vtcam_id = __cpu_to_le32(vtcam_id), |
1335 | }; |
1336 | |
1337 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_VTCAM_DESTROY, |
1338 | cmd: &req.cmd, clen: sizeof(req)); |
1339 | } |
1340 | |
1341 | static int |
1342 | prestera_acl_rule_add_put_action(struct prestera_msg_acl_action *action, |
1343 | struct prestera_acl_hw_action_info *info) |
1344 | { |
1345 | action->id = __cpu_to_le32(info->id); |
1346 | |
1347 | switch (info->id) { |
1348 | case PRESTERA_ACL_RULE_ACTION_ACCEPT: |
1349 | case PRESTERA_ACL_RULE_ACTION_DROP: |
1350 | case PRESTERA_ACL_RULE_ACTION_TRAP: |
1351 | /* just rule action id, no specific data */ |
1352 | break; |
1353 | case PRESTERA_ACL_RULE_ACTION_JUMP: |
1354 | action->jump.index = __cpu_to_le32(info->jump.index); |
1355 | break; |
1356 | case PRESTERA_ACL_RULE_ACTION_POLICE: |
1357 | action->police.id = __cpu_to_le32(info->police.id); |
1358 | break; |
1359 | case PRESTERA_ACL_RULE_ACTION_COUNT: |
1360 | action->count.id = __cpu_to_le32(info->count.id); |
1361 | break; |
1362 | default: |
1363 | return -EINVAL; |
1364 | } |
1365 | |
1366 | return 0; |
1367 | } |
1368 | |
1369 | int prestera_hw_vtcam_rule_add(struct prestera_switch *sw, |
1370 | u32 vtcam_id, u32 prio, void *key, void *keymask, |
1371 | struct prestera_acl_hw_action_info *act, |
1372 | u8 n_act, u32 *rule_id) |
1373 | { |
1374 | struct prestera_msg_acl_action *actions_msg; |
1375 | struct prestera_msg_vtcam_rule_add_req *req; |
1376 | struct prestera_msg_vtcam_resp resp; |
1377 | void *buff; |
1378 | u32 size; |
1379 | int err; |
1380 | u8 i; |
1381 | |
1382 | size = sizeof(*req) + sizeof(*actions_msg) * n_act; |
1383 | |
1384 | buff = kzalloc(size, GFP_KERNEL); |
1385 | if (!buff) |
1386 | return -ENOMEM; |
1387 | |
1388 | req = buff; |
1389 | req->n_act = __cpu_to_le32(n_act); |
1390 | actions_msg = buff + sizeof(*req); |
1391 | |
1392 | /* put acl matches into the message */ |
1393 | memcpy(req->key, key, sizeof(req->key)); |
1394 | memcpy(req->keymask, keymask, sizeof(req->keymask)); |
1395 | |
1396 | /* put acl actions into the message */ |
1397 | for (i = 0; i < n_act; i++) { |
1398 | err = prestera_acl_rule_add_put_action(action: &actions_msg[i], |
1399 | info: &act[i]); |
1400 | if (err) |
1401 | goto free_buff; |
1402 | } |
1403 | |
1404 | req->vtcam_id = __cpu_to_le32(vtcam_id); |
1405 | req->prio = __cpu_to_le32(prio); |
1406 | |
1407 | err = prestera_cmd_ret(sw, type: PRESTERA_CMD_TYPE_VTCAM_RULE_ADD, |
1408 | cmd: &req->cmd, clen: size, ret: &resp.ret, rlen: sizeof(resp)); |
1409 | if (err) |
1410 | goto free_buff; |
1411 | |
1412 | *rule_id = __le32_to_cpu(resp.rule_id); |
1413 | free_buff: |
1414 | kfree(objp: buff); |
1415 | return err; |
1416 | } |
1417 | |
1418 | int prestera_hw_vtcam_rule_del(struct prestera_switch *sw, |
1419 | u32 vtcam_id, u32 rule_id) |
1420 | { |
1421 | struct prestera_msg_vtcam_rule_del_req req = { |
1422 | .vtcam_id = __cpu_to_le32(vtcam_id), |
1423 | .id = __cpu_to_le32(rule_id) |
1424 | }; |
1425 | |
1426 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_VTCAM_RULE_DELETE, |
1427 | cmd: &req.cmd, clen: sizeof(req)); |
1428 | } |
1429 | |
1430 | int prestera_hw_vtcam_iface_bind(struct prestera_switch *sw, |
1431 | struct prestera_acl_iface *iface, |
1432 | u32 vtcam_id, u16 pcl_id) |
1433 | { |
1434 | struct prestera_msg_vtcam_bind_req req = { |
1435 | .vtcam_id = __cpu_to_le32(vtcam_id), |
1436 | .type = __cpu_to_le16(iface->type), |
1437 | .pcl_id = __cpu_to_le16(pcl_id) |
1438 | }; |
1439 | |
1440 | if (iface->type == PRESTERA_ACL_IFACE_TYPE_PORT) { |
1441 | req.port.dev_id = __cpu_to_le32(iface->port->dev_id); |
1442 | req.port.hw_id = __cpu_to_le32(iface->port->hw_id); |
1443 | } else { |
1444 | req.index = __cpu_to_le32(iface->index); |
1445 | } |
1446 | |
1447 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_VTCAM_IFACE_BIND, |
1448 | cmd: &req.cmd, clen: sizeof(req)); |
1449 | } |
1450 | |
1451 | int prestera_hw_vtcam_iface_unbind(struct prestera_switch *sw, |
1452 | struct prestera_acl_iface *iface, |
1453 | u32 vtcam_id) |
1454 | { |
1455 | struct prestera_msg_vtcam_bind_req req = { |
1456 | .vtcam_id = __cpu_to_le32(vtcam_id), |
1457 | .type = __cpu_to_le16(iface->type) |
1458 | }; |
1459 | |
1460 | if (iface->type == PRESTERA_ACL_IFACE_TYPE_PORT) { |
1461 | req.port.dev_id = __cpu_to_le32(iface->port->dev_id); |
1462 | req.port.hw_id = __cpu_to_le32(iface->port->hw_id); |
1463 | } else { |
1464 | req.index = __cpu_to_le32(iface->index); |
1465 | } |
1466 | |
1467 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_VTCAM_IFACE_UNBIND, |
1468 | cmd: &req.cmd, clen: sizeof(req)); |
1469 | } |
1470 | |
1471 | int prestera_hw_span_get(const struct prestera_port *port, u8 *span_id) |
1472 | { |
1473 | struct prestera_msg_span_resp resp; |
1474 | struct prestera_msg_span_req req = { |
1475 | .port = __cpu_to_le32(port->hw_id), |
1476 | .dev = __cpu_to_le32(port->dev_id), |
1477 | }; |
1478 | int err; |
1479 | |
1480 | err = prestera_cmd_ret(sw: port->sw, type: PRESTERA_CMD_TYPE_SPAN_GET, |
1481 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
1482 | if (err) |
1483 | return err; |
1484 | |
1485 | *span_id = resp.id; |
1486 | |
1487 | return 0; |
1488 | } |
1489 | |
1490 | int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id, |
1491 | bool ingress) |
1492 | { |
1493 | struct prestera_msg_span_req req = { |
1494 | .port = __cpu_to_le32(port->hw_id), |
1495 | .dev = __cpu_to_le32(port->dev_id), |
1496 | .id = span_id, |
1497 | }; |
1498 | enum prestera_cmd_type_t cmd_type; |
1499 | |
1500 | if (ingress) |
1501 | cmd_type = PRESTERA_CMD_TYPE_SPAN_INGRESS_BIND; |
1502 | else |
1503 | cmd_type = PRESTERA_CMD_TYPE_SPAN_EGRESS_BIND; |
1504 | |
1505 | return prestera_cmd(sw: port->sw, type: cmd_type, cmd: &req.cmd, clen: sizeof(req)); |
1506 | |
1507 | } |
1508 | |
1509 | int prestera_hw_span_unbind(const struct prestera_port *port, bool ingress) |
1510 | { |
1511 | struct prestera_msg_span_req req = { |
1512 | .port = __cpu_to_le32(port->hw_id), |
1513 | .dev = __cpu_to_le32(port->dev_id), |
1514 | }; |
1515 | enum prestera_cmd_type_t cmd_type; |
1516 | |
1517 | if (ingress) |
1518 | cmd_type = PRESTERA_CMD_TYPE_SPAN_INGRESS_UNBIND; |
1519 | else |
1520 | cmd_type = PRESTERA_CMD_TYPE_SPAN_EGRESS_UNBIND; |
1521 | |
1522 | return prestera_cmd(sw: port->sw, type: cmd_type, cmd: &req.cmd, clen: sizeof(req)); |
1523 | } |
1524 | |
1525 | int prestera_hw_span_release(struct prestera_switch *sw, u8 span_id) |
1526 | { |
1527 | struct prestera_msg_span_req req = { |
1528 | .id = span_id |
1529 | }; |
1530 | |
1531 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_SPAN_RELEASE, |
1532 | cmd: &req.cmd, clen: sizeof(req)); |
1533 | } |
1534 | |
1535 | int prestera_hw_port_type_get(const struct prestera_port *port, u8 *type) |
1536 | { |
1537 | struct prestera_msg_port_attr_req req = { |
1538 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_TYPE), |
1539 | .port = __cpu_to_le32(port->hw_id), |
1540 | .dev = __cpu_to_le32(port->dev_id), |
1541 | }; |
1542 | struct prestera_msg_port_attr_resp resp; |
1543 | int err; |
1544 | |
1545 | err = prestera_cmd_ret(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_GET, |
1546 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
1547 | if (err) |
1548 | return err; |
1549 | |
1550 | *type = resp.param.type; |
1551 | |
1552 | return 0; |
1553 | } |
1554 | |
1555 | int prestera_hw_port_speed_get(const struct prestera_port *port, u32 *speed) |
1556 | { |
1557 | struct prestera_msg_port_attr_req req = { |
1558 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_SPEED), |
1559 | .port = __cpu_to_le32(port->hw_id), |
1560 | .dev = __cpu_to_le32(port->dev_id), |
1561 | }; |
1562 | struct prestera_msg_port_attr_resp resp; |
1563 | int err; |
1564 | |
1565 | err = prestera_cmd_ret(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_GET, |
1566 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
1567 | if (err) |
1568 | return err; |
1569 | |
1570 | *speed = __le32_to_cpu(resp.param.speed); |
1571 | |
1572 | return 0; |
1573 | } |
1574 | |
1575 | int prestera_hw_port_autoneg_restart(struct prestera_port *port) |
1576 | { |
1577 | struct prestera_msg_port_attr_req req = { |
1578 | .attr = |
1579 | __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_PHY_AUTONEG_RESTART), |
1580 | .port = __cpu_to_le32(port->hw_id), |
1581 | .dev = __cpu_to_le32(port->dev_id), |
1582 | }; |
1583 | |
1584 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_SET, |
1585 | cmd: &req.cmd, clen: sizeof(req)); |
1586 | } |
1587 | |
1588 | int prestera_hw_port_stats_get(const struct prestera_port *port, |
1589 | struct prestera_port_stats *st) |
1590 | { |
1591 | struct prestera_msg_port_attr_req req = { |
1592 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_STATS), |
1593 | .port = __cpu_to_le32(port->hw_id), |
1594 | .dev = __cpu_to_le32(port->dev_id), |
1595 | }; |
1596 | struct prestera_msg_port_stats_resp resp; |
1597 | __le64 *hw = resp.stats; |
1598 | int err; |
1599 | |
1600 | err = prestera_cmd_ret(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_GET, |
1601 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
1602 | if (err) |
1603 | return err; |
1604 | |
1605 | st->good_octets_received = |
1606 | __le64_to_cpu(hw[PRESTERA_PORT_GOOD_OCTETS_RCV_CNT]); |
1607 | st->bad_octets_received = |
1608 | __le64_to_cpu(hw[PRESTERA_PORT_BAD_OCTETS_RCV_CNT]); |
1609 | st->mac_trans_error = |
1610 | __le64_to_cpu(hw[PRESTERA_PORT_MAC_TRANSMIT_ERR_CNT]); |
1611 | st->broadcast_frames_received = |
1612 | __le64_to_cpu(hw[PRESTERA_PORT_BRDC_PKTS_RCV_CNT]); |
1613 | st->multicast_frames_received = |
1614 | __le64_to_cpu(hw[PRESTERA_PORT_MC_PKTS_RCV_CNT]); |
1615 | st->frames_64_octets = __le64_to_cpu(hw[PRESTERA_PORT_PKTS_64L_CNT]); |
1616 | st->frames_65_to_127_octets = |
1617 | __le64_to_cpu(hw[PRESTERA_PORT_PKTS_65TO127L_CNT]); |
1618 | st->frames_128_to_255_octets = |
1619 | __le64_to_cpu(hw[PRESTERA_PORT_PKTS_128TO255L_CNT]); |
1620 | st->frames_256_to_511_octets = |
1621 | __le64_to_cpu(hw[PRESTERA_PORT_PKTS_256TO511L_CNT]); |
1622 | st->frames_512_to_1023_octets = |
1623 | __le64_to_cpu(hw[PRESTERA_PORT_PKTS_512TO1023L_CNT]); |
1624 | st->frames_1024_to_max_octets = |
1625 | __le64_to_cpu(hw[PRESTERA_PORT_PKTS_1024TOMAXL_CNT]); |
1626 | st->excessive_collision = |
1627 | __le64_to_cpu(hw[PRESTERA_PORT_EXCESSIVE_COLLISIONS_CNT]); |
1628 | st->multicast_frames_sent = |
1629 | __le64_to_cpu(hw[PRESTERA_PORT_MC_PKTS_SENT_CNT]); |
1630 | st->broadcast_frames_sent = |
1631 | __le64_to_cpu(hw[PRESTERA_PORT_BRDC_PKTS_SENT_CNT]); |
1632 | st->fc_sent = __le64_to_cpu(hw[PRESTERA_PORT_FC_SENT_CNT]); |
1633 | st->fc_received = __le64_to_cpu(hw[PRESTERA_PORT_GOOD_FC_RCV_CNT]); |
1634 | st->buffer_overrun = __le64_to_cpu(hw[PRESTERA_PORT_DROP_EVENTS_CNT]); |
1635 | st->undersize = __le64_to_cpu(hw[PRESTERA_PORT_UNDERSIZE_PKTS_CNT]); |
1636 | st->fragments = __le64_to_cpu(hw[PRESTERA_PORT_FRAGMENTS_PKTS_CNT]); |
1637 | st->oversize = __le64_to_cpu(hw[PRESTERA_PORT_OVERSIZE_PKTS_CNT]); |
1638 | st->jabber = __le64_to_cpu(hw[PRESTERA_PORT_JABBER_PKTS_CNT]); |
1639 | st->rx_error_frame_received = |
1640 | __le64_to_cpu(hw[PRESTERA_PORT_MAC_RCV_ERROR_CNT]); |
1641 | st->bad_crc = __le64_to_cpu(hw[PRESTERA_PORT_BAD_CRC_CNT]); |
1642 | st->collisions = __le64_to_cpu(hw[PRESTERA_PORT_COLLISIONS_CNT]); |
1643 | st->late_collision = |
1644 | __le64_to_cpu(hw[PRESTERA_PORT_LATE_COLLISIONS_CNT]); |
1645 | st->unicast_frames_received = |
1646 | __le64_to_cpu(hw[PRESTERA_PORT_GOOD_UC_PKTS_RCV_CNT]); |
1647 | st->unicast_frames_sent = |
1648 | __le64_to_cpu(hw[PRESTERA_PORT_GOOD_UC_PKTS_SENT_CNT]); |
1649 | st->sent_multiple = |
1650 | __le64_to_cpu(hw[PRESTERA_PORT_MULTIPLE_PKTS_SENT_CNT]); |
1651 | st->sent_deferred = |
1652 | __le64_to_cpu(hw[PRESTERA_PORT_DEFERRED_PKTS_SENT_CNT]); |
1653 | st->good_octets_sent = |
1654 | __le64_to_cpu(hw[PRESTERA_PORT_GOOD_OCTETS_SENT_CNT]); |
1655 | |
1656 | return 0; |
1657 | } |
1658 | |
1659 | int prestera_hw_port_learning_set(struct prestera_port *port, bool enable) |
1660 | { |
1661 | struct prestera_msg_port_attr_req req = { |
1662 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_LEARNING), |
1663 | .port = __cpu_to_le32(port->hw_id), |
1664 | .dev = __cpu_to_le32(port->dev_id), |
1665 | .param = { |
1666 | .learning = enable, |
1667 | } |
1668 | }; |
1669 | |
1670 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_SET, |
1671 | cmd: &req.cmd, clen: sizeof(req)); |
1672 | } |
1673 | |
1674 | int prestera_hw_port_uc_flood_set(const struct prestera_port *port, bool flood) |
1675 | { |
1676 | struct prestera_msg_port_attr_req req = { |
1677 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_FLOOD), |
1678 | .port = __cpu_to_le32(port->hw_id), |
1679 | .dev = __cpu_to_le32(port->dev_id), |
1680 | .param = { |
1681 | .flood_ext = { |
1682 | .type = PRESTERA_PORT_FLOOD_TYPE_UC, |
1683 | .enable = flood, |
1684 | } |
1685 | } |
1686 | }; |
1687 | |
1688 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_SET, |
1689 | cmd: &req.cmd, clen: sizeof(req)); |
1690 | } |
1691 | |
1692 | int prestera_hw_port_mc_flood_set(const struct prestera_port *port, bool flood) |
1693 | { |
1694 | struct prestera_msg_port_attr_req req = { |
1695 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_FLOOD), |
1696 | .port = __cpu_to_le32(port->hw_id), |
1697 | .dev = __cpu_to_le32(port->dev_id), |
1698 | .param = { |
1699 | .flood_ext = { |
1700 | .type = PRESTERA_PORT_FLOOD_TYPE_MC, |
1701 | .enable = flood, |
1702 | } |
1703 | } |
1704 | }; |
1705 | |
1706 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_SET, |
1707 | cmd: &req.cmd, clen: sizeof(req)); |
1708 | } |
1709 | |
1710 | int prestera_hw_port_br_locked_set(const struct prestera_port *port, |
1711 | bool br_locked) |
1712 | { |
1713 | struct prestera_msg_port_attr_req req = { |
1714 | .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_LOCKED), |
1715 | .port = __cpu_to_le32(port->hw_id), |
1716 | .dev = __cpu_to_le32(port->dev_id), |
1717 | .param = { |
1718 | .br_locked = br_locked, |
1719 | } |
1720 | }; |
1721 | |
1722 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_PORT_ATTR_SET, |
1723 | cmd: &req.cmd, clen: sizeof(req)); |
1724 | } |
1725 | |
1726 | int prestera_hw_vlan_create(struct prestera_switch *sw, u16 vid) |
1727 | { |
1728 | struct prestera_msg_vlan_req req = { |
1729 | .vid = __cpu_to_le16(vid), |
1730 | }; |
1731 | |
1732 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_VLAN_CREATE, |
1733 | cmd: &req.cmd, clen: sizeof(req)); |
1734 | } |
1735 | |
1736 | int prestera_hw_vlan_delete(struct prestera_switch *sw, u16 vid) |
1737 | { |
1738 | struct prestera_msg_vlan_req req = { |
1739 | .vid = __cpu_to_le16(vid), |
1740 | }; |
1741 | |
1742 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_VLAN_DELETE, |
1743 | cmd: &req.cmd, clen: sizeof(req)); |
1744 | } |
1745 | |
1746 | int prestera_hw_vlan_port_set(struct prestera_port *port, u16 vid, |
1747 | bool is_member, bool untagged) |
1748 | { |
1749 | struct prestera_msg_vlan_req req = { |
1750 | .port = __cpu_to_le32(port->hw_id), |
1751 | .dev = __cpu_to_le32(port->dev_id), |
1752 | .vid = __cpu_to_le16(vid), |
1753 | .is_member = is_member, |
1754 | .is_tagged = !untagged, |
1755 | }; |
1756 | |
1757 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_VLAN_PORT_SET, |
1758 | cmd: &req.cmd, clen: sizeof(req)); |
1759 | } |
1760 | |
1761 | int prestera_hw_vlan_port_vid_set(struct prestera_port *port, u16 vid) |
1762 | { |
1763 | struct prestera_msg_vlan_req req = { |
1764 | .port = __cpu_to_le32(port->hw_id), |
1765 | .dev = __cpu_to_le32(port->dev_id), |
1766 | .vid = __cpu_to_le16(vid), |
1767 | }; |
1768 | |
1769 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_VLAN_PVID_SET, |
1770 | cmd: &req.cmd, clen: sizeof(req)); |
1771 | } |
1772 | |
1773 | int prestera_hw_vlan_port_stp_set(struct prestera_port *port, u16 vid, u8 state) |
1774 | { |
1775 | struct prestera_msg_stp_req req = { |
1776 | .port = __cpu_to_le32(port->hw_id), |
1777 | .dev = __cpu_to_le32(port->dev_id), |
1778 | .vid = __cpu_to_le16(vid), |
1779 | .state = state, |
1780 | }; |
1781 | |
1782 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_STP_PORT_SET, |
1783 | cmd: &req.cmd, clen: sizeof(req)); |
1784 | } |
1785 | |
1786 | int prestera_hw_fdb_add(struct prestera_port *port, const unsigned char *mac, |
1787 | u16 vid, bool dynamic) |
1788 | { |
1789 | struct prestera_msg_fdb_req req = { |
1790 | .dest = { |
1791 | .dev = __cpu_to_le32(port->dev_id), |
1792 | .port = __cpu_to_le32(port->hw_id), |
1793 | }, |
1794 | .vid = __cpu_to_le16(vid), |
1795 | .dynamic = dynamic, |
1796 | }; |
1797 | |
1798 | ether_addr_copy(dst: req.mac, src: mac); |
1799 | |
1800 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_FDB_ADD, |
1801 | cmd: &req.cmd, clen: sizeof(req)); |
1802 | } |
1803 | |
1804 | int prestera_hw_fdb_del(struct prestera_port *port, const unsigned char *mac, |
1805 | u16 vid) |
1806 | { |
1807 | struct prestera_msg_fdb_req req = { |
1808 | .dest = { |
1809 | .dev = __cpu_to_le32(port->dev_id), |
1810 | .port = __cpu_to_le32(port->hw_id), |
1811 | }, |
1812 | .vid = __cpu_to_le16(vid), |
1813 | }; |
1814 | |
1815 | ether_addr_copy(dst: req.mac, src: mac); |
1816 | |
1817 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_FDB_DELETE, |
1818 | cmd: &req.cmd, clen: sizeof(req)); |
1819 | } |
1820 | |
1821 | int prestera_hw_lag_fdb_add(struct prestera_switch *sw, u16 lag_id, |
1822 | const unsigned char *mac, u16 vid, bool dynamic) |
1823 | { |
1824 | struct prestera_msg_fdb_req req = { |
1825 | .dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG, |
1826 | .dest = { |
1827 | .lag_id = __cpu_to_le16(lag_id), |
1828 | }, |
1829 | .vid = __cpu_to_le16(vid), |
1830 | .dynamic = dynamic, |
1831 | }; |
1832 | |
1833 | ether_addr_copy(dst: req.mac, src: mac); |
1834 | |
1835 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_FDB_ADD, |
1836 | cmd: &req.cmd, clen: sizeof(req)); |
1837 | } |
1838 | |
1839 | int prestera_hw_lag_fdb_del(struct prestera_switch *sw, u16 lag_id, |
1840 | const unsigned char *mac, u16 vid) |
1841 | { |
1842 | struct prestera_msg_fdb_req req = { |
1843 | .dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG, |
1844 | .dest = { |
1845 | .lag_id = __cpu_to_le16(lag_id), |
1846 | }, |
1847 | .vid = __cpu_to_le16(vid), |
1848 | }; |
1849 | |
1850 | ether_addr_copy(dst: req.mac, src: mac); |
1851 | |
1852 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_FDB_DELETE, |
1853 | cmd: &req.cmd, clen: sizeof(req)); |
1854 | } |
1855 | |
1856 | int prestera_hw_fdb_flush_port(struct prestera_port *port, u32 mode) |
1857 | { |
1858 | struct prestera_msg_fdb_req req = { |
1859 | .dest = { |
1860 | .dev = __cpu_to_le32(port->dev_id), |
1861 | .port = __cpu_to_le32(port->hw_id), |
1862 | }, |
1863 | .flush_mode = __cpu_to_le32(mode), |
1864 | }; |
1865 | |
1866 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_FDB_FLUSH_PORT, |
1867 | cmd: &req.cmd, clen: sizeof(req)); |
1868 | } |
1869 | |
1870 | int prestera_hw_fdb_flush_vlan(struct prestera_switch *sw, u16 vid, u32 mode) |
1871 | { |
1872 | struct prestera_msg_fdb_req req = { |
1873 | .vid = __cpu_to_le16(vid), |
1874 | .flush_mode = __cpu_to_le32(mode), |
1875 | }; |
1876 | |
1877 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_FDB_FLUSH_VLAN, |
1878 | cmd: &req.cmd, clen: sizeof(req)); |
1879 | } |
1880 | |
1881 | int prestera_hw_fdb_flush_port_vlan(struct prestera_port *port, u16 vid, |
1882 | u32 mode) |
1883 | { |
1884 | struct prestera_msg_fdb_req req = { |
1885 | .dest = { |
1886 | .dev = __cpu_to_le32(port->dev_id), |
1887 | .port = __cpu_to_le32(port->hw_id), |
1888 | }, |
1889 | .vid = __cpu_to_le16(vid), |
1890 | .flush_mode = __cpu_to_le32(mode), |
1891 | }; |
1892 | |
1893 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_FDB_FLUSH_PORT_VLAN, |
1894 | cmd: &req.cmd, clen: sizeof(req)); |
1895 | } |
1896 | |
1897 | int prestera_hw_fdb_flush_lag(struct prestera_switch *sw, u16 lag_id, |
1898 | u32 mode) |
1899 | { |
1900 | struct prestera_msg_fdb_req req = { |
1901 | .dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG, |
1902 | .dest = { |
1903 | .lag_id = __cpu_to_le16(lag_id), |
1904 | }, |
1905 | .flush_mode = __cpu_to_le32(mode), |
1906 | }; |
1907 | |
1908 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_FDB_FLUSH_PORT, |
1909 | cmd: &req.cmd, clen: sizeof(req)); |
1910 | } |
1911 | |
1912 | int prestera_hw_fdb_flush_lag_vlan(struct prestera_switch *sw, |
1913 | u16 lag_id, u16 vid, u32 mode) |
1914 | { |
1915 | struct prestera_msg_fdb_req req = { |
1916 | .dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG, |
1917 | .dest = { |
1918 | .lag_id = __cpu_to_le16(lag_id), |
1919 | }, |
1920 | .vid = __cpu_to_le16(vid), |
1921 | .flush_mode = __cpu_to_le32(mode), |
1922 | }; |
1923 | |
1924 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_FDB_FLUSH_PORT_VLAN, |
1925 | cmd: &req.cmd, clen: sizeof(req)); |
1926 | } |
1927 | |
1928 | int prestera_hw_bridge_create(struct prestera_switch *sw, u16 *bridge_id) |
1929 | { |
1930 | struct prestera_msg_bridge_resp resp; |
1931 | struct prestera_msg_bridge_req req; |
1932 | int err; |
1933 | |
1934 | err = prestera_cmd_ret(sw, type: PRESTERA_CMD_TYPE_BRIDGE_CREATE, |
1935 | cmd: &req.cmd, clen: sizeof(req), |
1936 | ret: &resp.ret, rlen: sizeof(resp)); |
1937 | if (err) |
1938 | return err; |
1939 | |
1940 | *bridge_id = __le16_to_cpu(resp.bridge); |
1941 | |
1942 | return 0; |
1943 | } |
1944 | |
1945 | int prestera_hw_bridge_delete(struct prestera_switch *sw, u16 bridge_id) |
1946 | { |
1947 | struct prestera_msg_bridge_req req = { |
1948 | .bridge = __cpu_to_le16(bridge_id), |
1949 | }; |
1950 | |
1951 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_BRIDGE_DELETE, |
1952 | cmd: &req.cmd, clen: sizeof(req)); |
1953 | } |
1954 | |
1955 | int prestera_hw_bridge_port_add(struct prestera_port *port, u16 bridge_id) |
1956 | { |
1957 | struct prestera_msg_bridge_req req = { |
1958 | .bridge = __cpu_to_le16(bridge_id), |
1959 | .port = __cpu_to_le32(port->hw_id), |
1960 | .dev = __cpu_to_le32(port->dev_id), |
1961 | }; |
1962 | |
1963 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_BRIDGE_PORT_ADD, |
1964 | cmd: &req.cmd, clen: sizeof(req)); |
1965 | } |
1966 | |
1967 | int prestera_hw_bridge_port_delete(struct prestera_port *port, u16 bridge_id) |
1968 | { |
1969 | struct prestera_msg_bridge_req req = { |
1970 | .bridge = __cpu_to_le16(bridge_id), |
1971 | .port = __cpu_to_le32(port->hw_id), |
1972 | .dev = __cpu_to_le32(port->dev_id), |
1973 | }; |
1974 | |
1975 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_BRIDGE_PORT_DELETE, |
1976 | cmd: &req.cmd, clen: sizeof(req)); |
1977 | } |
1978 | |
1979 | static int prestera_iface_to_msg(struct prestera_iface *iface, |
1980 | struct prestera_msg_iface *msg_if) |
1981 | { |
1982 | switch (iface->type) { |
1983 | case PRESTERA_IF_PORT_E: |
1984 | case PRESTERA_IF_VID_E: |
1985 | msg_if->port = __cpu_to_le32(iface->dev_port.port_num); |
1986 | msg_if->dev = __cpu_to_le32(iface->dev_port.hw_dev_num); |
1987 | break; |
1988 | case PRESTERA_IF_LAG_E: |
1989 | msg_if->lag_id = __cpu_to_le16(iface->lag_id); |
1990 | break; |
1991 | default: |
1992 | return -EOPNOTSUPP; |
1993 | } |
1994 | |
1995 | msg_if->vr_id = __cpu_to_le16(iface->vr_id); |
1996 | msg_if->vid = __cpu_to_le16(iface->vlan_id); |
1997 | msg_if->type = iface->type; |
1998 | return 0; |
1999 | } |
2000 | |
2001 | int prestera_hw_rif_create(struct prestera_switch *sw, |
2002 | struct prestera_iface *iif, u8 *mac, u16 *rif_id) |
2003 | { |
2004 | struct prestera_msg_rif_resp resp; |
2005 | struct prestera_msg_rif_req req; |
2006 | int err; |
2007 | |
2008 | memcpy(req.mac, mac, ETH_ALEN); |
2009 | |
2010 | err = prestera_iface_to_msg(iface: iif, msg_if: &req.iif); |
2011 | if (err) |
2012 | return err; |
2013 | |
2014 | err = prestera_cmd_ret(sw, type: PRESTERA_CMD_TYPE_ROUTER_RIF_CREATE, |
2015 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
2016 | if (err) |
2017 | return err; |
2018 | |
2019 | *rif_id = __le16_to_cpu(resp.rif_id); |
2020 | return err; |
2021 | } |
2022 | |
2023 | int prestera_hw_rif_delete(struct prestera_switch *sw, u16 rif_id, |
2024 | struct prestera_iface *iif) |
2025 | { |
2026 | struct prestera_msg_rif_req req = { |
2027 | .rif_id = __cpu_to_le16(rif_id), |
2028 | }; |
2029 | int err; |
2030 | |
2031 | err = prestera_iface_to_msg(iface: iif, msg_if: &req.iif); |
2032 | if (err) |
2033 | return err; |
2034 | |
2035 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_ROUTER_RIF_DELETE, cmd: &req.cmd, |
2036 | clen: sizeof(req)); |
2037 | } |
2038 | |
2039 | int prestera_hw_vr_create(struct prestera_switch *sw, u16 *vr_id) |
2040 | { |
2041 | struct prestera_msg_vr_resp resp; |
2042 | struct prestera_msg_vr_req req; |
2043 | int err; |
2044 | |
2045 | err = prestera_cmd_ret(sw, type: PRESTERA_CMD_TYPE_ROUTER_VR_CREATE, |
2046 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
2047 | if (err) |
2048 | return err; |
2049 | |
2050 | *vr_id = __le16_to_cpu(resp.vr_id); |
2051 | return err; |
2052 | } |
2053 | |
2054 | int prestera_hw_vr_delete(struct prestera_switch *sw, u16 vr_id) |
2055 | { |
2056 | struct prestera_msg_vr_req req = { |
2057 | .vr_id = __cpu_to_le16(vr_id), |
2058 | }; |
2059 | |
2060 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_ROUTER_VR_DELETE, cmd: &req.cmd, |
2061 | clen: sizeof(req)); |
2062 | } |
2063 | |
2064 | int prestera_hw_lpm_add(struct prestera_switch *sw, u16 vr_id, |
2065 | __be32 dst, u32 dst_len, u32 grp_id) |
2066 | { |
2067 | struct prestera_msg_lpm_req req = { |
2068 | .dst_len = __cpu_to_le32(dst_len), |
2069 | .vr_id = __cpu_to_le16(vr_id), |
2070 | .grp_id = __cpu_to_le32(grp_id), |
2071 | .dst.u.ipv4 = dst |
2072 | }; |
2073 | |
2074 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_ROUTER_LPM_ADD, cmd: &req.cmd, |
2075 | clen: sizeof(req)); |
2076 | } |
2077 | |
2078 | int prestera_hw_lpm_del(struct prestera_switch *sw, u16 vr_id, |
2079 | __be32 dst, u32 dst_len) |
2080 | { |
2081 | struct prestera_msg_lpm_req req = { |
2082 | .dst_len = __cpu_to_le32(dst_len), |
2083 | .vr_id = __cpu_to_le16(vr_id), |
2084 | .dst.u.ipv4 = dst |
2085 | }; |
2086 | |
2087 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_ROUTER_LPM_DELETE, cmd: &req.cmd, |
2088 | clen: sizeof(req)); |
2089 | } |
2090 | |
2091 | int prestera_hw_nh_entries_set(struct prestera_switch *sw, int count, |
2092 | struct prestera_neigh_info *nhs, u32 grp_id) |
2093 | { |
2094 | struct prestera_msg_nh_req req = { .size = __cpu_to_le32((u32)count), |
2095 | .grp_id = __cpu_to_le32(grp_id) }; |
2096 | int i, err; |
2097 | |
2098 | for (i = 0; i < count; i++) { |
2099 | req.nh[i].is_active = nhs[i].connected; |
2100 | memcpy(&req.nh[i].mac, nhs[i].ha, ETH_ALEN); |
2101 | err = prestera_iface_to_msg(iface: &nhs[i].iface, msg_if: &req.nh[i].oif); |
2102 | if (err) |
2103 | return err; |
2104 | } |
2105 | |
2106 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_ROUTER_NH_GRP_SET, cmd: &req.cmd, |
2107 | clen: sizeof(req)); |
2108 | } |
2109 | |
2110 | int prestera_hw_nhgrp_blk_get(struct prestera_switch *sw, |
2111 | u8 *hw_state, u32 buf_size /* Buffer in bytes */) |
2112 | { |
2113 | static struct prestera_msg_nh_chunk_resp resp; |
2114 | struct prestera_msg_nh_chunk_req req; |
2115 | u32 buf_offset; |
2116 | int err; |
2117 | |
2118 | memset(&hw_state[0], 0, buf_size); |
2119 | buf_offset = 0; |
2120 | while (1) { |
2121 | if (buf_offset >= buf_size) |
2122 | break; |
2123 | |
2124 | memset(&req, 0, sizeof(req)); |
2125 | req.offset = __cpu_to_le32(buf_offset * 8); /* 8 bits in u8 */ |
2126 | err = prestera_cmd_ret(sw, |
2127 | type: PRESTERA_CMD_TYPE_ROUTER_NH_GRP_BLK_GET, |
2128 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, |
2129 | rlen: sizeof(resp)); |
2130 | if (err) |
2131 | return err; |
2132 | |
2133 | memcpy(&hw_state[buf_offset], &resp.hw_state[0], |
2134 | buf_offset + PRESTERA_MSG_CHUNK_SIZE > buf_size ? |
2135 | buf_size - buf_offset : PRESTERA_MSG_CHUNK_SIZE); |
2136 | buf_offset += PRESTERA_MSG_CHUNK_SIZE; |
2137 | } |
2138 | |
2139 | return 0; |
2140 | } |
2141 | |
2142 | int prestera_hw_nh_group_create(struct prestera_switch *sw, u16 nh_count, |
2143 | u32 *grp_id) |
2144 | { |
2145 | struct prestera_msg_nh_grp_req req = { .size = __cpu_to_le32((u32)nh_count) }; |
2146 | struct prestera_msg_nh_grp_resp resp; |
2147 | int err; |
2148 | |
2149 | err = prestera_cmd_ret(sw, type: PRESTERA_CMD_TYPE_ROUTER_NH_GRP_ADD, |
2150 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
2151 | if (err) |
2152 | return err; |
2153 | |
2154 | *grp_id = __le32_to_cpu(resp.grp_id); |
2155 | return err; |
2156 | } |
2157 | |
2158 | int prestera_hw_nh_group_delete(struct prestera_switch *sw, u16 nh_count, |
2159 | u32 grp_id) |
2160 | { |
2161 | struct prestera_msg_nh_grp_req req = { |
2162 | .grp_id = __cpu_to_le32(grp_id), |
2163 | .size = __cpu_to_le32(nh_count) |
2164 | }; |
2165 | |
2166 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_ROUTER_NH_GRP_DELETE, |
2167 | cmd: &req.cmd, clen: sizeof(req)); |
2168 | } |
2169 | |
2170 | int prestera_hw_rxtx_init(struct prestera_switch *sw, |
2171 | struct prestera_rxtx_params *params) |
2172 | { |
2173 | struct prestera_msg_rxtx_resp resp; |
2174 | struct prestera_msg_rxtx_req req; |
2175 | int err; |
2176 | |
2177 | req.use_sdma = params->use_sdma; |
2178 | |
2179 | err = prestera_cmd_ret(sw, type: PRESTERA_CMD_TYPE_RXTX_INIT, |
2180 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
2181 | if (err) |
2182 | return err; |
2183 | |
2184 | params->map_addr = __le32_to_cpu(resp.map_addr); |
2185 | |
2186 | return 0; |
2187 | } |
2188 | |
2189 | int prestera_hw_lag_member_add(struct prestera_port *port, u16 lag_id) |
2190 | { |
2191 | struct prestera_msg_lag_req req = { |
2192 | .port = __cpu_to_le32(port->hw_id), |
2193 | .dev = __cpu_to_le32(port->dev_id), |
2194 | .lag_id = __cpu_to_le16(lag_id), |
2195 | }; |
2196 | |
2197 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_LAG_MEMBER_ADD, |
2198 | cmd: &req.cmd, clen: sizeof(req)); |
2199 | } |
2200 | |
2201 | int prestera_hw_lag_member_del(struct prestera_port *port, u16 lag_id) |
2202 | { |
2203 | struct prestera_msg_lag_req req = { |
2204 | .port = __cpu_to_le32(port->hw_id), |
2205 | .dev = __cpu_to_le32(port->dev_id), |
2206 | .lag_id = __cpu_to_le16(lag_id), |
2207 | }; |
2208 | |
2209 | return prestera_cmd(sw: port->sw, type: PRESTERA_CMD_TYPE_LAG_MEMBER_DELETE, |
2210 | cmd: &req.cmd, clen: sizeof(req)); |
2211 | } |
2212 | |
2213 | int prestera_hw_lag_member_enable(struct prestera_port *port, u16 lag_id, |
2214 | bool enable) |
2215 | { |
2216 | struct prestera_msg_lag_req req = { |
2217 | .port = __cpu_to_le32(port->hw_id), |
2218 | .dev = __cpu_to_le32(port->dev_id), |
2219 | .lag_id = __cpu_to_le16(lag_id), |
2220 | }; |
2221 | u32 cmd; |
2222 | |
2223 | cmd = enable ? PRESTERA_CMD_TYPE_LAG_MEMBER_ENABLE : |
2224 | PRESTERA_CMD_TYPE_LAG_MEMBER_DISABLE; |
2225 | |
2226 | return prestera_cmd(sw: port->sw, type: cmd, cmd: &req.cmd, clen: sizeof(req)); |
2227 | } |
2228 | |
2229 | int |
2230 | prestera_hw_cpu_code_counters_get(struct prestera_switch *sw, u8 code, |
2231 | enum prestera_hw_cpu_code_cnt_t counter_type, |
2232 | u64 *packet_count) |
2233 | { |
2234 | struct prestera_msg_cpu_code_counter_req req = { |
2235 | .counter_type = counter_type, |
2236 | .code = code, |
2237 | }; |
2238 | struct mvsw_msg_cpu_code_counter_ret resp; |
2239 | int err; |
2240 | |
2241 | err = prestera_cmd_ret(sw, type: PRESTERA_CMD_TYPE_CPU_CODE_COUNTERS_GET, |
2242 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
2243 | if (err) |
2244 | return err; |
2245 | |
2246 | *packet_count = __le64_to_cpu(resp.packet_count); |
2247 | |
2248 | return 0; |
2249 | } |
2250 | |
2251 | int prestera_hw_event_handler_register(struct prestera_switch *sw, |
2252 | enum prestera_event_type type, |
2253 | prestera_event_cb_t fn, |
2254 | void *arg) |
2255 | { |
2256 | struct prestera_fw_event_handler *eh; |
2257 | |
2258 | eh = __find_event_handler(sw, type); |
2259 | if (eh) |
2260 | return -EEXIST; |
2261 | |
2262 | eh = kmalloc(size: sizeof(*eh), GFP_KERNEL); |
2263 | if (!eh) |
2264 | return -ENOMEM; |
2265 | |
2266 | eh->type = type; |
2267 | eh->func = fn; |
2268 | eh->arg = arg; |
2269 | |
2270 | INIT_LIST_HEAD(list: &eh->list); |
2271 | |
2272 | list_add_rcu(new: &eh->list, head: &sw->event_handlers); |
2273 | |
2274 | return 0; |
2275 | } |
2276 | |
2277 | void prestera_hw_event_handler_unregister(struct prestera_switch *sw, |
2278 | enum prestera_event_type type, |
2279 | prestera_event_cb_t fn) |
2280 | { |
2281 | struct prestera_fw_event_handler *eh; |
2282 | |
2283 | eh = __find_event_handler(sw, type); |
2284 | if (!eh) |
2285 | return; |
2286 | |
2287 | list_del_rcu(entry: &eh->list); |
2288 | kfree_rcu(eh, rcu); |
2289 | } |
2290 | |
2291 | int prestera_hw_counter_trigger(struct prestera_switch *sw, u32 block_id) |
2292 | { |
2293 | struct prestera_msg_counter_req req = { |
2294 | .block_id = __cpu_to_le32(block_id) |
2295 | }; |
2296 | |
2297 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_COUNTER_TRIGGER, |
2298 | cmd: &req.cmd, clen: sizeof(req)); |
2299 | } |
2300 | |
2301 | int prestera_hw_counter_abort(struct prestera_switch *sw) |
2302 | { |
2303 | struct prestera_msg_counter_req req; |
2304 | |
2305 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_COUNTER_ABORT, |
2306 | cmd: &req.cmd, clen: sizeof(req)); |
2307 | } |
2308 | |
2309 | int prestera_hw_counters_get(struct prestera_switch *sw, u32 idx, |
2310 | u32 *len, bool *done, |
2311 | struct prestera_counter_stats *stats) |
2312 | { |
2313 | struct prestera_msg_counter_resp *resp; |
2314 | struct prestera_msg_counter_req req = { |
2315 | .block_id = __cpu_to_le32(idx), |
2316 | .num_counters = __cpu_to_le32(*len), |
2317 | }; |
2318 | size_t size = struct_size(resp, stats, *len); |
2319 | int err, i; |
2320 | |
2321 | resp = kmalloc(size, GFP_KERNEL); |
2322 | if (!resp) |
2323 | return -ENOMEM; |
2324 | |
2325 | err = prestera_cmd_ret(sw, type: PRESTERA_CMD_TYPE_COUNTER_GET, |
2326 | cmd: &req.cmd, clen: sizeof(req), ret: &resp->ret, rlen: size); |
2327 | if (err) |
2328 | goto free_buff; |
2329 | |
2330 | for (i = 0; i < __le32_to_cpu(resp->num_counters); i++) { |
2331 | stats[i].packets += __le64_to_cpu(resp->stats[i].packets); |
2332 | stats[i].bytes += __le64_to_cpu(resp->stats[i].bytes); |
2333 | } |
2334 | |
2335 | *len = __le32_to_cpu(resp->num_counters); |
2336 | *done = __le32_to_cpu(resp->done); |
2337 | |
2338 | free_buff: |
2339 | kfree(objp: resp); |
2340 | return err; |
2341 | } |
2342 | |
2343 | int prestera_hw_counter_block_get(struct prestera_switch *sw, |
2344 | u32 client, u32 *block_id, u32 *offset, |
2345 | u32 *num_counters) |
2346 | { |
2347 | struct prestera_msg_counter_resp resp; |
2348 | struct prestera_msg_counter_req req = { |
2349 | .client = __cpu_to_le32(client) |
2350 | }; |
2351 | int err; |
2352 | |
2353 | err = prestera_cmd_ret(sw, type: PRESTERA_CMD_TYPE_COUNTER_BLOCK_GET, |
2354 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
2355 | if (err) |
2356 | return err; |
2357 | |
2358 | *block_id = __le32_to_cpu(resp.block_id); |
2359 | *offset = __le32_to_cpu(resp.offset); |
2360 | *num_counters = __le32_to_cpu(resp.num_counters); |
2361 | |
2362 | return 0; |
2363 | } |
2364 | |
2365 | int prestera_hw_counter_block_release(struct prestera_switch *sw, |
2366 | u32 block_id) |
2367 | { |
2368 | struct prestera_msg_counter_req req = { |
2369 | .block_id = __cpu_to_le32(block_id) |
2370 | }; |
2371 | |
2372 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_COUNTER_BLOCK_RELEASE, |
2373 | cmd: &req.cmd, clen: sizeof(req)); |
2374 | } |
2375 | |
2376 | int prestera_hw_counter_clear(struct prestera_switch *sw, u32 block_id, |
2377 | u32 counter_id) |
2378 | { |
2379 | struct prestera_msg_counter_req req = { |
2380 | .block_id = __cpu_to_le32(block_id), |
2381 | .num_counters = __cpu_to_le32(counter_id) |
2382 | }; |
2383 | |
2384 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_COUNTER_CLEAR, |
2385 | cmd: &req.cmd, clen: sizeof(req)); |
2386 | } |
2387 | |
2388 | int prestera_hw_policer_create(struct prestera_switch *sw, u8 type, |
2389 | u32 *policer_id) |
2390 | { |
2391 | struct prestera_msg_policer_resp resp; |
2392 | struct prestera_msg_policer_req req = { |
2393 | .type = type |
2394 | }; |
2395 | int err; |
2396 | |
2397 | err = prestera_cmd_ret(sw, type: PRESTERA_CMD_TYPE_POLICER_CREATE, |
2398 | cmd: &req.cmd, clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
2399 | if (err) |
2400 | return err; |
2401 | |
2402 | *policer_id = __le32_to_cpu(resp.id); |
2403 | return 0; |
2404 | } |
2405 | |
2406 | int prestera_hw_policer_release(struct prestera_switch *sw, |
2407 | u32 policer_id) |
2408 | { |
2409 | struct prestera_msg_policer_req req = { |
2410 | .id = __cpu_to_le32(policer_id) |
2411 | }; |
2412 | |
2413 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_POLICER_RELEASE, |
2414 | cmd: &req.cmd, clen: sizeof(req)); |
2415 | } |
2416 | |
2417 | int prestera_hw_policer_sr_tcm_set(struct prestera_switch *sw, |
2418 | u32 policer_id, u64 cir, u32 cbs) |
2419 | { |
2420 | struct prestera_msg_policer_req req = { |
2421 | .mode = PRESTERA_POLICER_MODE_SR_TCM, |
2422 | .id = __cpu_to_le32(policer_id), |
2423 | .sr_tcm = { |
2424 | .cir = __cpu_to_le64(cir), |
2425 | .cbs = __cpu_to_le32(cbs) |
2426 | } |
2427 | }; |
2428 | |
2429 | return prestera_cmd(sw, type: PRESTERA_CMD_TYPE_POLICER_SET, |
2430 | cmd: &req.cmd, clen: sizeof(req)); |
2431 | } |
2432 | |
2433 | int prestera_hw_flood_domain_create(struct prestera_flood_domain *domain) |
2434 | { |
2435 | struct prestera_msg_flood_domain_create_resp resp; |
2436 | struct prestera_msg_flood_domain_create_req req; |
2437 | int err; |
2438 | |
2439 | err = prestera_cmd_ret(sw: domain->sw, |
2440 | type: PRESTERA_CMD_TYPE_FLOOD_DOMAIN_CREATE, cmd: &req.cmd, |
2441 | clen: sizeof(req), ret: &resp.ret, rlen: sizeof(resp)); |
2442 | if (err) |
2443 | return err; |
2444 | |
2445 | domain->idx = __le32_to_cpu(resp.flood_domain_idx); |
2446 | |
2447 | return 0; |
2448 | } |
2449 | |
2450 | int prestera_hw_flood_domain_destroy(struct prestera_flood_domain *domain) |
2451 | { |
2452 | struct prestera_msg_flood_domain_destroy_req req = { |
2453 | .flood_domain_idx = __cpu_to_le32(domain->idx), |
2454 | }; |
2455 | |
2456 | return prestera_cmd(sw: domain->sw, type: PRESTERA_CMD_TYPE_FLOOD_DOMAIN_DESTROY, |
2457 | cmd: &req.cmd, clen: sizeof(req)); |
2458 | } |
2459 | |
2460 | int prestera_hw_flood_domain_ports_set(struct prestera_flood_domain *domain) |
2461 | { |
2462 | struct prestera_flood_domain_port *flood_domain_port; |
2463 | struct prestera_msg_flood_domain_ports_set_req *req; |
2464 | struct prestera_msg_flood_domain_port *ports; |
2465 | struct prestera_switch *sw = domain->sw; |
2466 | struct prestera_port *port; |
2467 | u32 ports_num = 0; |
2468 | int buf_size; |
2469 | void *buff; |
2470 | u16 lag_id; |
2471 | int err; |
2472 | |
2473 | list_for_each_entry(flood_domain_port, &domain->flood_domain_port_list, |
2474 | flood_domain_port_node) |
2475 | ports_num++; |
2476 | |
2477 | if (!ports_num) |
2478 | return -EINVAL; |
2479 | |
2480 | buf_size = sizeof(*req) + sizeof(*ports) * ports_num; |
2481 | |
2482 | buff = kmalloc(size: buf_size, GFP_KERNEL); |
2483 | if (!buff) |
2484 | return -ENOMEM; |
2485 | |
2486 | req = buff; |
2487 | ports = buff + sizeof(*req); |
2488 | |
2489 | req->flood_domain_idx = __cpu_to_le32(domain->idx); |
2490 | req->ports_num = __cpu_to_le32(ports_num); |
2491 | |
2492 | list_for_each_entry(flood_domain_port, &domain->flood_domain_port_list, |
2493 | flood_domain_port_node) { |
2494 | if (netif_is_lag_master(dev: flood_domain_port->dev)) { |
2495 | if (prestera_lag_id(sw, lag_dev: flood_domain_port->dev, |
2496 | lag_id: &lag_id)) { |
2497 | kfree(objp: buff); |
2498 | return -EINVAL; |
2499 | } |
2500 | |
2501 | ports->port_type = |
2502 | __cpu_to_le16(PRESTERA_HW_FLOOD_DOMAIN_PORT_TYPE_LAG); |
2503 | ports->lag_id = __cpu_to_le16(lag_id); |
2504 | } else { |
2505 | port = prestera_port_dev_lower_find(dev: flood_domain_port->dev); |
2506 | |
2507 | ports->port_type = |
2508 | __cpu_to_le16(PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT); |
2509 | ports->dev_num = __cpu_to_le32(port->dev_id); |
2510 | ports->port_num = __cpu_to_le32(port->hw_id); |
2511 | } |
2512 | |
2513 | ports->vid = __cpu_to_le16(flood_domain_port->vid); |
2514 | |
2515 | ports++; |
2516 | } |
2517 | |
2518 | err = prestera_cmd(sw, type: PRESTERA_CMD_TYPE_FLOOD_DOMAIN_PORTS_SET, |
2519 | cmd: &req->cmd, clen: buf_size); |
2520 | |
2521 | kfree(objp: buff); |
2522 | |
2523 | return err; |
2524 | } |
2525 | |
2526 | int prestera_hw_flood_domain_ports_reset(struct prestera_flood_domain *domain) |
2527 | { |
2528 | struct prestera_msg_flood_domain_ports_reset_req req = { |
2529 | .flood_domain_idx = __cpu_to_le32(domain->idx), |
2530 | }; |
2531 | |
2532 | return prestera_cmd(sw: domain->sw, |
2533 | type: PRESTERA_CMD_TYPE_FLOOD_DOMAIN_PORTS_RESET, cmd: &req.cmd, |
2534 | clen: sizeof(req)); |
2535 | } |
2536 | |
2537 | int prestera_hw_mdb_create(struct prestera_mdb_entry *mdb) |
2538 | { |
2539 | struct prestera_msg_mdb_create_req req = { |
2540 | .flood_domain_idx = __cpu_to_le32(mdb->flood_domain->idx), |
2541 | .vid = __cpu_to_le16(mdb->vid), |
2542 | }; |
2543 | |
2544 | memcpy(req.mac, mdb->addr, ETH_ALEN); |
2545 | |
2546 | return prestera_cmd(sw: mdb->sw, type: PRESTERA_CMD_TYPE_MDB_CREATE, cmd: &req.cmd, |
2547 | clen: sizeof(req)); |
2548 | } |
2549 | |
2550 | int prestera_hw_mdb_destroy(struct prestera_mdb_entry *mdb) |
2551 | { |
2552 | struct prestera_msg_mdb_destroy_req req = { |
2553 | .flood_domain_idx = __cpu_to_le32(mdb->flood_domain->idx), |
2554 | .vid = __cpu_to_le16(mdb->vid), |
2555 | }; |
2556 | |
2557 | memcpy(req.mac, mdb->addr, ETH_ALEN); |
2558 | |
2559 | return prestera_cmd(sw: mdb->sw, type: PRESTERA_CMD_TYPE_MDB_DESTROY, cmd: &req.cmd, |
2560 | clen: sizeof(req)); |
2561 | } |
2562 | |