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
15enum 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
48enum {
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
69enum {
70	PRESTERA_CMD_SWITCH_ATTR_MAC = 1,
71	PRESTERA_CMD_SWITCH_ATTR_AGEING = 2,
72};
73
74enum {
75	PRESTERA_CMD_ACK_OK,
76	PRESTERA_CMD_ACK_FAILED,
77
78	PRESTERA_CMD_ACK_MAX
79};
80
81enum {
82	PRESTERA_PORT_TP_NA,
83	PRESTERA_PORT_TP_MDI,
84	PRESTERA_PORT_TP_MDIX,
85	PRESTERA_PORT_TP_AUTO,
86};
87
88enum {
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
123enum {
124	PRESTERA_FC_NONE,
125	PRESTERA_FC_SYMMETRIC,
126	PRESTERA_FC_ASYMMETRIC,
127	PRESTERA_FC_SYMM_ASYMM,
128};
129
130struct 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
138struct prestera_msg_cmd {
139	u32 type;
140};
141
142struct prestera_msg_ret {
143	struct prestera_msg_cmd cmd;
144	u32 status;
145};
146
147struct prestera_msg_common_req {
148	struct prestera_msg_cmd cmd;
149};
150
151struct prestera_msg_common_resp {
152	struct prestera_msg_ret ret;
153};
154
155union prestera_msg_switch_param {
156	u8 mac[ETH_ALEN];
157	u32 ageing_timeout_ms;
158};
159
160struct prestera_msg_switch_attr_req {
161	struct prestera_msg_cmd cmd;
162	u32 attr;
163	union prestera_msg_switch_param param;
164};
165
166struct 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
173struct prestera_msg_port_autoneg_param {
174	u64 link_mode;
175	u8  enable;
176	u8  fec;
177};
178
179struct prestera_msg_port_cap_param {
180	u64 link_mode;
181	u8  type;
182	u8  fec;
183	u8  transceiver;
184};
185
186struct prestera_msg_port_mdix_param {
187	u8 status;
188	u8 admin_mode;
189};
190
191union 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
210struct 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
218struct prestera_msg_port_attr_resp {
219	struct prestera_msg_ret ret;
220	union prestera_msg_port_param param;
221};
222
223struct prestera_msg_port_stats_resp {
224	struct prestera_msg_ret ret;
225	u64 stats[PRESTERA_PORT_CNT_MAX];
226};
227
228struct prestera_msg_port_info_req {
229	struct prestera_msg_cmd cmd;
230	u32 port;
231};
232
233struct 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
240struct 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
249struct 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
260struct prestera_msg_bridge_req {
261	struct prestera_msg_cmd cmd;
262	u32 port;
263	u32 dev;
264	u16 bridge;
265};
266
267struct prestera_msg_bridge_resp {
268	struct prestera_msg_ret ret;
269	u16 bridge;
270};
271
272struct prestera_msg_stp_req {
273	struct prestera_msg_cmd cmd;
274	u32 port;
275	u32 dev;
276	u16 vid;
277	u8  state;
278};
279
280struct prestera_msg_rxtx_req {
281	struct prestera_msg_cmd cmd;
282	u8 use_sdma;
283};
284
285struct prestera_msg_rxtx_resp {
286	struct prestera_msg_ret ret;
287	u32 map_addr;
288};
289
290struct prestera_msg_rxtx_port_req {
291	struct prestera_msg_cmd cmd;
292	u32 port;
293	u32 dev;
294};
295
296struct prestera_msg_event {
297	u16 type;
298	u16 id;
299};
300
301union prestera_msg_event_port_param {
302	u32 oper_state;
303};
304
305struct prestera_msg_event_port {
306	struct prestera_msg_event id;
307	u32 port_id;
308	union prestera_msg_event_port_param param;
309};
310
311union prestera_msg_event_fdb_param {
312	u8 mac[ETH_ALEN];
313};
314
315struct 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
323static 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
346static 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
354static 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
363static 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
372static 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
385static 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
397static 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
404static 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
418static 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
436static 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
464static 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
480int 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
501int 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
513int 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
538void prestera_hw_switch_fini(struct prestera_switch *sw)
539{
540	WARN_ON(!list_empty(&sw->event_handlers));
541}
542
543int 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
556int 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
572int 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
587int 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
601int 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
617int 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
641int 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
662int 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
699int 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
719int 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
739int 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
754static 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
768static 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
782int 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
804int 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
818int 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
833int 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
853int 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
873int 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
893int 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
905int 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
925int 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
976int 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
991int 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
1006int 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
1016int 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
1026int 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
1041int 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
1053int 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
1066int 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
1082int 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
1097int 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
1109int 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
1120int 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
1134int 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
1151int 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
1161int 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
1173int 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
1185int 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
1204int 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
1215int 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
1241void 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