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 
12 #define PRESTERA_SWITCH_INIT_TIMEOUT_MS (30 * 1000)
13 
14 #define PRESTERA_MIN_MTU 64
15 
16 enum prestera_cmd_type_t {
17 	PRESTERA_CMD_TYPE_SWITCH_INIT = 0x1,
18 	PRESTERA_CMD_TYPE_SWITCH_ATTR_SET = 0x2,
19 
20 	PRESTERA_CMD_TYPE_PORT_ATTR_SET = 0x100,
21 	PRESTERA_CMD_TYPE_PORT_ATTR_GET = 0x101,
22 	PRESTERA_CMD_TYPE_PORT_INFO_GET = 0x110,
23 
24 	PRESTERA_CMD_TYPE_VLAN_CREATE = 0x200,
25 	PRESTERA_CMD_TYPE_VLAN_DELETE = 0x201,
26 	PRESTERA_CMD_TYPE_VLAN_PORT_SET = 0x202,
27 	PRESTERA_CMD_TYPE_VLAN_PVID_SET = 0x203,
28 
29 	PRESTERA_CMD_TYPE_FDB_ADD = 0x300,
30 	PRESTERA_CMD_TYPE_FDB_DELETE = 0x301,
31 	PRESTERA_CMD_TYPE_FDB_FLUSH_PORT = 0x310,
32 	PRESTERA_CMD_TYPE_FDB_FLUSH_VLAN = 0x311,
33 	PRESTERA_CMD_TYPE_FDB_FLUSH_PORT_VLAN = 0x312,
34 
35 	PRESTERA_CMD_TYPE_BRIDGE_CREATE = 0x400,
36 	PRESTERA_CMD_TYPE_BRIDGE_DELETE = 0x401,
37 	PRESTERA_CMD_TYPE_BRIDGE_PORT_ADD = 0x402,
38 	PRESTERA_CMD_TYPE_BRIDGE_PORT_DELETE = 0x403,
39 
40 	PRESTERA_CMD_TYPE_RXTX_INIT = 0x800,
41 	PRESTERA_CMD_TYPE_RXTX_PORT_INIT = 0x801,
42 
43 	PRESTERA_CMD_TYPE_LAG_MEMBER_ADD = 0x900,
44 	PRESTERA_CMD_TYPE_LAG_MEMBER_DELETE = 0x901,
45 	PRESTERA_CMD_TYPE_LAG_MEMBER_ENABLE = 0x902,
46 	PRESTERA_CMD_TYPE_LAG_MEMBER_DISABLE = 0x903,
47 
48 	PRESTERA_CMD_TYPE_STP_PORT_SET = 0x1000,
49 
50 	PRESTERA_CMD_TYPE_CPU_CODE_COUNTERS_GET = 0x2000,
51 
52 	PRESTERA_CMD_TYPE_ACK = 0x10000,
53 	PRESTERA_CMD_TYPE_MAX
54 };
55 
56 enum {
57 	PRESTERA_CMD_PORT_ATTR_ADMIN_STATE = 1,
58 	PRESTERA_CMD_PORT_ATTR_MTU = 3,
59 	PRESTERA_CMD_PORT_ATTR_MAC = 4,
60 	PRESTERA_CMD_PORT_ATTR_SPEED = 5,
61 	PRESTERA_CMD_PORT_ATTR_ACCEPT_FRAME_TYPE = 6,
62 	PRESTERA_CMD_PORT_ATTR_LEARNING = 7,
63 	PRESTERA_CMD_PORT_ATTR_FLOOD = 8,
64 	PRESTERA_CMD_PORT_ATTR_CAPABILITY = 9,
65 	PRESTERA_CMD_PORT_ATTR_REMOTE_CAPABILITY = 10,
66 	PRESTERA_CMD_PORT_ATTR_REMOTE_FC = 11,
67 	PRESTERA_CMD_PORT_ATTR_LINK_MODE = 12,
68 	PRESTERA_CMD_PORT_ATTR_TYPE = 13,
69 	PRESTERA_CMD_PORT_ATTR_FEC = 14,
70 	PRESTERA_CMD_PORT_ATTR_AUTONEG = 15,
71 	PRESTERA_CMD_PORT_ATTR_DUPLEX = 16,
72 	PRESTERA_CMD_PORT_ATTR_STATS = 17,
73 	PRESTERA_CMD_PORT_ATTR_MDIX = 18,
74 	PRESTERA_CMD_PORT_ATTR_AUTONEG_RESTART = 19,
75 };
76 
77 enum {
78 	PRESTERA_CMD_SWITCH_ATTR_MAC = 1,
79 	PRESTERA_CMD_SWITCH_ATTR_AGEING = 2,
80 };
81 
82 enum {
83 	PRESTERA_CMD_ACK_OK,
84 	PRESTERA_CMD_ACK_FAILED,
85 
86 	PRESTERA_CMD_ACK_MAX
87 };
88 
89 enum {
90 	PRESTERA_PORT_TP_NA,
91 	PRESTERA_PORT_TP_MDI,
92 	PRESTERA_PORT_TP_MDIX,
93 	PRESTERA_PORT_TP_AUTO,
94 };
95 
96 enum {
97 	PRESTERA_PORT_FLOOD_TYPE_UC = 0,
98 	PRESTERA_PORT_FLOOD_TYPE_MC = 1,
99 };
100 
101 enum {
102 	PRESTERA_PORT_GOOD_OCTETS_RCV_CNT,
103 	PRESTERA_PORT_BAD_OCTETS_RCV_CNT,
104 	PRESTERA_PORT_MAC_TRANSMIT_ERR_CNT,
105 	PRESTERA_PORT_BRDC_PKTS_RCV_CNT,
106 	PRESTERA_PORT_MC_PKTS_RCV_CNT,
107 	PRESTERA_PORT_PKTS_64L_CNT,
108 	PRESTERA_PORT_PKTS_65TO127L_CNT,
109 	PRESTERA_PORT_PKTS_128TO255L_CNT,
110 	PRESTERA_PORT_PKTS_256TO511L_CNT,
111 	PRESTERA_PORT_PKTS_512TO1023L_CNT,
112 	PRESTERA_PORT_PKTS_1024TOMAXL_CNT,
113 	PRESTERA_PORT_EXCESSIVE_COLLISIONS_CNT,
114 	PRESTERA_PORT_MC_PKTS_SENT_CNT,
115 	PRESTERA_PORT_BRDC_PKTS_SENT_CNT,
116 	PRESTERA_PORT_FC_SENT_CNT,
117 	PRESTERA_PORT_GOOD_FC_RCV_CNT,
118 	PRESTERA_PORT_DROP_EVENTS_CNT,
119 	PRESTERA_PORT_UNDERSIZE_PKTS_CNT,
120 	PRESTERA_PORT_FRAGMENTS_PKTS_CNT,
121 	PRESTERA_PORT_OVERSIZE_PKTS_CNT,
122 	PRESTERA_PORT_JABBER_PKTS_CNT,
123 	PRESTERA_PORT_MAC_RCV_ERROR_CNT,
124 	PRESTERA_PORT_BAD_CRC_CNT,
125 	PRESTERA_PORT_COLLISIONS_CNT,
126 	PRESTERA_PORT_LATE_COLLISIONS_CNT,
127 	PRESTERA_PORT_GOOD_UC_PKTS_RCV_CNT,
128 	PRESTERA_PORT_GOOD_UC_PKTS_SENT_CNT,
129 	PRESTERA_PORT_MULTIPLE_PKTS_SENT_CNT,
130 	PRESTERA_PORT_DEFERRED_PKTS_SENT_CNT,
131 	PRESTERA_PORT_GOOD_OCTETS_SENT_CNT,
132 
133 	PRESTERA_PORT_CNT_MAX
134 };
135 
136 enum {
137 	PRESTERA_FC_NONE,
138 	PRESTERA_FC_SYMMETRIC,
139 	PRESTERA_FC_ASYMMETRIC,
140 	PRESTERA_FC_SYMM_ASYMM,
141 };
142 
143 enum {
144 	PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT = 0,
145 	PRESTERA_HW_FDB_ENTRY_TYPE_LAG = 1,
146 	PRESTERA_HW_FDB_ENTRY_TYPE_MAX = 2,
147 };
148 
149 struct prestera_fw_event_handler {
150 	struct list_head list;
151 	struct rcu_head rcu;
152 	enum prestera_event_type type;
153 	prestera_event_cb_t func;
154 	void *arg;
155 };
156 
157 struct prestera_msg_cmd {
158 	u32 type;
159 };
160 
161 struct prestera_msg_ret {
162 	struct prestera_msg_cmd cmd;
163 	u32 status;
164 };
165 
166 struct prestera_msg_common_req {
167 	struct prestera_msg_cmd cmd;
168 };
169 
170 struct prestera_msg_common_resp {
171 	struct prestera_msg_ret ret;
172 };
173 
174 union prestera_msg_switch_param {
175 	u8 mac[ETH_ALEN];
176 	u32 ageing_timeout_ms;
177 };
178 
179 struct prestera_msg_switch_attr_req {
180 	struct prestera_msg_cmd cmd;
181 	u32 attr;
182 	union prestera_msg_switch_param param;
183 };
184 
185 struct prestera_msg_switch_init_resp {
186 	struct prestera_msg_ret ret;
187 	u32 port_count;
188 	u32 mtu_max;
189 	u8  switch_id;
190 	u8  lag_max;
191 	u8  lag_member_max;
192 };
193 
194 struct prestera_msg_port_autoneg_param {
195 	u64 link_mode;
196 	u8  enable;
197 	u8  fec;
198 };
199 
200 struct prestera_msg_port_cap_param {
201 	u64 link_mode;
202 	u8  type;
203 	u8  fec;
204 	u8  transceiver;
205 };
206 
207 struct prestera_msg_port_mdix_param {
208 	u8 status;
209 	u8 admin_mode;
210 };
211 
212 struct prestera_msg_port_flood_param {
213 	u8 type;
214 	u8 enable;
215 };
216 
217 union prestera_msg_port_param {
218 	u8  admin_state;
219 	u8  oper_state;
220 	u32 mtu;
221 	u8  mac[ETH_ALEN];
222 	u8  accept_frm_type;
223 	u32 speed;
224 	u8 learning;
225 	u8 flood;
226 	u32 link_mode;
227 	u8  type;
228 	u8  duplex;
229 	u8  fec;
230 	u8  fc;
231 	struct prestera_msg_port_mdix_param mdix;
232 	struct prestera_msg_port_autoneg_param autoneg;
233 	struct prestera_msg_port_cap_param cap;
234 	struct prestera_msg_port_flood_param flood_ext;
235 };
236 
237 struct prestera_msg_port_attr_req {
238 	struct prestera_msg_cmd cmd;
239 	u32 attr;
240 	u32 port;
241 	u32 dev;
242 	union prestera_msg_port_param param;
243 };
244 
245 struct prestera_msg_port_attr_resp {
246 	struct prestera_msg_ret ret;
247 	union prestera_msg_port_param param;
248 };
249 
250 struct prestera_msg_port_stats_resp {
251 	struct prestera_msg_ret ret;
252 	u64 stats[PRESTERA_PORT_CNT_MAX];
253 };
254 
255 struct prestera_msg_port_info_req {
256 	struct prestera_msg_cmd cmd;
257 	u32 port;
258 };
259 
260 struct prestera_msg_port_info_resp {
261 	struct prestera_msg_ret ret;
262 	u32 hw_id;
263 	u32 dev_id;
264 	u16 fp_id;
265 };
266 
267 struct prestera_msg_vlan_req {
268 	struct prestera_msg_cmd cmd;
269 	u32 port;
270 	u32 dev;
271 	u16 vid;
272 	u8  is_member;
273 	u8  is_tagged;
274 };
275 
276 struct prestera_msg_fdb_req {
277 	struct prestera_msg_cmd cmd;
278 	u8 dest_type;
279 	union {
280 		struct {
281 			u32 port;
282 			u32 dev;
283 		};
284 		u16 lag_id;
285 	} dest;
286 	u8  mac[ETH_ALEN];
287 	u16 vid;
288 	u8  dynamic;
289 	u32 flush_mode;
290 };
291 
292 struct prestera_msg_bridge_req {
293 	struct prestera_msg_cmd cmd;
294 	u32 port;
295 	u32 dev;
296 	u16 bridge;
297 };
298 
299 struct prestera_msg_bridge_resp {
300 	struct prestera_msg_ret ret;
301 	u16 bridge;
302 };
303 
304 struct prestera_msg_stp_req {
305 	struct prestera_msg_cmd cmd;
306 	u32 port;
307 	u32 dev;
308 	u16 vid;
309 	u8  state;
310 };
311 
312 struct prestera_msg_rxtx_req {
313 	struct prestera_msg_cmd cmd;
314 	u8 use_sdma;
315 };
316 
317 struct prestera_msg_rxtx_resp {
318 	struct prestera_msg_ret ret;
319 	u32 map_addr;
320 };
321 
322 struct prestera_msg_rxtx_port_req {
323 	struct prestera_msg_cmd cmd;
324 	u32 port;
325 	u32 dev;
326 };
327 
328 struct prestera_msg_lag_req {
329 	struct prestera_msg_cmd cmd;
330 	u32 port;
331 	u32 dev;
332 	u16 lag_id;
333 };
334 
335 struct prestera_msg_cpu_code_counter_req {
336 	struct prestera_msg_cmd cmd;
337 	u8 counter_type;
338 	u8 code;
339 };
340 
341 struct mvsw_msg_cpu_code_counter_ret {
342 	struct prestera_msg_ret ret;
343 	u64 packet_count;
344 };
345 
346 struct prestera_msg_event {
347 	u16 type;
348 	u16 id;
349 };
350 
351 union prestera_msg_event_port_param {
352 	u32 oper_state;
353 };
354 
355 struct prestera_msg_event_port {
356 	struct prestera_msg_event id;
357 	u32 port_id;
358 	union prestera_msg_event_port_param param;
359 };
360 
361 union prestera_msg_event_fdb_param {
362 	u8 mac[ETH_ALEN];
363 };
364 
365 struct prestera_msg_event_fdb {
366 	struct prestera_msg_event id;
367 	u8 dest_type;
368 	union {
369 		u32 port_id;
370 		u16 lag_id;
371 	} dest;
372 	u32 vid;
373 	union prestera_msg_event_fdb_param param;
374 };
375 
376 static int __prestera_cmd_ret(struct prestera_switch *sw,
377 			      enum prestera_cmd_type_t type,
378 			      struct prestera_msg_cmd *cmd, size_t clen,
379 			      struct prestera_msg_ret *ret, size_t rlen,
380 			      int waitms)
381 {
382 	struct prestera_device *dev = sw->dev;
383 	int err;
384 
385 	cmd->type = type;
386 
387 	err = dev->send_req(dev, cmd, clen, ret, rlen, waitms);
388 	if (err)
389 		return err;
390 
391 	if (ret->cmd.type != PRESTERA_CMD_TYPE_ACK)
392 		return -EBADE;
393 	if (ret->status != PRESTERA_CMD_ACK_OK)
394 		return -EINVAL;
395 
396 	return 0;
397 }
398 
399 static int prestera_cmd_ret(struct prestera_switch *sw,
400 			    enum prestera_cmd_type_t type,
401 			    struct prestera_msg_cmd *cmd, size_t clen,
402 			    struct prestera_msg_ret *ret, size_t rlen)
403 {
404 	return __prestera_cmd_ret(sw, type, cmd, clen, ret, rlen, 0);
405 }
406 
407 static int prestera_cmd_ret_wait(struct prestera_switch *sw,
408 				 enum prestera_cmd_type_t type,
409 				 struct prestera_msg_cmd *cmd, size_t clen,
410 				 struct prestera_msg_ret *ret, size_t rlen,
411 				 int waitms)
412 {
413 	return __prestera_cmd_ret(sw, type, cmd, clen, ret, rlen, waitms);
414 }
415 
416 static int prestera_cmd(struct prestera_switch *sw,
417 			enum prestera_cmd_type_t type,
418 			struct prestera_msg_cmd *cmd, size_t clen)
419 {
420 	struct prestera_msg_common_resp resp;
421 
422 	return prestera_cmd_ret(sw, type, cmd, clen, &resp.ret, sizeof(resp));
423 }
424 
425 static int prestera_fw_parse_port_evt(void *msg, struct prestera_event *evt)
426 {
427 	struct prestera_msg_event_port *hw_evt = msg;
428 
429 	if (evt->id != PRESTERA_PORT_EVENT_STATE_CHANGED)
430 		return -EINVAL;
431 
432 	evt->port_evt.data.oper_state = hw_evt->param.oper_state;
433 	evt->port_evt.port_id = hw_evt->port_id;
434 
435 	return 0;
436 }
437 
438 static int prestera_fw_parse_fdb_evt(void *msg, struct prestera_event *evt)
439 {
440 	struct prestera_msg_event_fdb *hw_evt = msg;
441 
442 	switch (hw_evt->dest_type) {
443 	case PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT:
444 		evt->fdb_evt.type = PRESTERA_FDB_ENTRY_TYPE_REG_PORT;
445 		evt->fdb_evt.dest.port_id = hw_evt->dest.port_id;
446 		break;
447 	case PRESTERA_HW_FDB_ENTRY_TYPE_LAG:
448 		evt->fdb_evt.type = PRESTERA_FDB_ENTRY_TYPE_LAG;
449 		evt->fdb_evt.dest.lag_id = hw_evt->dest.lag_id;
450 		break;
451 	default:
452 		return -EINVAL;
453 	}
454 
455 	evt->fdb_evt.vid = hw_evt->vid;
456 
457 	ether_addr_copy(evt->fdb_evt.data.mac, hw_evt->param.mac);
458 
459 	return 0;
460 }
461 
462 static struct prestera_fw_evt_parser {
463 	int (*func)(void *msg, struct prestera_event *evt);
464 } fw_event_parsers[PRESTERA_EVENT_TYPE_MAX] = {
465 	[PRESTERA_EVENT_TYPE_PORT] = { .func = prestera_fw_parse_port_evt },
466 	[PRESTERA_EVENT_TYPE_FDB] = { .func = prestera_fw_parse_fdb_evt },
467 };
468 
469 static struct prestera_fw_event_handler *
470 __find_event_handler(const struct prestera_switch *sw,
471 		     enum prestera_event_type type)
472 {
473 	struct prestera_fw_event_handler *eh;
474 
475 	list_for_each_entry_rcu(eh, &sw->event_handlers, list) {
476 		if (eh->type == type)
477 			return eh;
478 	}
479 
480 	return NULL;
481 }
482 
483 static int prestera_find_event_handler(const struct prestera_switch *sw,
484 				       enum prestera_event_type type,
485 				       struct prestera_fw_event_handler *eh)
486 {
487 	struct prestera_fw_event_handler *tmp;
488 	int err = 0;
489 
490 	rcu_read_lock();
491 	tmp = __find_event_handler(sw, type);
492 	if (tmp)
493 		*eh = *tmp;
494 	else
495 		err = -ENOENT;
496 	rcu_read_unlock();
497 
498 	return err;
499 }
500 
501 static int prestera_evt_recv(struct prestera_device *dev, void *buf, size_t size)
502 {
503 	struct prestera_switch *sw = dev->priv;
504 	struct prestera_msg_event *msg = buf;
505 	struct prestera_fw_event_handler eh;
506 	struct prestera_event evt;
507 	int err;
508 
509 	if (msg->type >= PRESTERA_EVENT_TYPE_MAX)
510 		return -EINVAL;
511 	if (!fw_event_parsers[msg->type].func)
512 		return -ENOENT;
513 
514 	err = prestera_find_event_handler(sw, msg->type, &eh);
515 	if (err)
516 		return err;
517 
518 	evt.id = msg->id;
519 
520 	err = fw_event_parsers[msg->type].func(buf, &evt);
521 	if (err)
522 		return err;
523 
524 	eh.func(sw, &evt, eh.arg);
525 
526 	return 0;
527 }
528 
529 static void prestera_pkt_recv(struct prestera_device *dev)
530 {
531 	struct prestera_switch *sw = dev->priv;
532 	struct prestera_fw_event_handler eh;
533 	struct prestera_event ev;
534 	int err;
535 
536 	ev.id = PRESTERA_RXTX_EVENT_RCV_PKT;
537 
538 	err = prestera_find_event_handler(sw, PRESTERA_EVENT_TYPE_RXTX, &eh);
539 	if (err)
540 		return;
541 
542 	eh.func(sw, &ev, eh.arg);
543 }
544 
545 int prestera_hw_port_info_get(const struct prestera_port *port,
546 			      u32 *dev_id, u32 *hw_id, u16 *fp_id)
547 {
548 	struct prestera_msg_port_info_req req = {
549 		.port = port->id,
550 	};
551 	struct prestera_msg_port_info_resp resp;
552 	int err;
553 
554 	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_INFO_GET,
555 			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
556 	if (err)
557 		return err;
558 
559 	*dev_id = resp.dev_id;
560 	*hw_id = resp.hw_id;
561 	*fp_id = resp.fp_id;
562 
563 	return 0;
564 }
565 
566 int prestera_hw_switch_mac_set(struct prestera_switch *sw, const char *mac)
567 {
568 	struct prestera_msg_switch_attr_req req = {
569 		.attr = PRESTERA_CMD_SWITCH_ATTR_MAC,
570 	};
571 
572 	ether_addr_copy(req.param.mac, mac);
573 
574 	return prestera_cmd(sw, PRESTERA_CMD_TYPE_SWITCH_ATTR_SET,
575 			    &req.cmd, sizeof(req));
576 }
577 
578 int prestera_hw_switch_init(struct prestera_switch *sw)
579 {
580 	struct prestera_msg_switch_init_resp resp;
581 	struct prestera_msg_common_req req;
582 	int err;
583 
584 	INIT_LIST_HEAD(&sw->event_handlers);
585 
586 	err = prestera_cmd_ret_wait(sw, PRESTERA_CMD_TYPE_SWITCH_INIT,
587 				    &req.cmd, sizeof(req),
588 				    &resp.ret, sizeof(resp),
589 				    PRESTERA_SWITCH_INIT_TIMEOUT_MS);
590 	if (err)
591 		return err;
592 
593 	sw->dev->recv_msg = prestera_evt_recv;
594 	sw->dev->recv_pkt = prestera_pkt_recv;
595 	sw->port_count = resp.port_count;
596 	sw->mtu_min = PRESTERA_MIN_MTU;
597 	sw->mtu_max = resp.mtu_max;
598 	sw->id = resp.switch_id;
599 	sw->lag_member_max = resp.lag_member_max;
600 	sw->lag_max = resp.lag_max;
601 
602 	return 0;
603 }
604 
605 void prestera_hw_switch_fini(struct prestera_switch *sw)
606 {
607 	WARN_ON(!list_empty(&sw->event_handlers));
608 }
609 
610 int prestera_hw_switch_ageing_set(struct prestera_switch *sw, u32 ageing_ms)
611 {
612 	struct prestera_msg_switch_attr_req req = {
613 		.attr = PRESTERA_CMD_SWITCH_ATTR_AGEING,
614 		.param = {
615 			.ageing_timeout_ms = ageing_ms,
616 		},
617 	};
618 
619 	return prestera_cmd(sw, PRESTERA_CMD_TYPE_SWITCH_ATTR_SET,
620 			    &req.cmd, sizeof(req));
621 }
622 
623 int prestera_hw_port_state_set(const struct prestera_port *port,
624 			       bool admin_state)
625 {
626 	struct prestera_msg_port_attr_req req = {
627 		.attr = PRESTERA_CMD_PORT_ATTR_ADMIN_STATE,
628 		.port = port->hw_id,
629 		.dev = port->dev_id,
630 		.param = {
631 			.admin_state = admin_state,
632 		}
633 	};
634 
635 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
636 			    &req.cmd, sizeof(req));
637 }
638 
639 int prestera_hw_port_mtu_set(const struct prestera_port *port, u32 mtu)
640 {
641 	struct prestera_msg_port_attr_req req = {
642 		.attr = PRESTERA_CMD_PORT_ATTR_MTU,
643 		.port = port->hw_id,
644 		.dev = port->dev_id,
645 		.param = {
646 			.mtu = mtu,
647 		}
648 	};
649 
650 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
651 			    &req.cmd, sizeof(req));
652 }
653 
654 int prestera_hw_port_mac_set(const struct prestera_port *port, const char *mac)
655 {
656 	struct prestera_msg_port_attr_req req = {
657 		.attr = PRESTERA_CMD_PORT_ATTR_MAC,
658 		.port = port->hw_id,
659 		.dev = port->dev_id,
660 	};
661 
662 	ether_addr_copy(req.param.mac, mac);
663 
664 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
665 			    &req.cmd, sizeof(req));
666 }
667 
668 int prestera_hw_port_accept_frm_type(struct prestera_port *port,
669 				     enum prestera_accept_frm_type type)
670 {
671 	struct prestera_msg_port_attr_req req = {
672 		.attr = PRESTERA_CMD_PORT_ATTR_ACCEPT_FRAME_TYPE,
673 		.port = port->hw_id,
674 		.dev = port->dev_id,
675 		.param = {
676 			.accept_frm_type = type,
677 		}
678 	};
679 
680 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
681 			    &req.cmd, sizeof(req));
682 }
683 
684 int prestera_hw_port_cap_get(const struct prestera_port *port,
685 			     struct prestera_port_caps *caps)
686 {
687 	struct prestera_msg_port_attr_req req = {
688 		.attr = PRESTERA_CMD_PORT_ATTR_CAPABILITY,
689 		.port = port->hw_id,
690 		.dev = port->dev_id,
691 	};
692 	struct prestera_msg_port_attr_resp resp;
693 	int err;
694 
695 	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
696 			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
697 	if (err)
698 		return err;
699 
700 	caps->supp_link_modes = resp.param.cap.link_mode;
701 	caps->transceiver = resp.param.cap.transceiver;
702 	caps->supp_fec = resp.param.cap.fec;
703 	caps->type = resp.param.cap.type;
704 
705 	return err;
706 }
707 
708 int prestera_hw_port_remote_cap_get(const struct prestera_port *port,
709 				    u64 *link_mode_bitmap)
710 {
711 	struct prestera_msg_port_attr_req req = {
712 		.attr = PRESTERA_CMD_PORT_ATTR_REMOTE_CAPABILITY,
713 		.port = port->hw_id,
714 		.dev = port->dev_id,
715 	};
716 	struct prestera_msg_port_attr_resp resp;
717 	int err;
718 
719 	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
720 			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
721 	if (err)
722 		return err;
723 
724 	*link_mode_bitmap = resp.param.cap.link_mode;
725 
726 	return 0;
727 }
728 
729 int prestera_hw_port_remote_fc_get(const struct prestera_port *port,
730 				   bool *pause, bool *asym_pause)
731 {
732 	struct prestera_msg_port_attr_req req = {
733 		.attr = PRESTERA_CMD_PORT_ATTR_REMOTE_FC,
734 		.port = port->hw_id,
735 		.dev = port->dev_id,
736 	};
737 	struct prestera_msg_port_attr_resp resp;
738 	int err;
739 
740 	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
741 			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
742 	if (err)
743 		return err;
744 
745 	switch (resp.param.fc) {
746 	case PRESTERA_FC_SYMMETRIC:
747 		*pause = true;
748 		*asym_pause = false;
749 		break;
750 	case PRESTERA_FC_ASYMMETRIC:
751 		*pause = false;
752 		*asym_pause = true;
753 		break;
754 	case PRESTERA_FC_SYMM_ASYMM:
755 		*pause = true;
756 		*asym_pause = true;
757 		break;
758 	default:
759 		*pause = false;
760 		*asym_pause = false;
761 	}
762 
763 	return 0;
764 }
765 
766 int prestera_hw_port_type_get(const struct prestera_port *port, u8 *type)
767 {
768 	struct prestera_msg_port_attr_req req = {
769 		.attr = PRESTERA_CMD_PORT_ATTR_TYPE,
770 		.port = port->hw_id,
771 		.dev = port->dev_id,
772 	};
773 	struct prestera_msg_port_attr_resp resp;
774 	int err;
775 
776 	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
777 			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
778 	if (err)
779 		return err;
780 
781 	*type = resp.param.type;
782 
783 	return 0;
784 }
785 
786 int prestera_hw_port_fec_get(const struct prestera_port *port, u8 *fec)
787 {
788 	struct prestera_msg_port_attr_req req = {
789 		.attr = PRESTERA_CMD_PORT_ATTR_FEC,
790 		.port = port->hw_id,
791 		.dev = port->dev_id,
792 	};
793 	struct prestera_msg_port_attr_resp resp;
794 	int err;
795 
796 	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
797 			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
798 	if (err)
799 		return err;
800 
801 	*fec = resp.param.fec;
802 
803 	return 0;
804 }
805 
806 int prestera_hw_port_fec_set(const struct prestera_port *port, u8 fec)
807 {
808 	struct prestera_msg_port_attr_req req = {
809 		.attr = PRESTERA_CMD_PORT_ATTR_FEC,
810 		.port = port->hw_id,
811 		.dev = port->dev_id,
812 		.param = {
813 			.fec = fec,
814 		}
815 	};
816 
817 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
818 			    &req.cmd, sizeof(req));
819 }
820 
821 static u8 prestera_hw_mdix_to_eth(u8 mode)
822 {
823 	switch (mode) {
824 	case PRESTERA_PORT_TP_MDI:
825 		return ETH_TP_MDI;
826 	case PRESTERA_PORT_TP_MDIX:
827 		return ETH_TP_MDI_X;
828 	case PRESTERA_PORT_TP_AUTO:
829 		return ETH_TP_MDI_AUTO;
830 	default:
831 		return ETH_TP_MDI_INVALID;
832 	}
833 }
834 
835 static u8 prestera_hw_mdix_from_eth(u8 mode)
836 {
837 	switch (mode) {
838 	case ETH_TP_MDI:
839 		return PRESTERA_PORT_TP_MDI;
840 	case ETH_TP_MDI_X:
841 		return PRESTERA_PORT_TP_MDIX;
842 	case ETH_TP_MDI_AUTO:
843 		return PRESTERA_PORT_TP_AUTO;
844 	default:
845 		return PRESTERA_PORT_TP_NA;
846 	}
847 }
848 
849 int prestera_hw_port_mdix_get(const struct prestera_port *port, u8 *status,
850 			      u8 *admin_mode)
851 {
852 	struct prestera_msg_port_attr_req req = {
853 		.attr = PRESTERA_CMD_PORT_ATTR_MDIX,
854 		.port = port->hw_id,
855 		.dev = port->dev_id,
856 	};
857 	struct prestera_msg_port_attr_resp resp;
858 	int err;
859 
860 	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
861 			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
862 	if (err)
863 		return err;
864 
865 	*status = prestera_hw_mdix_to_eth(resp.param.mdix.status);
866 	*admin_mode = prestera_hw_mdix_to_eth(resp.param.mdix.admin_mode);
867 
868 	return 0;
869 }
870 
871 int prestera_hw_port_mdix_set(const struct prestera_port *port, u8 mode)
872 {
873 	struct prestera_msg_port_attr_req req = {
874 		.attr = PRESTERA_CMD_PORT_ATTR_MDIX,
875 		.port = port->hw_id,
876 		.dev = port->dev_id,
877 	};
878 
879 	req.param.mdix.admin_mode = prestera_hw_mdix_from_eth(mode);
880 
881 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
882 			    &req.cmd, sizeof(req));
883 }
884 
885 int prestera_hw_port_link_mode_set(const struct prestera_port *port, u32 mode)
886 {
887 	struct prestera_msg_port_attr_req req = {
888 		.attr = PRESTERA_CMD_PORT_ATTR_LINK_MODE,
889 		.port = port->hw_id,
890 		.dev = port->dev_id,
891 		.param = {
892 			.link_mode = mode,
893 		}
894 	};
895 
896 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
897 			    &req.cmd, sizeof(req));
898 }
899 
900 int prestera_hw_port_link_mode_get(const struct prestera_port *port, u32 *mode)
901 {
902 	struct prestera_msg_port_attr_req req = {
903 		.attr = PRESTERA_CMD_PORT_ATTR_LINK_MODE,
904 		.port = port->hw_id,
905 		.dev = port->dev_id,
906 	};
907 	struct prestera_msg_port_attr_resp resp;
908 	int err;
909 
910 	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
911 			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
912 	if (err)
913 		return err;
914 
915 	*mode = resp.param.link_mode;
916 
917 	return 0;
918 }
919 
920 int prestera_hw_port_speed_get(const struct prestera_port *port, u32 *speed)
921 {
922 	struct prestera_msg_port_attr_req req = {
923 		.attr = PRESTERA_CMD_PORT_ATTR_SPEED,
924 		.port = port->hw_id,
925 		.dev = port->dev_id,
926 	};
927 	struct prestera_msg_port_attr_resp resp;
928 	int err;
929 
930 	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
931 			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
932 	if (err)
933 		return err;
934 
935 	*speed = resp.param.speed;
936 
937 	return 0;
938 }
939 
940 int prestera_hw_port_autoneg_set(const struct prestera_port *port,
941 				 bool autoneg, u64 link_modes, u8 fec)
942 {
943 	struct prestera_msg_port_attr_req req = {
944 		.attr = PRESTERA_CMD_PORT_ATTR_AUTONEG,
945 		.port = port->hw_id,
946 		.dev = port->dev_id,
947 		.param = {
948 			.autoneg = {
949 				.link_mode = link_modes,
950 				.enable = autoneg,
951 				.fec = fec,
952 			}
953 		}
954 	};
955 
956 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
957 			    &req.cmd, sizeof(req));
958 }
959 
960 int prestera_hw_port_autoneg_restart(struct prestera_port *port)
961 {
962 	struct prestera_msg_port_attr_req req = {
963 		.attr = PRESTERA_CMD_PORT_ATTR_AUTONEG_RESTART,
964 		.port = port->hw_id,
965 		.dev = port->dev_id,
966 	};
967 
968 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
969 			    &req.cmd, sizeof(req));
970 }
971 
972 int prestera_hw_port_duplex_get(const struct prestera_port *port, u8 *duplex)
973 {
974 	struct prestera_msg_port_attr_req req = {
975 		.attr = PRESTERA_CMD_PORT_ATTR_DUPLEX,
976 		.port = port->hw_id,
977 		.dev = port->dev_id,
978 	};
979 	struct prestera_msg_port_attr_resp resp;
980 	int err;
981 
982 	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
983 			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
984 	if (err)
985 		return err;
986 
987 	*duplex = resp.param.duplex;
988 
989 	return 0;
990 }
991 
992 int prestera_hw_port_stats_get(const struct prestera_port *port,
993 			       struct prestera_port_stats *st)
994 {
995 	struct prestera_msg_port_attr_req req = {
996 		.attr = PRESTERA_CMD_PORT_ATTR_STATS,
997 		.port = port->hw_id,
998 		.dev = port->dev_id,
999 	};
1000 	struct prestera_msg_port_stats_resp resp;
1001 	u64 *hw = resp.stats;
1002 	int err;
1003 
1004 	err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,
1005 			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
1006 	if (err)
1007 		return err;
1008 
1009 	st->good_octets_received = hw[PRESTERA_PORT_GOOD_OCTETS_RCV_CNT];
1010 	st->bad_octets_received = hw[PRESTERA_PORT_BAD_OCTETS_RCV_CNT];
1011 	st->mac_trans_error = hw[PRESTERA_PORT_MAC_TRANSMIT_ERR_CNT];
1012 	st->broadcast_frames_received = hw[PRESTERA_PORT_BRDC_PKTS_RCV_CNT];
1013 	st->multicast_frames_received = hw[PRESTERA_PORT_MC_PKTS_RCV_CNT];
1014 	st->frames_64_octets = hw[PRESTERA_PORT_PKTS_64L_CNT];
1015 	st->frames_65_to_127_octets = hw[PRESTERA_PORT_PKTS_65TO127L_CNT];
1016 	st->frames_128_to_255_octets = hw[PRESTERA_PORT_PKTS_128TO255L_CNT];
1017 	st->frames_256_to_511_octets = hw[PRESTERA_PORT_PKTS_256TO511L_CNT];
1018 	st->frames_512_to_1023_octets = hw[PRESTERA_PORT_PKTS_512TO1023L_CNT];
1019 	st->frames_1024_to_max_octets = hw[PRESTERA_PORT_PKTS_1024TOMAXL_CNT];
1020 	st->excessive_collision = hw[PRESTERA_PORT_EXCESSIVE_COLLISIONS_CNT];
1021 	st->multicast_frames_sent = hw[PRESTERA_PORT_MC_PKTS_SENT_CNT];
1022 	st->broadcast_frames_sent = hw[PRESTERA_PORT_BRDC_PKTS_SENT_CNT];
1023 	st->fc_sent = hw[PRESTERA_PORT_FC_SENT_CNT];
1024 	st->fc_received = hw[PRESTERA_PORT_GOOD_FC_RCV_CNT];
1025 	st->buffer_overrun = hw[PRESTERA_PORT_DROP_EVENTS_CNT];
1026 	st->undersize = hw[PRESTERA_PORT_UNDERSIZE_PKTS_CNT];
1027 	st->fragments = hw[PRESTERA_PORT_FRAGMENTS_PKTS_CNT];
1028 	st->oversize = hw[PRESTERA_PORT_OVERSIZE_PKTS_CNT];
1029 	st->jabber = hw[PRESTERA_PORT_JABBER_PKTS_CNT];
1030 	st->rx_error_frame_received = hw[PRESTERA_PORT_MAC_RCV_ERROR_CNT];
1031 	st->bad_crc = hw[PRESTERA_PORT_BAD_CRC_CNT];
1032 	st->collisions = hw[PRESTERA_PORT_COLLISIONS_CNT];
1033 	st->late_collision = hw[PRESTERA_PORT_LATE_COLLISIONS_CNT];
1034 	st->unicast_frames_received = hw[PRESTERA_PORT_GOOD_UC_PKTS_RCV_CNT];
1035 	st->unicast_frames_sent = hw[PRESTERA_PORT_GOOD_UC_PKTS_SENT_CNT];
1036 	st->sent_multiple = hw[PRESTERA_PORT_MULTIPLE_PKTS_SENT_CNT];
1037 	st->sent_deferred = hw[PRESTERA_PORT_DEFERRED_PKTS_SENT_CNT];
1038 	st->good_octets_sent = hw[PRESTERA_PORT_GOOD_OCTETS_SENT_CNT];
1039 
1040 	return 0;
1041 }
1042 
1043 int prestera_hw_port_learning_set(struct prestera_port *port, bool enable)
1044 {
1045 	struct prestera_msg_port_attr_req req = {
1046 		.attr = PRESTERA_CMD_PORT_ATTR_LEARNING,
1047 		.port = port->hw_id,
1048 		.dev = port->dev_id,
1049 		.param = {
1050 			.learning = enable,
1051 		}
1052 	};
1053 
1054 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
1055 			    &req.cmd, sizeof(req));
1056 }
1057 
1058 static int prestera_hw_port_uc_flood_set(struct prestera_port *port, bool flood)
1059 {
1060 	struct prestera_msg_port_attr_req req = {
1061 		.attr = PRESTERA_CMD_PORT_ATTR_FLOOD,
1062 		.port = port->hw_id,
1063 		.dev = port->dev_id,
1064 		.param = {
1065 			.flood_ext = {
1066 				.type = PRESTERA_PORT_FLOOD_TYPE_UC,
1067 				.enable = flood,
1068 			}
1069 		}
1070 	};
1071 
1072 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
1073 			    &req.cmd, sizeof(req));
1074 }
1075 
1076 static int prestera_hw_port_mc_flood_set(struct prestera_port *port, bool flood)
1077 {
1078 	struct prestera_msg_port_attr_req req = {
1079 		.attr = PRESTERA_CMD_PORT_ATTR_FLOOD,
1080 		.port = port->hw_id,
1081 		.dev = port->dev_id,
1082 		.param = {
1083 			.flood_ext = {
1084 				.type = PRESTERA_PORT_FLOOD_TYPE_MC,
1085 				.enable = flood,
1086 			}
1087 		}
1088 	};
1089 
1090 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
1091 			    &req.cmd, sizeof(req));
1092 }
1093 
1094 static int prestera_hw_port_flood_set_v2(struct prestera_port *port, bool flood)
1095 {
1096 	struct prestera_msg_port_attr_req req = {
1097 		.attr = PRESTERA_CMD_PORT_ATTR_FLOOD,
1098 		.port = port->hw_id,
1099 		.dev = port->dev_id,
1100 		.param = {
1101 			.flood = flood,
1102 		}
1103 	};
1104 
1105 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,
1106 			    &req.cmd, sizeof(req));
1107 }
1108 
1109 int prestera_hw_port_flood_set(struct prestera_port *port, unsigned long mask,
1110 			       unsigned long val)
1111 {
1112 	int err;
1113 
1114 	if (port->sw->dev->fw_rev.maj <= 2) {
1115 		if (!(mask & BR_FLOOD))
1116 			return 0;
1117 
1118 		return prestera_hw_port_flood_set_v2(port, val & BR_FLOOD);
1119 	}
1120 
1121 	if (mask & BR_FLOOD) {
1122 		err = prestera_hw_port_uc_flood_set(port, val & BR_FLOOD);
1123 		if (err)
1124 			goto err_uc_flood;
1125 	}
1126 
1127 	if (mask & BR_MCAST_FLOOD) {
1128 		err = prestera_hw_port_mc_flood_set(port, val & BR_MCAST_FLOOD);
1129 		if (err)
1130 			goto err_mc_flood;
1131 	}
1132 
1133 	return 0;
1134 
1135 err_mc_flood:
1136 	prestera_hw_port_mc_flood_set(port, 0);
1137 err_uc_flood:
1138 	if (mask & BR_FLOOD)
1139 		prestera_hw_port_uc_flood_set(port, 0);
1140 
1141 	return err;
1142 }
1143 
1144 int prestera_hw_vlan_create(struct prestera_switch *sw, u16 vid)
1145 {
1146 	struct prestera_msg_vlan_req req = {
1147 		.vid = vid,
1148 	};
1149 
1150 	return prestera_cmd(sw, PRESTERA_CMD_TYPE_VLAN_CREATE,
1151 			    &req.cmd, sizeof(req));
1152 }
1153 
1154 int prestera_hw_vlan_delete(struct prestera_switch *sw, u16 vid)
1155 {
1156 	struct prestera_msg_vlan_req req = {
1157 		.vid = vid,
1158 	};
1159 
1160 	return prestera_cmd(sw, PRESTERA_CMD_TYPE_VLAN_DELETE,
1161 			    &req.cmd, sizeof(req));
1162 }
1163 
1164 int prestera_hw_vlan_port_set(struct prestera_port *port, u16 vid,
1165 			      bool is_member, bool untagged)
1166 {
1167 	struct prestera_msg_vlan_req req = {
1168 		.port = port->hw_id,
1169 		.dev = port->dev_id,
1170 		.vid = vid,
1171 		.is_member = is_member,
1172 		.is_tagged = !untagged,
1173 	};
1174 
1175 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_VLAN_PORT_SET,
1176 			    &req.cmd, sizeof(req));
1177 }
1178 
1179 int prestera_hw_vlan_port_vid_set(struct prestera_port *port, u16 vid)
1180 {
1181 	struct prestera_msg_vlan_req req = {
1182 		.port = port->hw_id,
1183 		.dev = port->dev_id,
1184 		.vid = vid,
1185 	};
1186 
1187 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_VLAN_PVID_SET,
1188 			    &req.cmd, sizeof(req));
1189 }
1190 
1191 int prestera_hw_vlan_port_stp_set(struct prestera_port *port, u16 vid, u8 state)
1192 {
1193 	struct prestera_msg_stp_req req = {
1194 		.port = port->hw_id,
1195 		.dev = port->dev_id,
1196 		.vid = vid,
1197 		.state = state,
1198 	};
1199 
1200 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_STP_PORT_SET,
1201 			    &req.cmd, sizeof(req));
1202 }
1203 
1204 int prestera_hw_fdb_add(struct prestera_port *port, const unsigned char *mac,
1205 			u16 vid, bool dynamic)
1206 {
1207 	struct prestera_msg_fdb_req req = {
1208 		.dest = {
1209 			.dev = port->dev_id,
1210 			.port = port->hw_id,
1211 		},
1212 		.vid = vid,
1213 		.dynamic = dynamic,
1214 	};
1215 
1216 	ether_addr_copy(req.mac, mac);
1217 
1218 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_FDB_ADD,
1219 			    &req.cmd, sizeof(req));
1220 }
1221 
1222 int prestera_hw_fdb_del(struct prestera_port *port, const unsigned char *mac,
1223 			u16 vid)
1224 {
1225 	struct prestera_msg_fdb_req req = {
1226 		.dest = {
1227 			.dev = port->dev_id,
1228 			.port = port->hw_id,
1229 		},
1230 		.vid = vid,
1231 	};
1232 
1233 	ether_addr_copy(req.mac, mac);
1234 
1235 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_FDB_DELETE,
1236 			    &req.cmd, sizeof(req));
1237 }
1238 
1239 int prestera_hw_lag_fdb_add(struct prestera_switch *sw, u16 lag_id,
1240 			    const unsigned char *mac, u16 vid, bool dynamic)
1241 {
1242 	struct prestera_msg_fdb_req req = {
1243 		.dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
1244 		.dest = {
1245 			.lag_id = lag_id,
1246 		},
1247 		.vid = vid,
1248 		.dynamic = dynamic,
1249 	};
1250 
1251 	ether_addr_copy(req.mac, mac);
1252 
1253 	return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_ADD,
1254 			    &req.cmd, sizeof(req));
1255 }
1256 
1257 int prestera_hw_lag_fdb_del(struct prestera_switch *sw, u16 lag_id,
1258 			    const unsigned char *mac, u16 vid)
1259 {
1260 	struct prestera_msg_fdb_req req = {
1261 		.dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
1262 		.dest = {
1263 			.lag_id = lag_id,
1264 		},
1265 		.vid = vid,
1266 	};
1267 
1268 	ether_addr_copy(req.mac, mac);
1269 
1270 	return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_DELETE,
1271 			    &req.cmd, sizeof(req));
1272 }
1273 
1274 int prestera_hw_fdb_flush_port(struct prestera_port *port, u32 mode)
1275 {
1276 	struct prestera_msg_fdb_req req = {
1277 		.dest = {
1278 			.dev = port->dev_id,
1279 			.port = port->hw_id,
1280 		},
1281 		.flush_mode = mode,
1282 	};
1283 
1284 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT,
1285 			    &req.cmd, sizeof(req));
1286 }
1287 
1288 int prestera_hw_fdb_flush_vlan(struct prestera_switch *sw, u16 vid, u32 mode)
1289 {
1290 	struct prestera_msg_fdb_req req = {
1291 		.vid = vid,
1292 		.flush_mode = mode,
1293 	};
1294 
1295 	return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_FLUSH_VLAN,
1296 			    &req.cmd, sizeof(req));
1297 }
1298 
1299 int prestera_hw_fdb_flush_port_vlan(struct prestera_port *port, u16 vid,
1300 				    u32 mode)
1301 {
1302 	struct prestera_msg_fdb_req req = {
1303 		.dest = {
1304 			.dev = port->dev_id,
1305 			.port = port->hw_id,
1306 		},
1307 		.vid = vid,
1308 		.flush_mode = mode,
1309 	};
1310 
1311 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT_VLAN,
1312 			    &req.cmd, sizeof(req));
1313 }
1314 
1315 int prestera_hw_fdb_flush_lag(struct prestera_switch *sw, u16 lag_id,
1316 			      u32 mode)
1317 {
1318 	struct prestera_msg_fdb_req req = {
1319 		.dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
1320 		.dest = {
1321 			.lag_id = lag_id,
1322 		},
1323 		.flush_mode = mode,
1324 	};
1325 
1326 	return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT,
1327 			    &req.cmd, sizeof(req));
1328 }
1329 
1330 int prestera_hw_fdb_flush_lag_vlan(struct prestera_switch *sw,
1331 				   u16 lag_id, u16 vid, u32 mode)
1332 {
1333 	struct prestera_msg_fdb_req req = {
1334 		.dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,
1335 		.dest = {
1336 			.lag_id = lag_id,
1337 		},
1338 		.vid = vid,
1339 		.flush_mode = mode,
1340 	};
1341 
1342 	return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT_VLAN,
1343 			    &req.cmd, sizeof(req));
1344 }
1345 
1346 int prestera_hw_bridge_create(struct prestera_switch *sw, u16 *bridge_id)
1347 {
1348 	struct prestera_msg_bridge_resp resp;
1349 	struct prestera_msg_bridge_req req;
1350 	int err;
1351 
1352 	err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_BRIDGE_CREATE,
1353 			       &req.cmd, sizeof(req),
1354 			       &resp.ret, sizeof(resp));
1355 	if (err)
1356 		return err;
1357 
1358 	*bridge_id = resp.bridge;
1359 
1360 	return 0;
1361 }
1362 
1363 int prestera_hw_bridge_delete(struct prestera_switch *sw, u16 bridge_id)
1364 {
1365 	struct prestera_msg_bridge_req req = {
1366 		.bridge = bridge_id,
1367 	};
1368 
1369 	return prestera_cmd(sw, PRESTERA_CMD_TYPE_BRIDGE_DELETE,
1370 			    &req.cmd, sizeof(req));
1371 }
1372 
1373 int prestera_hw_bridge_port_add(struct prestera_port *port, u16 bridge_id)
1374 {
1375 	struct prestera_msg_bridge_req req = {
1376 		.bridge = bridge_id,
1377 		.port = port->hw_id,
1378 		.dev = port->dev_id,
1379 	};
1380 
1381 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_BRIDGE_PORT_ADD,
1382 			    &req.cmd, sizeof(req));
1383 }
1384 
1385 int prestera_hw_bridge_port_delete(struct prestera_port *port, u16 bridge_id)
1386 {
1387 	struct prestera_msg_bridge_req req = {
1388 		.bridge = bridge_id,
1389 		.port = port->hw_id,
1390 		.dev = port->dev_id,
1391 	};
1392 
1393 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_BRIDGE_PORT_DELETE,
1394 			    &req.cmd, sizeof(req));
1395 }
1396 
1397 int prestera_hw_rxtx_init(struct prestera_switch *sw,
1398 			  struct prestera_rxtx_params *params)
1399 {
1400 	struct prestera_msg_rxtx_resp resp;
1401 	struct prestera_msg_rxtx_req req;
1402 	int err;
1403 
1404 	req.use_sdma = params->use_sdma;
1405 
1406 	err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_RXTX_INIT,
1407 			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
1408 	if (err)
1409 		return err;
1410 
1411 	params->map_addr = resp.map_addr;
1412 
1413 	return 0;
1414 }
1415 
1416 int prestera_hw_rxtx_port_init(struct prestera_port *port)
1417 {
1418 	struct prestera_msg_rxtx_port_req req = {
1419 		.port = port->hw_id,
1420 		.dev = port->dev_id,
1421 	};
1422 
1423 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_RXTX_PORT_INIT,
1424 			    &req.cmd, sizeof(req));
1425 }
1426 
1427 int prestera_hw_lag_member_add(struct prestera_port *port, u16 lag_id)
1428 {
1429 	struct prestera_msg_lag_req req = {
1430 		.port = port->hw_id,
1431 		.dev = port->dev_id,
1432 		.lag_id = lag_id,
1433 	};
1434 
1435 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_LAG_MEMBER_ADD,
1436 			    &req.cmd, sizeof(req));
1437 }
1438 
1439 int prestera_hw_lag_member_del(struct prestera_port *port, u16 lag_id)
1440 {
1441 	struct prestera_msg_lag_req req = {
1442 		.port = port->hw_id,
1443 		.dev = port->dev_id,
1444 		.lag_id = lag_id,
1445 	};
1446 
1447 	return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_LAG_MEMBER_DELETE,
1448 			    &req.cmd, sizeof(req));
1449 }
1450 
1451 int prestera_hw_lag_member_enable(struct prestera_port *port, u16 lag_id,
1452 				  bool enable)
1453 {
1454 	struct prestera_msg_lag_req req = {
1455 		.port = port->hw_id,
1456 		.dev = port->dev_id,
1457 		.lag_id = lag_id,
1458 	};
1459 	u32 cmd;
1460 
1461 	cmd = enable ? PRESTERA_CMD_TYPE_LAG_MEMBER_ENABLE :
1462 			PRESTERA_CMD_TYPE_LAG_MEMBER_DISABLE;
1463 
1464 	return prestera_cmd(port->sw, cmd, &req.cmd, sizeof(req));
1465 }
1466 
1467 int
1468 prestera_hw_cpu_code_counters_get(struct prestera_switch *sw, u8 code,
1469 				  enum prestera_hw_cpu_code_cnt_t counter_type,
1470 				  u64 *packet_count)
1471 {
1472 	struct prestera_msg_cpu_code_counter_req req = {
1473 		.counter_type = counter_type,
1474 		.code = code,
1475 	};
1476 	struct mvsw_msg_cpu_code_counter_ret resp;
1477 	int err;
1478 
1479 	err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_CPU_CODE_COUNTERS_GET,
1480 			       &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
1481 	if (err)
1482 		return err;
1483 
1484 	*packet_count = resp.packet_count;
1485 
1486 	return 0;
1487 }
1488 
1489 int prestera_hw_event_handler_register(struct prestera_switch *sw,
1490 				       enum prestera_event_type type,
1491 				       prestera_event_cb_t fn,
1492 				       void *arg)
1493 {
1494 	struct prestera_fw_event_handler *eh;
1495 
1496 	eh = __find_event_handler(sw, type);
1497 	if (eh)
1498 		return -EEXIST;
1499 
1500 	eh = kmalloc(sizeof(*eh), GFP_KERNEL);
1501 	if (!eh)
1502 		return -ENOMEM;
1503 
1504 	eh->type = type;
1505 	eh->func = fn;
1506 	eh->arg = arg;
1507 
1508 	INIT_LIST_HEAD(&eh->list);
1509 
1510 	list_add_rcu(&eh->list, &sw->event_handlers);
1511 
1512 	return 0;
1513 }
1514 
1515 void prestera_hw_event_handler_unregister(struct prestera_switch *sw,
1516 					  enum prestera_event_type type,
1517 					  prestera_event_cb_t fn)
1518 {
1519 	struct prestera_fw_event_handler *eh;
1520 
1521 	eh = __find_event_handler(sw, type);
1522 	if (!eh)
1523 		return;
1524 
1525 	list_del_rcu(&eh->list);
1526 	kfree_rcu(eh, rcu);
1527 }
1528