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