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
__prestera_cmd_ret(struct prestera_switch * sw,enum prestera_cmd_type_t type,struct prestera_msg_cmd * cmd,size_t clen,struct prestera_msg_ret * ret,size_t rlen,int waitms)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
prestera_cmd_ret(struct prestera_switch * sw,enum prestera_cmd_type_t type,struct prestera_msg_cmd * cmd,size_t clen,struct prestera_msg_ret * ret,size_t rlen)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
prestera_cmd_ret_wait(struct prestera_switch * sw,enum prestera_cmd_type_t type,struct prestera_msg_cmd * cmd,size_t clen,struct prestera_msg_ret * ret,size_t rlen,int waitms)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
prestera_cmd(struct prestera_switch * sw,enum prestera_cmd_type_t type,struct prestera_msg_cmd * cmd,size_t clen)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
prestera_fw_parse_port_evt(void * msg,struct prestera_event * evt)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
prestera_fw_parse_fdb_evt(void * msg,struct prestera_event * evt)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 *
__find_event_handler(const struct prestera_switch * sw,enum prestera_event_type type)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
prestera_find_event_handler(const struct prestera_switch * sw,enum prestera_event_type type,struct prestera_fw_event_handler * eh)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
prestera_evt_recv(struct prestera_device * dev,void * buf,size_t size)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
prestera_pkt_recv(struct prestera_device * dev)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
prestera_hw_port_info_get(const struct prestera_port * port,u32 * dev_id,u32 * hw_id,u16 * fp_id)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
prestera_hw_switch_mac_set(struct prestera_switch * sw,const char * mac)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
prestera_hw_switch_init(struct prestera_switch * sw)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
prestera_hw_switch_fini(struct prestera_switch * sw)538 void prestera_hw_switch_fini(struct prestera_switch *sw)
539 {
540 WARN_ON(!list_empty(&sw->event_handlers));
541 }
542
prestera_hw_switch_ageing_set(struct prestera_switch * sw,u32 ageing_ms)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
prestera_hw_port_state_set(const struct prestera_port * port,bool admin_state)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
prestera_hw_port_mtu_set(const struct prestera_port * port,u32 mtu)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
prestera_hw_port_mac_set(const struct prestera_port * port,const char * mac)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
prestera_hw_port_accept_frm_type(struct prestera_port * port,enum prestera_accept_frm_type type)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
prestera_hw_port_cap_get(const struct prestera_port * port,struct prestera_port_caps * caps)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
prestera_hw_port_remote_cap_get(const struct prestera_port * port,u64 * link_mode_bitmap)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
prestera_hw_port_remote_fc_get(const struct prestera_port * port,bool * pause,bool * asym_pause)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
prestera_hw_port_type_get(const struct prestera_port * port,u8 * type)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
prestera_hw_port_fec_get(const struct prestera_port * port,u8 * fec)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
prestera_hw_port_fec_set(const struct prestera_port * port,u8 fec)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
prestera_hw_mdix_to_eth(u8 mode)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
prestera_hw_mdix_from_eth(u8 mode)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
prestera_hw_port_mdix_get(const struct prestera_port * port,u8 * status,u8 * admin_mode)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
prestera_hw_port_mdix_set(const struct prestera_port * port,u8 mode)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
prestera_hw_port_link_mode_set(const struct prestera_port * port,u32 mode)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
prestera_hw_port_link_mode_get(const struct prestera_port * port,u32 * mode)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
prestera_hw_port_speed_get(const struct prestera_port * port,u32 * speed)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
prestera_hw_port_autoneg_set(const struct prestera_port * port,bool autoneg,u64 link_modes,u8 fec)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
prestera_hw_port_autoneg_restart(struct prestera_port * port)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
prestera_hw_port_duplex_get(const struct prestera_port * port,u8 * duplex)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
prestera_hw_port_stats_get(const struct prestera_port * port,struct prestera_port_stats * st)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
prestera_hw_port_learning_set(struct prestera_port * port,bool enable)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
prestera_hw_port_flood_set(struct prestera_port * port,bool flood)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
prestera_hw_vlan_create(struct prestera_switch * sw,u16 vid)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
prestera_hw_vlan_delete(struct prestera_switch * sw,u16 vid)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
prestera_hw_vlan_port_set(struct prestera_port * port,u16 vid,bool is_member,bool untagged)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
prestera_hw_vlan_port_vid_set(struct prestera_port * port,u16 vid)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
prestera_hw_vlan_port_stp_set(struct prestera_port * port,u16 vid,u8 state)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
prestera_hw_fdb_add(struct prestera_port * port,const unsigned char * mac,u16 vid,bool dynamic)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
prestera_hw_fdb_del(struct prestera_port * port,const unsigned char * mac,u16 vid)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
prestera_hw_fdb_flush_port(struct prestera_port * port,u32 mode)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
prestera_hw_fdb_flush_vlan(struct prestera_switch * sw,u16 vid,u32 mode)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
prestera_hw_fdb_flush_port_vlan(struct prestera_port * port,u16 vid,u32 mode)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
prestera_hw_bridge_create(struct prestera_switch * sw,u16 * bridge_id)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
prestera_hw_bridge_delete(struct prestera_switch * sw,u16 bridge_id)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
prestera_hw_bridge_port_add(struct prestera_port * port,u16 bridge_id)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
prestera_hw_bridge_port_delete(struct prestera_port * port,u16 bridge_id)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
prestera_hw_rxtx_init(struct prestera_switch * sw,struct prestera_rxtx_params * params)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
prestera_hw_rxtx_port_init(struct prestera_port * port)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
prestera_hw_event_handler_register(struct prestera_switch * sw,enum prestera_event_type type,prestera_event_cb_t fn,void * arg)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
prestera_hw_event_handler_unregister(struct prestera_switch * sw,enum prestera_event_type type,prestera_event_cb_t fn)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