1
2
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
17enum 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
70enum {
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
91enum {
92 PRESTERA_CMD_SWITCH_ATTR_MAC = 1,
93 PRESTERA_CMD_SWITCH_ATTR_AGEING = 2,
94};
95
96enum {
97 PRESTERA_CMD_ACK_OK,
98 PRESTERA_CMD_ACK_FAILED,
99
100 PRESTERA_CMD_ACK_MAX
101};
102
103enum {
104 PRESTERA_PORT_TP_NA,
105 PRESTERA_PORT_TP_MDI,
106 PRESTERA_PORT_TP_MDIX,
107 PRESTERA_PORT_TP_AUTO,
108};
109
110enum {
111 PRESTERA_PORT_FLOOD_TYPE_UC = 0,
112 PRESTERA_PORT_FLOOD_TYPE_MC = 1,
113};
114
115enum {
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
150enum {
151 PRESTERA_FC_NONE,
152 PRESTERA_FC_SYMMETRIC,
153 PRESTERA_FC_ASYMMETRIC,
154 PRESTERA_FC_SYMM_ASYMM,
155};
156
157enum {
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
163struct 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
171struct prestera_msg_cmd {
172 u32 type;
173};
174
175struct prestera_msg_ret {
176 struct prestera_msg_cmd cmd;
177 u32 status;
178};
179
180struct prestera_msg_common_req {
181 struct prestera_msg_cmd cmd;
182};
183
184struct prestera_msg_common_resp {
185 struct prestera_msg_ret ret;
186};
187
188union prestera_msg_switch_param {
189 u8 mac[ETH_ALEN];
190 u32 ageing_timeout_ms;
191};
192
193struct prestera_msg_switch_attr_req {
194 struct prestera_msg_cmd cmd;
195 u32 attr;
196 union prestera_msg_switch_param param;
197};
198
199struct 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
208struct prestera_msg_port_autoneg_param {
209 u64 link_mode;
210 u8 enable;
211 u8 fec;
212};
213
214struct prestera_msg_port_cap_param {
215 u64 link_mode;
216 u8 type;
217 u8 fec;
218 u8 transceiver;
219};
220
221struct prestera_msg_port_mdix_param {
222 u8 status;
223 u8 admin_mode;
224};
225
226struct prestera_msg_port_flood_param {
227 u8 type;
228 u8 enable;
229};
230
231union 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
251struct 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
259struct prestera_msg_port_attr_resp {
260 struct prestera_msg_ret ret;
261 union prestera_msg_port_param param;
262};
263
264struct prestera_msg_port_stats_resp {
265 struct prestera_msg_ret ret;
266 u64 stats[PRESTERA_PORT_CNT_MAX];
267};
268
269struct prestera_msg_port_info_req {
270 struct prestera_msg_cmd cmd;
271 u32 port;
272};
273
274struct 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
281struct 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
290struct 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
306struct prestera_msg_bridge_req {
307 struct prestera_msg_cmd cmd;
308 u32 port;
309 u32 dev;
310 u16 bridge;
311};
312
313struct prestera_msg_bridge_resp {
314 struct prestera_msg_ret ret;
315 u16 bridge;
316};
317
318struct prestera_msg_acl_action {
319 u32 id;
320};
321
322struct 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
348struct 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
357struct prestera_msg_acl_rule_resp {
358 struct prestera_msg_ret ret;
359 u32 id;
360};
361
362struct prestera_msg_acl_rule_stats_resp {
363 struct prestera_msg_ret ret;
364 u64 packets;
365 u64 bytes;
366};
367
368struct prestera_msg_acl_ruleset_bind_req {
369 struct prestera_msg_cmd cmd;
370 u32 port;
371 u32 dev;
372 u16 ruleset_id;
373};
374
375struct prestera_msg_acl_ruleset_req {
376 struct prestera_msg_cmd cmd;
377 u16 id;
378};
379
380struct prestera_msg_acl_ruleset_resp {
381 struct prestera_msg_ret ret;
382 u16 id;
383};
384
385struct prestera_msg_span_req {
386 struct prestera_msg_cmd cmd;
387 u32 port;
388 u32 dev;
389 u8 id;
390} __packed __aligned(4);
391
392struct prestera_msg_span_resp {
393 struct prestera_msg_ret ret;
394 u8 id;
395} __packed __aligned(4);
396
397struct prestera_msg_stp_req {
398 struct prestera_msg_cmd cmd;
399 u32 port;
400 u32 dev;
401 u16 vid;
402 u8 state;
403};
404
405struct prestera_msg_rxtx_req {
406 struct prestera_msg_cmd cmd;
407 u8 use_sdma;
408};
409
410struct prestera_msg_rxtx_resp {
411 struct prestera_msg_ret ret;
412 u32 map_addr;
413};
414
415struct prestera_msg_rxtx_port_req {
416 struct prestera_msg_cmd cmd;
417 u32 port;
418 u32 dev;
419};
420
421struct prestera_msg_lag_req {
422 struct prestera_msg_cmd cmd;
423 u32 port;
424 u32 dev;
425 u16 lag_id;
426};
427
428struct prestera_msg_cpu_code_counter_req {
429 struct prestera_msg_cmd cmd;
430 u8 counter_type;
431 u8 code;
432};
433
434struct mvsw_msg_cpu_code_counter_ret {
435 struct prestera_msg_ret ret;
436 u64 packet_count;
437};
438
439struct prestera_msg_event {
440 u16 type;
441 u16 id;
442};
443
444union prestera_msg_event_port_param {
445 u32 oper_state;
446};
447
448struct prestera_msg_event_port {
449 struct prestera_msg_event id;
450 u32 port_id;
451 union prestera_msg_event_port_param param;
452};
453
454union prestera_msg_event_fdb_param {
455 u8 mac[ETH_ALEN];
456};
457
458struct 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
469static 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
492static 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
500static 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
509static 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
518static 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
531static 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
555static 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
562static 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
576static 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
594static 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
622static 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
638int 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
659int 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
671int 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
698void prestera_hw_switch_fini(struct prestera_switch *sw)
699{
700 WARN_ON(!list_empty(&sw->event_handlers));
701}
702
703int 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
716int 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
732int 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
747int 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
761int 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
777int 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
801int 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
822int 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
859int 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
875int 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
885static 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
900 break;
901 default:
902 return -EINVAL;
903 }
904
905 i++;
906 }
907
908 return 0;
909}
910
911static 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
966int 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
995 err = prestera_hw_acl_actions_put(actions, rule);
996 if (err)
997 goto free_buff;
998
999
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;
1015free_buff:
1016 kfree(buff);
1017 return err;
1018}
1019
1020int 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
1030int 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
1050int 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
1062int 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
1075int 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
1094int 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
1106int 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
1117int 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
1127int 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
1147int 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
1167int 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
1182static 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
1196static 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
1210int 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
1232int 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
1246int 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
1261int 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
1281int 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
1301int 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
1321int 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
1333int 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
1353int 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
1404int 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
1419static 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
1437static 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
1455static 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
1470int 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
1496err_mc_flood:
1497 prestera_hw_port_mc_flood_set(port, 0);
1498err_uc_flood:
1499 if (mask & BR_FLOOD)
1500 prestera_hw_port_uc_flood_set(port, 0);
1501
1502 return err;
1503}
1504
1505int 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
1515int 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
1525int 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
1540int 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
1552int 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
1565int 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
1583int 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
1600int 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
1618int 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
1635int 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
1649int 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
1660int 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
1676int 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
1691int 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
1707int 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
1724int 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
1734int 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
1746int 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
1758int 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
1777int 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
1788int 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
1800int 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
1812int 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
1828int
1829prestera_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
1850int 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
1876void 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