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