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