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