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