2553 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* 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#include "prestera_acl.h"12#include "prestera_counter.h"13#include "prestera_router_hw.h"14 15#define PRESTERA_SWITCH_INIT_TIMEOUT_MS (30 * 1000)16 17#define PRESTERA_MIN_MTU 6418 19#define PRESTERA_MSG_CHUNK_SIZE 102420 21enum prestera_cmd_type_t {22 PRESTERA_CMD_TYPE_SWITCH_INIT = 0x1,23 PRESTERA_CMD_TYPE_SWITCH_ATTR_SET = 0x2,24 25 PRESTERA_CMD_TYPE_PORT_ATTR_SET = 0x100,26 PRESTERA_CMD_TYPE_PORT_ATTR_GET = 0x101,27 PRESTERA_CMD_TYPE_PORT_INFO_GET = 0x110,28 29 PRESTERA_CMD_TYPE_VLAN_CREATE = 0x200,30 PRESTERA_CMD_TYPE_VLAN_DELETE = 0x201,31 PRESTERA_CMD_TYPE_VLAN_PORT_SET = 0x202,32 PRESTERA_CMD_TYPE_VLAN_PVID_SET = 0x203,33 34 PRESTERA_CMD_TYPE_FDB_ADD = 0x300,35 PRESTERA_CMD_TYPE_FDB_DELETE = 0x301,36 PRESTERA_CMD_TYPE_FDB_FLUSH_PORT = 0x310,37 PRESTERA_CMD_TYPE_FDB_FLUSH_VLAN = 0x311,38 PRESTERA_CMD_TYPE_FDB_FLUSH_PORT_VLAN = 0x312,39 40 PRESTERA_CMD_TYPE_BRIDGE_CREATE = 0x400,41 PRESTERA_CMD_TYPE_BRIDGE_DELETE = 0x401,42 PRESTERA_CMD_TYPE_BRIDGE_PORT_ADD = 0x402,43 PRESTERA_CMD_TYPE_BRIDGE_PORT_DELETE = 0x403,44 45 PRESTERA_CMD_TYPE_COUNTER_GET = 0x510,46 PRESTERA_CMD_TYPE_COUNTER_ABORT = 0x511,47 PRESTERA_CMD_TYPE_COUNTER_TRIGGER = 0x512,48 PRESTERA_CMD_TYPE_COUNTER_BLOCK_GET = 0x513,49 PRESTERA_CMD_TYPE_COUNTER_BLOCK_RELEASE = 0x514,50 PRESTERA_CMD_TYPE_COUNTER_CLEAR = 0x515,51 52 PRESTERA_CMD_TYPE_VTCAM_CREATE = 0x540,53 PRESTERA_CMD_TYPE_VTCAM_DESTROY = 0x541,54 PRESTERA_CMD_TYPE_VTCAM_RULE_ADD = 0x550,55 PRESTERA_CMD_TYPE_VTCAM_RULE_DELETE = 0x551,56 PRESTERA_CMD_TYPE_VTCAM_IFACE_BIND = 0x560,57 PRESTERA_CMD_TYPE_VTCAM_IFACE_UNBIND = 0x561,58 59 PRESTERA_CMD_TYPE_ROUTER_RIF_CREATE = 0x600,60 PRESTERA_CMD_TYPE_ROUTER_RIF_DELETE = 0x601,61 PRESTERA_CMD_TYPE_ROUTER_LPM_ADD = 0x610,62 PRESTERA_CMD_TYPE_ROUTER_LPM_DELETE = 0x611,63 PRESTERA_CMD_TYPE_ROUTER_NH_GRP_SET = 0x622,64 PRESTERA_CMD_TYPE_ROUTER_NH_GRP_BLK_GET = 0x645,65 PRESTERA_CMD_TYPE_ROUTER_NH_GRP_ADD = 0x623,66 PRESTERA_CMD_TYPE_ROUTER_NH_GRP_DELETE = 0x624,67 PRESTERA_CMD_TYPE_ROUTER_VR_CREATE = 0x630,68 PRESTERA_CMD_TYPE_ROUTER_VR_DELETE = 0x631,69 70 PRESTERA_CMD_TYPE_FLOOD_DOMAIN_CREATE = 0x700,71 PRESTERA_CMD_TYPE_FLOOD_DOMAIN_DESTROY = 0x701,72 PRESTERA_CMD_TYPE_FLOOD_DOMAIN_PORTS_SET = 0x702,73 PRESTERA_CMD_TYPE_FLOOD_DOMAIN_PORTS_RESET = 0x703,74 75 PRESTERA_CMD_TYPE_MDB_CREATE = 0x704,76 PRESTERA_CMD_TYPE_MDB_DESTROY = 0x705,77 78 PRESTERA_CMD_TYPE_RXTX_INIT = 0x800,79 80 PRESTERA_CMD_TYPE_LAG_MEMBER_ADD = 0x900,81 PRESTERA_CMD_TYPE_LAG_MEMBER_DELETE = 0x901,82 PRESTERA_CMD_TYPE_LAG_MEMBER_ENABLE = 0x902,83 PRESTERA_CMD_TYPE_LAG_MEMBER_DISABLE = 0x903,84 85 PRESTERA_CMD_TYPE_STP_PORT_SET = 0x1000,86 87 PRESTERA_CMD_TYPE_SPAN_GET = 0x1100,88 PRESTERA_CMD_TYPE_SPAN_INGRESS_BIND = 0x1101,89 PRESTERA_CMD_TYPE_SPAN_INGRESS_UNBIND = 0x1102,90 PRESTERA_CMD_TYPE_SPAN_RELEASE = 0x1103,91 PRESTERA_CMD_TYPE_SPAN_EGRESS_BIND = 0x1104,92 PRESTERA_CMD_TYPE_SPAN_EGRESS_UNBIND = 0x1105,93 94 PRESTERA_CMD_TYPE_POLICER_CREATE = 0x1500,95 PRESTERA_CMD_TYPE_POLICER_RELEASE = 0x1501,96 PRESTERA_CMD_TYPE_POLICER_SET = 0x1502,97 98 PRESTERA_CMD_TYPE_CPU_CODE_COUNTERS_GET = 0x2000,99 100 PRESTERA_CMD_TYPE_ACK = 0x10000,101 PRESTERA_CMD_TYPE_MAX102};103 104enum {105 PRESTERA_CMD_PORT_ATTR_ADMIN_STATE = 1,106 PRESTERA_CMD_PORT_ATTR_MTU = 3,107 PRESTERA_CMD_PORT_ATTR_MAC = 4,108 PRESTERA_CMD_PORT_ATTR_SPEED = 5,109 PRESTERA_CMD_PORT_ATTR_ACCEPT_FRAME_TYPE = 6,110 PRESTERA_CMD_PORT_ATTR_LEARNING = 7,111 PRESTERA_CMD_PORT_ATTR_FLOOD = 8,112 PRESTERA_CMD_PORT_ATTR_CAPABILITY = 9,113 PRESTERA_CMD_PORT_ATTR_LOCKED = 10,114 PRESTERA_CMD_PORT_ATTR_PHY_MODE = 12,115 PRESTERA_CMD_PORT_ATTR_TYPE = 13,116 PRESTERA_CMD_PORT_ATTR_STATS = 17,117 PRESTERA_CMD_PORT_ATTR_MAC_AUTONEG_RESTART = 18,118 PRESTERA_CMD_PORT_ATTR_PHY_AUTONEG_RESTART = 19,119 PRESTERA_CMD_PORT_ATTR_MAC_MODE = 22,120};121 122enum {123 PRESTERA_CMD_SWITCH_ATTR_MAC = 1,124 PRESTERA_CMD_SWITCH_ATTR_AGEING = 2,125};126 127enum {128 PRESTERA_CMD_ACK_OK,129 PRESTERA_CMD_ACK_FAILED,130 131 PRESTERA_CMD_ACK_MAX132};133 134enum {135 PRESTERA_PORT_TP_NA,136 PRESTERA_PORT_TP_MDI,137 PRESTERA_PORT_TP_MDIX,138 PRESTERA_PORT_TP_AUTO,139};140 141enum {142 PRESTERA_PORT_FLOOD_TYPE_UC = 0,143 PRESTERA_PORT_FLOOD_TYPE_MC = 1,144};145 146enum {147 PRESTERA_PORT_GOOD_OCTETS_RCV_CNT,148 PRESTERA_PORT_BAD_OCTETS_RCV_CNT,149 PRESTERA_PORT_MAC_TRANSMIT_ERR_CNT,150 PRESTERA_PORT_BRDC_PKTS_RCV_CNT,151 PRESTERA_PORT_MC_PKTS_RCV_CNT,152 PRESTERA_PORT_PKTS_64L_CNT,153 PRESTERA_PORT_PKTS_65TO127L_CNT,154 PRESTERA_PORT_PKTS_128TO255L_CNT,155 PRESTERA_PORT_PKTS_256TO511L_CNT,156 PRESTERA_PORT_PKTS_512TO1023L_CNT,157 PRESTERA_PORT_PKTS_1024TOMAXL_CNT,158 PRESTERA_PORT_EXCESSIVE_COLLISIONS_CNT,159 PRESTERA_PORT_MC_PKTS_SENT_CNT,160 PRESTERA_PORT_BRDC_PKTS_SENT_CNT,161 PRESTERA_PORT_FC_SENT_CNT,162 PRESTERA_PORT_GOOD_FC_RCV_CNT,163 PRESTERA_PORT_DROP_EVENTS_CNT,164 PRESTERA_PORT_UNDERSIZE_PKTS_CNT,165 PRESTERA_PORT_FRAGMENTS_PKTS_CNT,166 PRESTERA_PORT_OVERSIZE_PKTS_CNT,167 PRESTERA_PORT_JABBER_PKTS_CNT,168 PRESTERA_PORT_MAC_RCV_ERROR_CNT,169 PRESTERA_PORT_BAD_CRC_CNT,170 PRESTERA_PORT_COLLISIONS_CNT,171 PRESTERA_PORT_LATE_COLLISIONS_CNT,172 PRESTERA_PORT_GOOD_UC_PKTS_RCV_CNT,173 PRESTERA_PORT_GOOD_UC_PKTS_SENT_CNT,174 PRESTERA_PORT_MULTIPLE_PKTS_SENT_CNT,175 PRESTERA_PORT_DEFERRED_PKTS_SENT_CNT,176 PRESTERA_PORT_GOOD_OCTETS_SENT_CNT,177 178 PRESTERA_PORT_CNT_MAX179};180 181enum {182 PRESTERA_FC_NONE,183 PRESTERA_FC_SYMMETRIC,184 PRESTERA_FC_ASYMMETRIC,185 PRESTERA_FC_SYMM_ASYMM,186};187 188enum {189 PRESTERA_POLICER_MODE_SR_TCM190};191 192enum {193 PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT = 0,194 PRESTERA_HW_FDB_ENTRY_TYPE_LAG = 1,195 PRESTERA_HW_FDB_ENTRY_TYPE_MAX = 2,196};197 198struct prestera_fw_event_handler {199 struct list_head list;200 struct rcu_head rcu;201 enum prestera_event_type type;202 prestera_event_cb_t func;203 void *arg;204};205 206enum {207 PRESTERA_HW_FLOOD_DOMAIN_PORT_TYPE_REG_PORT = 0,208 PRESTERA_HW_FLOOD_DOMAIN_PORT_TYPE_LAG = 1,209 PRESTERA_HW_FLOOD_DOMAIN_PORT_TYPE_MAX = 2,210};211 212struct prestera_msg_cmd {213 __le32 type;214};215 216struct prestera_msg_ret {217 struct prestera_msg_cmd cmd;218 __le32 status;219};220 221struct prestera_msg_common_req {222 struct prestera_msg_cmd cmd;223};224 225struct prestera_msg_common_resp {226 struct prestera_msg_ret ret;227};228 229struct prestera_msg_switch_attr_req {230 struct prestera_msg_cmd cmd;231 __le32 attr;232 union {233 __le32 ageing_timeout_ms;234 struct {235 u8 mac[ETH_ALEN];236 u8 __pad[2];237 };238 } param;239};240 241struct prestera_msg_switch_init_resp {242 struct prestera_msg_ret ret;243 __le32 port_count;244 __le32 mtu_max;245 __le32 size_tbl_router_nexthop;246 u8 switch_id;247 u8 lag_max;248 u8 lag_member_max;249};250 251struct prestera_msg_event_port_param {252 union {253 struct {254 __le32 mode;255 __le32 speed;256 u8 oper;257 u8 duplex;258 u8 fc;259 u8 fec;260 } mac;261 struct {262 __le64 lmode_bmap;263 u8 mdix;264 u8 fc;265 u8 __pad[2];266 } __packed phy; /* make sure always 12 bytes size */267 };268};269 270struct prestera_msg_port_cap_param {271 __le64 link_mode;272 u8 type;273 u8 fec;274 u8 fc;275 u8 transceiver;276};277 278struct prestera_msg_port_flood_param {279 u8 type;280 u8 enable;281 u8 __pad[2];282};283 284union prestera_msg_port_param {285 __le32 mtu;286 __le32 speed;287 __le32 link_mode;288 u8 admin_state;289 u8 oper_state;290 u8 mac[ETH_ALEN];291 u8 accept_frm_type;292 u8 learning;293 u8 flood;294 u8 type;295 u8 duplex;296 u8 fec;297 u8 fc;298 u8 br_locked;299 union {300 struct {301 u8 admin;302 u8 fc;303 u8 ap_enable;304 u8 __reserved[5];305 union {306 struct {307 __le32 mode;308 __le32 speed;309 u8 inband;310 u8 duplex;311 u8 fec;312 u8 fec_supp;313 } reg_mode;314 struct {315 __le32 mode;316 __le32 speed;317 u8 fec;318 u8 fec_supp;319 u8 __pad[2];320 } ap_modes[PRESTERA_AP_PORT_MAX];321 };322 } mac;323 struct {324 __le64 modes;325 __le32 mode;326 u8 admin;327 u8 adv_enable;328 u8 mdix;329 u8 __pad;330 } phy;331 } link;332 333 struct prestera_msg_port_cap_param cap;334 struct prestera_msg_port_flood_param flood_ext;335 struct prestera_msg_event_port_param link_evt;336};337 338struct prestera_msg_port_attr_req {339 struct prestera_msg_cmd cmd;340 __le32 attr;341 __le32 port;342 __le32 dev;343 union prestera_msg_port_param param;344};345 346struct prestera_msg_port_attr_resp {347 struct prestera_msg_ret ret;348 union prestera_msg_port_param param;349};350 351struct prestera_msg_port_stats_resp {352 struct prestera_msg_ret ret;353 __le64 stats[PRESTERA_PORT_CNT_MAX];354};355 356struct prestera_msg_port_info_req {357 struct prestera_msg_cmd cmd;358 __le32 port;359};360 361struct prestera_msg_port_info_resp {362 struct prestera_msg_ret ret;363 __le32 hw_id;364 __le32 dev_id;365 __le16 fp_id;366 u8 pad[2];367};368 369struct prestera_msg_vlan_req {370 struct prestera_msg_cmd cmd;371 __le32 port;372 __le32 dev;373 __le16 vid;374 u8 is_member;375 u8 is_tagged;376};377 378struct prestera_msg_fdb_req {379 struct prestera_msg_cmd cmd;380 __le32 flush_mode;381 union {382 struct {383 __le32 port;384 __le32 dev;385 };386 __le16 lag_id;387 } dest;388 __le16 vid;389 u8 dest_type;390 u8 dynamic;391 u8 mac[ETH_ALEN];392 u8 __pad[2];393};394 395struct prestera_msg_bridge_req {396 struct prestera_msg_cmd cmd;397 __le32 port;398 __le32 dev;399 __le16 bridge;400 u8 pad[2];401};402 403struct prestera_msg_bridge_resp {404 struct prestera_msg_ret ret;405 __le16 bridge;406 u8 pad[2];407};408 409struct prestera_msg_vtcam_create_req {410 struct prestera_msg_cmd cmd;411 __le32 keymask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX];412 u8 direction;413 u8 lookup;414 u8 pad[2];415};416 417struct prestera_msg_vtcam_destroy_req {418 struct prestera_msg_cmd cmd;419 __le32 vtcam_id;420};421 422struct prestera_msg_vtcam_rule_del_req {423 struct prestera_msg_cmd cmd;424 __le32 vtcam_id;425 __le32 id;426};427 428struct prestera_msg_vtcam_bind_req {429 struct prestera_msg_cmd cmd;430 union {431 struct {432 __le32 hw_id;433 __le32 dev_id;434 } port;435 __le32 index;436 };437 __le32 vtcam_id;438 __le16 pcl_id;439 __le16 type;440};441 442struct prestera_msg_vtcam_resp {443 struct prestera_msg_ret ret;444 __le32 vtcam_id;445 __le32 rule_id;446};447 448struct prestera_msg_acl_action {449 __le32 id;450 __le32 __reserved;451 union {452 struct {453 __le32 index;454 } jump;455 struct {456 __le32 id;457 } police;458 struct {459 __le32 id;460 } count;461 __le32 reserved[6];462 };463};464 465struct prestera_msg_vtcam_rule_add_req {466 struct prestera_msg_cmd cmd;467 __le32 key[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX];468 __le32 keymask[__PRESTERA_ACL_RULE_MATCH_TYPE_MAX];469 __le32 vtcam_id;470 __le32 prio;471 __le32 n_act;472 struct prestera_msg_acl_action actions_msg[] __counted_by_le(n_act);473};474 475struct prestera_msg_counter_req {476 struct prestera_msg_cmd cmd;477 __le32 client;478 __le32 block_id;479 __le32 num_counters;480};481 482struct prestera_msg_counter_stats {483 __le64 packets;484 __le64 bytes;485};486 487struct prestera_msg_counter_resp {488 struct prestera_msg_ret ret;489 __le32 block_id;490 __le32 offset;491 __le32 num_counters;492 __le32 done;493 struct prestera_msg_counter_stats stats[];494};495 496struct prestera_msg_span_req {497 struct prestera_msg_cmd cmd;498 __le32 port;499 __le32 dev;500 u8 id;501 u8 pad[3];502};503 504struct prestera_msg_span_resp {505 struct prestera_msg_ret ret;506 u8 id;507 u8 pad[3];508};509 510struct prestera_msg_stp_req {511 struct prestera_msg_cmd cmd;512 __le32 port;513 __le32 dev;514 __le16 vid;515 u8 state;516 u8 __pad;517};518 519struct prestera_msg_rxtx_req {520 struct prestera_msg_cmd cmd;521 u8 use_sdma;522 u8 pad[3];523};524 525struct prestera_msg_rxtx_resp {526 struct prestera_msg_ret ret;527 __le32 map_addr;528};529 530struct prestera_msg_iface {531 union {532 struct {533 __le32 dev;534 __le32 port;535 };536 __le16 lag_id;537 };538 __le16 vr_id;539 __le16 vid;540 u8 type;541 u8 __pad[3];542};543 544struct prestera_msg_ip_addr {545 union {546 __be32 ipv4;547 __be32 ipv6[4];548 } u;549 u8 v; /* e.g. PRESTERA_IPV4 */550 u8 __pad[3];551};552 553struct prestera_msg_nh {554 struct prestera_msg_iface oif;555 __le32 hw_id;556 u8 mac[ETH_ALEN];557 u8 is_active;558 u8 pad;559};560 561struct prestera_msg_rif_req {562 struct prestera_msg_cmd cmd;563 struct prestera_msg_iface iif;564 __le32 mtu;565 __le16 rif_id;566 __le16 __reserved;567 u8 mac[ETH_ALEN];568 u8 __pad[2];569};570 571struct prestera_msg_rif_resp {572 struct prestera_msg_ret ret;573 __le16 rif_id;574 u8 __pad[2];575};576 577struct prestera_msg_lpm_req {578 struct prestera_msg_cmd cmd;579 struct prestera_msg_ip_addr dst;580 __le32 grp_id;581 __le32 dst_len;582 __le16 vr_id;583 u8 __pad[2];584};585 586struct prestera_msg_nh_req {587 struct prestera_msg_cmd cmd;588 struct prestera_msg_nh nh[PRESTERA_NHGR_SIZE_MAX];589 __le32 size;590 __le32 grp_id;591};592 593struct prestera_msg_nh_chunk_req {594 struct prestera_msg_cmd cmd;595 __le32 offset;596};597 598struct prestera_msg_nh_chunk_resp {599 struct prestera_msg_ret ret;600 u8 hw_state[PRESTERA_MSG_CHUNK_SIZE];601};602 603struct prestera_msg_nh_grp_req {604 struct prestera_msg_cmd cmd;605 __le32 grp_id;606 __le32 size;607};608 609struct prestera_msg_nh_grp_resp {610 struct prestera_msg_ret ret;611 __le32 grp_id;612};613 614struct prestera_msg_vr_req {615 struct prestera_msg_cmd cmd;616 __le16 vr_id;617 u8 __pad[2];618};619 620struct prestera_msg_vr_resp {621 struct prestera_msg_ret ret;622 __le16 vr_id;623 u8 __pad[2];624};625 626struct prestera_msg_lag_req {627 struct prestera_msg_cmd cmd;628 __le32 port;629 __le32 dev;630 __le16 lag_id;631 u8 pad[2];632};633 634struct prestera_msg_cpu_code_counter_req {635 struct prestera_msg_cmd cmd;636 u8 counter_type;637 u8 code;638 u8 pad[2];639};640 641struct mvsw_msg_cpu_code_counter_ret {642 struct prestera_msg_ret ret;643 __le64 packet_count;644};645 646struct prestera_msg_policer_req {647 struct prestera_msg_cmd cmd;648 __le32 id;649 union {650 struct {651 __le64 cir;652 __le32 cbs;653 } __packed sr_tcm; /* make sure always 12 bytes size */654 __le32 reserved[6];655 };656 u8 mode;657 u8 type;658 u8 pad[2];659};660 661struct prestera_msg_policer_resp {662 struct prestera_msg_ret ret;663 __le32 id;664};665 666struct prestera_msg_event {667 __le16 type;668 __le16 id;669};670 671struct prestera_msg_event_port {672 struct prestera_msg_event id;673 __le32 port_id;674 struct prestera_msg_event_port_param param;675};676 677union prestera_msg_event_fdb_param {678 u8 mac[ETH_ALEN];679};680 681struct prestera_msg_event_fdb {682 struct prestera_msg_event id;683 __le32 vid;684 union {685 __le32 port_id;686 __le16 lag_id;687 } dest;688 union prestera_msg_event_fdb_param param;689 u8 dest_type;690};691 692struct prestera_msg_flood_domain_create_req {693 struct prestera_msg_cmd cmd;694};695 696struct prestera_msg_flood_domain_create_resp {697 struct prestera_msg_ret ret;698 __le32 flood_domain_idx;699};700 701struct prestera_msg_flood_domain_destroy_req {702 struct prestera_msg_cmd cmd;703 __le32 flood_domain_idx;704};705 706struct prestera_msg_flood_domain_ports_reset_req {707 struct prestera_msg_cmd cmd;708 __le32 flood_domain_idx;709};710 711struct prestera_msg_flood_domain_port {712 union {713 struct {714 __le32 port_num;715 __le32 dev_num;716 };717 __le16 lag_id;718 };719 __le16 vid;720 __le16 port_type;721};722 723struct prestera_msg_flood_domain_ports_set_req {724 struct prestera_msg_cmd cmd;725 __le32 flood_domain_idx;726 __le32 ports_num;727 struct prestera_msg_flood_domain_port ports[] __counted_by_le(ports_num);728};729 730struct prestera_msg_mdb_create_req {731 struct prestera_msg_cmd cmd;732 __le32 flood_domain_idx;733 __le16 vid;734 u8 mac[ETH_ALEN];735};736 737struct prestera_msg_mdb_destroy_req {738 struct prestera_msg_cmd cmd;739 __le32 flood_domain_idx;740 __le16 vid;741 u8 mac[ETH_ALEN];742};743 744static void prestera_hw_build_tests(void)745{746 /* check requests */747 BUILD_BUG_ON(sizeof(struct prestera_msg_common_req) != 4);748 BUILD_BUG_ON(sizeof(struct prestera_msg_switch_attr_req) != 16);749 BUILD_BUG_ON(sizeof(struct prestera_msg_port_attr_req) != 144);750 BUILD_BUG_ON(sizeof(struct prestera_msg_port_info_req) != 8);751 BUILD_BUG_ON(sizeof(struct prestera_msg_vlan_req) != 16);752 BUILD_BUG_ON(sizeof(struct prestera_msg_fdb_req) != 28);753 BUILD_BUG_ON(sizeof(struct prestera_msg_bridge_req) != 16);754 BUILD_BUG_ON(sizeof(struct prestera_msg_span_req) != 16);755 BUILD_BUG_ON(sizeof(struct prestera_msg_stp_req) != 16);756 BUILD_BUG_ON(sizeof(struct prestera_msg_rxtx_req) != 8);757 BUILD_BUG_ON(sizeof(struct prestera_msg_lag_req) != 16);758 BUILD_BUG_ON(sizeof(struct prestera_msg_cpu_code_counter_req) != 8);759 BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_create_req) != 84);760 BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_destroy_req) != 8);761 BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_rule_add_req) != 168);762 BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_rule_del_req) != 12);763 BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_bind_req) != 20);764 BUILD_BUG_ON(sizeof(struct prestera_msg_acl_action) != 32);765 BUILD_BUG_ON(sizeof(struct prestera_msg_counter_req) != 16);766 BUILD_BUG_ON(sizeof(struct prestera_msg_counter_stats) != 16);767 BUILD_BUG_ON(sizeof(struct prestera_msg_rif_req) != 36);768 BUILD_BUG_ON(sizeof(struct prestera_msg_vr_req) != 8);769 BUILD_BUG_ON(sizeof(struct prestera_msg_lpm_req) != 36);770 BUILD_BUG_ON(sizeof(struct prestera_msg_policer_req) != 36);771 BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_create_req) != 4);772 BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_destroy_req) != 8);773 BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_ports_set_req) != 12);774 BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_ports_reset_req) != 8);775 BUILD_BUG_ON(sizeof(struct prestera_msg_mdb_create_req) != 16);776 BUILD_BUG_ON(sizeof(struct prestera_msg_mdb_destroy_req) != 16);777 BUILD_BUG_ON(sizeof(struct prestera_msg_nh_req) != 124);778 BUILD_BUG_ON(sizeof(struct prestera_msg_nh_chunk_req) != 8);779 BUILD_BUG_ON(sizeof(struct prestera_msg_nh_grp_req) != 12);780 781 /* structure that are part of req/resp fw messages */782 BUILD_BUG_ON(sizeof(struct prestera_msg_iface) != 16);783 BUILD_BUG_ON(sizeof(struct prestera_msg_ip_addr) != 20);784 BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_port) != 12);785 BUILD_BUG_ON(sizeof(struct prestera_msg_nh) != 28);786 787 /* check responses */788 BUILD_BUG_ON(sizeof(struct prestera_msg_common_resp) != 8);789 BUILD_BUG_ON(sizeof(struct prestera_msg_switch_init_resp) != 24);790 BUILD_BUG_ON(sizeof(struct prestera_msg_port_attr_resp) != 136);791 BUILD_BUG_ON(sizeof(struct prestera_msg_port_stats_resp) != 248);792 BUILD_BUG_ON(sizeof(struct prestera_msg_port_info_resp) != 20);793 BUILD_BUG_ON(sizeof(struct prestera_msg_bridge_resp) != 12);794 BUILD_BUG_ON(sizeof(struct prestera_msg_span_resp) != 12);795 BUILD_BUG_ON(sizeof(struct prestera_msg_rxtx_resp) != 12);796 BUILD_BUG_ON(sizeof(struct prestera_msg_vtcam_resp) != 16);797 BUILD_BUG_ON(sizeof(struct prestera_msg_counter_resp) != 24);798 BUILD_BUG_ON(sizeof(struct prestera_msg_rif_resp) != 12);799 BUILD_BUG_ON(sizeof(struct prestera_msg_vr_resp) != 12);800 BUILD_BUG_ON(sizeof(struct prestera_msg_policer_resp) != 12);801 BUILD_BUG_ON(sizeof(struct prestera_msg_flood_domain_create_resp) != 12);802 BUILD_BUG_ON(sizeof(struct prestera_msg_nh_chunk_resp) != 1032);803 BUILD_BUG_ON(sizeof(struct prestera_msg_nh_grp_resp) != 12);804 805 /* check events */806 BUILD_BUG_ON(sizeof(struct prestera_msg_event_port) != 20);807 BUILD_BUG_ON(sizeof(struct prestera_msg_event_fdb) != 20);808}809 810static u8 prestera_hw_mdix_to_eth(u8 mode);811static void prestera_hw_remote_fc_to_eth(u8 fc, bool *pause, bool *asym_pause);812 813static int __prestera_cmd_ret(struct prestera_switch *sw,814 enum prestera_cmd_type_t type,815 struct prestera_msg_cmd *cmd, size_t clen,816 struct prestera_msg_ret *ret, size_t rlen,817 int waitms)818{819 struct prestera_device *dev = sw->dev;820 int err;821 822 cmd->type = __cpu_to_le32(type);823 824 err = dev->send_req(dev, 0, cmd, clen, ret, rlen, waitms);825 if (err)826 return err;827 828 if (ret->cmd.type != __cpu_to_le32(PRESTERA_CMD_TYPE_ACK))829 return -EBADE;830 if (ret->status != __cpu_to_le32(PRESTERA_CMD_ACK_OK))831 return -EINVAL;832 833 return 0;834}835 836static int prestera_cmd_ret(struct prestera_switch *sw,837 enum prestera_cmd_type_t type,838 struct prestera_msg_cmd *cmd, size_t clen,839 struct prestera_msg_ret *ret, size_t rlen)840{841 return __prestera_cmd_ret(sw, type, cmd, clen, ret, rlen, 0);842}843 844static int prestera_cmd_ret_wait(struct prestera_switch *sw,845 enum prestera_cmd_type_t type,846 struct prestera_msg_cmd *cmd, size_t clen,847 struct prestera_msg_ret *ret, size_t rlen,848 int waitms)849{850 return __prestera_cmd_ret(sw, type, cmd, clen, ret, rlen, waitms);851}852 853static int prestera_cmd(struct prestera_switch *sw,854 enum prestera_cmd_type_t type,855 struct prestera_msg_cmd *cmd, size_t clen)856{857 struct prestera_msg_common_resp resp;858 859 return prestera_cmd_ret(sw, type, cmd, clen, &resp.ret, sizeof(resp));860}861 862static int prestera_fw_parse_port_evt(void *msg, struct prestera_event *evt)863{864 struct prestera_msg_event_port *hw_evt;865 866 hw_evt = (struct prestera_msg_event_port *)msg;867 868 evt->port_evt.port_id = __le32_to_cpu(hw_evt->port_id);869 870 if (evt->id == PRESTERA_PORT_EVENT_MAC_STATE_CHANGED) {871 evt->port_evt.data.mac.oper = hw_evt->param.mac.oper;872 evt->port_evt.data.mac.mode =873 __le32_to_cpu(hw_evt->param.mac.mode);874 evt->port_evt.data.mac.speed =875 __le32_to_cpu(hw_evt->param.mac.speed);876 evt->port_evt.data.mac.duplex = hw_evt->param.mac.duplex;877 evt->port_evt.data.mac.fc = hw_evt->param.mac.fc;878 evt->port_evt.data.mac.fec = hw_evt->param.mac.fec;879 } else {880 return -EINVAL;881 }882 883 return 0;884}885 886static int prestera_fw_parse_fdb_evt(void *msg, struct prestera_event *evt)887{888 struct prestera_msg_event_fdb *hw_evt = msg;889 890 switch (hw_evt->dest_type) {891 case PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT:892 evt->fdb_evt.type = PRESTERA_FDB_ENTRY_TYPE_REG_PORT;893 evt->fdb_evt.dest.port_id = __le32_to_cpu(hw_evt->dest.port_id);894 break;895 case PRESTERA_HW_FDB_ENTRY_TYPE_LAG:896 evt->fdb_evt.type = PRESTERA_FDB_ENTRY_TYPE_LAG;897 evt->fdb_evt.dest.lag_id = __le16_to_cpu(hw_evt->dest.lag_id);898 break;899 default:900 return -EINVAL;901 }902 903 evt->fdb_evt.vid = __le32_to_cpu(hw_evt->vid);904 905 ether_addr_copy(evt->fdb_evt.data.mac, hw_evt->param.mac);906 907 return 0;908}909 910static struct prestera_fw_evt_parser {911 int (*func)(void *msg, struct prestera_event *evt);912} fw_event_parsers[PRESTERA_EVENT_TYPE_MAX] = {913 [PRESTERA_EVENT_TYPE_PORT] = { .func = prestera_fw_parse_port_evt },914 [PRESTERA_EVENT_TYPE_FDB] = { .func = prestera_fw_parse_fdb_evt },915};916 917static struct prestera_fw_event_handler *918__find_event_handler(const struct prestera_switch *sw,919 enum prestera_event_type type)920{921 struct prestera_fw_event_handler *eh;922 923 list_for_each_entry_rcu(eh, &sw->event_handlers, list) {924 if (eh->type == type)925 return eh;926 }927 928 return NULL;929}930 931static int prestera_find_event_handler(const struct prestera_switch *sw,932 enum prestera_event_type type,933 struct prestera_fw_event_handler *eh)934{935 struct prestera_fw_event_handler *tmp;936 int err = 0;937 938 rcu_read_lock();939 tmp = __find_event_handler(sw, type);940 if (tmp)941 *eh = *tmp;942 else943 err = -ENOENT;944 rcu_read_unlock();945 946 return err;947}948 949static int prestera_evt_recv(struct prestera_device *dev, void *buf, size_t size)950{951 struct prestera_switch *sw = dev->priv;952 struct prestera_msg_event *msg = buf;953 struct prestera_fw_event_handler eh;954 struct prestera_event evt;955 u16 msg_type;956 int err;957 958 msg_type = __le16_to_cpu(msg->type);959 if (msg_type >= PRESTERA_EVENT_TYPE_MAX)960 return -EINVAL;961 if (!fw_event_parsers[msg_type].func)962 return -ENOENT;963 964 err = prestera_find_event_handler(sw, msg_type, &eh);965 if (err)966 return err;967 968 evt.id = __le16_to_cpu(msg->id);969 970 err = fw_event_parsers[msg_type].func(buf, &evt);971 if (err)972 return err;973 974 eh.func(sw, &evt, eh.arg);975 976 return 0;977}978 979static void prestera_pkt_recv(struct prestera_device *dev)980{981 struct prestera_switch *sw = dev->priv;982 struct prestera_fw_event_handler eh;983 struct prestera_event ev;984 int err;985 986 ev.id = PRESTERA_RXTX_EVENT_RCV_PKT;987 988 err = prestera_find_event_handler(sw, PRESTERA_EVENT_TYPE_RXTX, &eh);989 if (err)990 return;991 992 eh.func(sw, &ev, eh.arg);993}994 995static u8 prestera_hw_mdix_to_eth(u8 mode)996{997 switch (mode) {998 case PRESTERA_PORT_TP_MDI:999 return ETH_TP_MDI;1000 case PRESTERA_PORT_TP_MDIX:1001 return ETH_TP_MDI_X;1002 case PRESTERA_PORT_TP_AUTO:1003 return ETH_TP_MDI_AUTO;1004 default:1005 return ETH_TP_MDI_INVALID;1006 }1007}1008 1009static u8 prestera_hw_mdix_from_eth(u8 mode)1010{1011 switch (mode) {1012 case ETH_TP_MDI:1013 return PRESTERA_PORT_TP_MDI;1014 case ETH_TP_MDI_X:1015 return PRESTERA_PORT_TP_MDIX;1016 case ETH_TP_MDI_AUTO:1017 return PRESTERA_PORT_TP_AUTO;1018 default:1019 return PRESTERA_PORT_TP_NA;1020 }1021}1022 1023int prestera_hw_port_info_get(const struct prestera_port *port,1024 u32 *dev_id, u32 *hw_id, u16 *fp_id)1025{1026 struct prestera_msg_port_info_req req = {1027 .port = __cpu_to_le32(port->id),1028 };1029 struct prestera_msg_port_info_resp resp;1030 int err;1031 1032 err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_INFO_GET,1033 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));1034 if (err)1035 return err;1036 1037 *dev_id = __le32_to_cpu(resp.dev_id);1038 *hw_id = __le32_to_cpu(resp.hw_id);1039 *fp_id = __le16_to_cpu(resp.fp_id);1040 1041 return 0;1042}1043 1044int prestera_hw_switch_mac_set(struct prestera_switch *sw, const char *mac)1045{1046 struct prestera_msg_switch_attr_req req = {1047 .attr = __cpu_to_le32(PRESTERA_CMD_SWITCH_ATTR_MAC),1048 };1049 1050 ether_addr_copy(req.param.mac, mac);1051 1052 return prestera_cmd(sw, PRESTERA_CMD_TYPE_SWITCH_ATTR_SET,1053 &req.cmd, sizeof(req));1054}1055 1056int prestera_hw_switch_init(struct prestera_switch *sw)1057{1058 struct prestera_msg_switch_init_resp resp;1059 struct prestera_msg_common_req req;1060 int err;1061 1062 INIT_LIST_HEAD(&sw->event_handlers);1063 1064 prestera_hw_build_tests();1065 1066 err = prestera_cmd_ret_wait(sw, PRESTERA_CMD_TYPE_SWITCH_INIT,1067 &req.cmd, sizeof(req),1068 &resp.ret, sizeof(resp),1069 PRESTERA_SWITCH_INIT_TIMEOUT_MS);1070 if (err)1071 return err;1072 1073 sw->dev->recv_msg = prestera_evt_recv;1074 sw->dev->recv_pkt = prestera_pkt_recv;1075 sw->port_count = __le32_to_cpu(resp.port_count);1076 sw->mtu_min = PRESTERA_MIN_MTU;1077 sw->mtu_max = __le32_to_cpu(resp.mtu_max);1078 sw->id = resp.switch_id;1079 sw->lag_member_max = resp.lag_member_max;1080 sw->lag_max = resp.lag_max;1081 sw->size_tbl_router_nexthop =1082 __le32_to_cpu(resp.size_tbl_router_nexthop);1083 1084 return 0;1085}1086 1087void prestera_hw_switch_fini(struct prestera_switch *sw)1088{1089 WARN_ON(!list_empty(&sw->event_handlers));1090}1091 1092int prestera_hw_switch_ageing_set(struct prestera_switch *sw, u32 ageing_ms)1093{1094 struct prestera_msg_switch_attr_req req = {1095 .attr = __cpu_to_le32(PRESTERA_CMD_SWITCH_ATTR_AGEING),1096 .param = {1097 .ageing_timeout_ms = __cpu_to_le32(ageing_ms),1098 },1099 };1100 1101 return prestera_cmd(sw, PRESTERA_CMD_TYPE_SWITCH_ATTR_SET,1102 &req.cmd, sizeof(req));1103}1104 1105int prestera_hw_port_mac_mode_get(const struct prestera_port *port,1106 u32 *mode, u32 *speed, u8 *duplex, u8 *fec)1107{1108 struct prestera_msg_port_attr_resp resp;1109 struct prestera_msg_port_attr_req req = {1110 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_MAC_MODE),1111 .port = __cpu_to_le32(port->hw_id),1112 .dev = __cpu_to_le32(port->dev_id)1113 };1114 int err;1115 1116 err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,1117 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));1118 if (err)1119 return err;1120 1121 if (mode)1122 *mode = __le32_to_cpu(resp.param.link_evt.mac.mode);1123 1124 if (speed)1125 *speed = __le32_to_cpu(resp.param.link_evt.mac.speed);1126 1127 if (duplex)1128 *duplex = resp.param.link_evt.mac.duplex;1129 1130 if (fec)1131 *fec = resp.param.link_evt.mac.fec;1132 1133 return err;1134}1135 1136int prestera_hw_port_mac_mode_set(const struct prestera_port *port,1137 bool admin, u32 mode, u8 inband,1138 u32 speed, u8 duplex, u8 fec)1139{1140 struct prestera_msg_port_attr_req req = {1141 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_MAC_MODE),1142 .port = __cpu_to_le32(port->hw_id),1143 .dev = __cpu_to_le32(port->dev_id),1144 .param = {1145 .link = {1146 .mac = {1147 .admin = admin,1148 .reg_mode.mode = __cpu_to_le32(mode),1149 .reg_mode.inband = inband,1150 .reg_mode.speed = __cpu_to_le32(speed),1151 .reg_mode.duplex = duplex,1152 .reg_mode.fec = fec1153 }1154 }1155 }1156 };1157 1158 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,1159 &req.cmd, sizeof(req));1160}1161 1162int prestera_hw_port_phy_mode_get(const struct prestera_port *port,1163 u8 *mdix, u64 *lmode_bmap,1164 bool *fc_pause, bool *fc_asym)1165{1166 struct prestera_msg_port_attr_resp resp;1167 struct prestera_msg_port_attr_req req = {1168 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_PHY_MODE),1169 .port = __cpu_to_le32(port->hw_id),1170 .dev = __cpu_to_le32(port->dev_id)1171 };1172 int err;1173 1174 err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,1175 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));1176 if (err)1177 return err;1178 1179 if (mdix)1180 *mdix = prestera_hw_mdix_to_eth(resp.param.link_evt.phy.mdix);1181 1182 if (lmode_bmap)1183 *lmode_bmap = __le64_to_cpu(resp.param.link_evt.phy.lmode_bmap);1184 1185 if (fc_pause && fc_asym)1186 prestera_hw_remote_fc_to_eth(resp.param.link_evt.phy.fc,1187 fc_pause, fc_asym);1188 1189 return err;1190}1191 1192int prestera_hw_port_phy_mode_set(const struct prestera_port *port,1193 bool admin, bool adv, u32 mode, u64 modes,1194 u8 mdix)1195{1196 struct prestera_msg_port_attr_req req = {1197 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_PHY_MODE),1198 .port = __cpu_to_le32(port->hw_id),1199 .dev = __cpu_to_le32(port->dev_id),1200 .param = {1201 .link = {1202 .phy = {1203 .admin = admin,1204 .adv_enable = adv ? 1 : 0,1205 .mode = __cpu_to_le32(mode),1206 .modes = __cpu_to_le64(modes),1207 }1208 }1209 }1210 };1211 1212 req.param.link.phy.mdix = prestera_hw_mdix_from_eth(mdix);1213 1214 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,1215 &req.cmd, sizeof(req));1216}1217 1218int prestera_hw_port_mtu_set(const struct prestera_port *port, u32 mtu)1219{1220 struct prestera_msg_port_attr_req req = {1221 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_MTU),1222 .port = __cpu_to_le32(port->hw_id),1223 .dev = __cpu_to_le32(port->dev_id),1224 .param = {1225 .mtu = __cpu_to_le32(mtu),1226 }1227 };1228 1229 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,1230 &req.cmd, sizeof(req));1231}1232 1233int prestera_hw_port_mac_set(const struct prestera_port *port, const char *mac)1234{1235 struct prestera_msg_port_attr_req req = {1236 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_MAC),1237 .port = __cpu_to_le32(port->hw_id),1238 .dev = __cpu_to_le32(port->dev_id),1239 };1240 1241 ether_addr_copy(req.param.mac, mac);1242 1243 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,1244 &req.cmd, sizeof(req));1245}1246 1247int prestera_hw_port_accept_frm_type(struct prestera_port *port,1248 enum prestera_accept_frm_type type)1249{1250 struct prestera_msg_port_attr_req req = {1251 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_ACCEPT_FRAME_TYPE),1252 .port = __cpu_to_le32(port->hw_id),1253 .dev = __cpu_to_le32(port->dev_id),1254 .param = {1255 .accept_frm_type = type,1256 }1257 };1258 1259 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,1260 &req.cmd, sizeof(req));1261}1262 1263int prestera_hw_port_cap_get(const struct prestera_port *port,1264 struct prestera_port_caps *caps)1265{1266 struct prestera_msg_port_attr_req req = {1267 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_CAPABILITY),1268 .port = __cpu_to_le32(port->hw_id),1269 .dev = __cpu_to_le32(port->dev_id),1270 };1271 struct prestera_msg_port_attr_resp resp;1272 int err;1273 1274 err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,1275 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));1276 if (err)1277 return err;1278 1279 caps->supp_link_modes = __le64_to_cpu(resp.param.cap.link_mode);1280 caps->transceiver = resp.param.cap.transceiver;1281 caps->supp_fec = resp.param.cap.fec;1282 caps->type = resp.param.cap.type;1283 1284 return err;1285}1286 1287static void prestera_hw_remote_fc_to_eth(u8 fc, bool *pause, bool *asym_pause)1288{1289 switch (fc) {1290 case PRESTERA_FC_SYMMETRIC:1291 *pause = true;1292 *asym_pause = false;1293 break;1294 case PRESTERA_FC_ASYMMETRIC:1295 *pause = false;1296 *asym_pause = true;1297 break;1298 case PRESTERA_FC_SYMM_ASYMM:1299 *pause = true;1300 *asym_pause = true;1301 break;1302 default:1303 *pause = false;1304 *asym_pause = false;1305 }1306}1307 1308int prestera_hw_vtcam_create(struct prestera_switch *sw,1309 u8 lookup, const u32 *keymask, u32 *vtcam_id,1310 enum prestera_hw_vtcam_direction_t dir)1311{1312 int err;1313 struct prestera_msg_vtcam_resp resp;1314 struct prestera_msg_vtcam_create_req req = {1315 .lookup = lookup,1316 .direction = dir,1317 };1318 1319 if (keymask)1320 memcpy(req.keymask, keymask, sizeof(req.keymask));1321 else1322 memset(req.keymask, 0, sizeof(req.keymask));1323 1324 err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_VTCAM_CREATE,1325 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));1326 if (err)1327 return err;1328 1329 *vtcam_id = __le32_to_cpu(resp.vtcam_id);1330 return 0;1331}1332 1333int prestera_hw_vtcam_destroy(struct prestera_switch *sw, u32 vtcam_id)1334{1335 struct prestera_msg_vtcam_destroy_req req = {1336 .vtcam_id = __cpu_to_le32(vtcam_id),1337 };1338 1339 return prestera_cmd(sw, PRESTERA_CMD_TYPE_VTCAM_DESTROY,1340 &req.cmd, sizeof(req));1341}1342 1343static int1344prestera_acl_rule_add_put_action(struct prestera_msg_acl_action *action,1345 struct prestera_acl_hw_action_info *info)1346{1347 action->id = __cpu_to_le32(info->id);1348 1349 switch (info->id) {1350 case PRESTERA_ACL_RULE_ACTION_ACCEPT:1351 case PRESTERA_ACL_RULE_ACTION_DROP:1352 case PRESTERA_ACL_RULE_ACTION_TRAP:1353 /* just rule action id, no specific data */1354 break;1355 case PRESTERA_ACL_RULE_ACTION_JUMP:1356 action->jump.index = __cpu_to_le32(info->jump.index);1357 break;1358 case PRESTERA_ACL_RULE_ACTION_POLICE:1359 action->police.id = __cpu_to_le32(info->police.id);1360 break;1361 case PRESTERA_ACL_RULE_ACTION_COUNT:1362 action->count.id = __cpu_to_le32(info->count.id);1363 break;1364 default:1365 return -EINVAL;1366 }1367 1368 return 0;1369}1370 1371int prestera_hw_vtcam_rule_add(struct prestera_switch *sw,1372 u32 vtcam_id, u32 prio, void *key, void *keymask,1373 struct prestera_acl_hw_action_info *act,1374 u8 n_act, u32 *rule_id)1375{1376 struct prestera_msg_vtcam_rule_add_req *req;1377 struct prestera_msg_vtcam_resp resp;1378 size_t size;1379 int err;1380 u8 i;1381 1382 size = struct_size(req, actions_msg, n_act);1383 req = kzalloc(size, GFP_KERNEL);1384 if (!req)1385 return -ENOMEM;1386 1387 req->n_act = __cpu_to_le32(n_act);1388 1389 /* put acl matches into the message */1390 memcpy(req->key, key, sizeof(req->key));1391 memcpy(req->keymask, keymask, sizeof(req->keymask));1392 1393 /* put acl actions into the message */1394 for (i = 0; i < n_act; i++) {1395 err = prestera_acl_rule_add_put_action(&req->actions_msg[i],1396 &act[i]);1397 if (err)1398 goto free_buff;1399 }1400 1401 req->vtcam_id = __cpu_to_le32(vtcam_id);1402 req->prio = __cpu_to_le32(prio);1403 1404 err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_VTCAM_RULE_ADD,1405 &req->cmd, size, &resp.ret, sizeof(resp));1406 if (err)1407 goto free_buff;1408 1409 *rule_id = __le32_to_cpu(resp.rule_id);1410free_buff:1411 kfree(req);1412 return err;1413}1414 1415int prestera_hw_vtcam_rule_del(struct prestera_switch *sw,1416 u32 vtcam_id, u32 rule_id)1417{1418 struct prestera_msg_vtcam_rule_del_req req = {1419 .vtcam_id = __cpu_to_le32(vtcam_id),1420 .id = __cpu_to_le32(rule_id)1421 };1422 1423 return prestera_cmd(sw, PRESTERA_CMD_TYPE_VTCAM_RULE_DELETE,1424 &req.cmd, sizeof(req));1425}1426 1427int prestera_hw_vtcam_iface_bind(struct prestera_switch *sw,1428 struct prestera_acl_iface *iface,1429 u32 vtcam_id, u16 pcl_id)1430{1431 struct prestera_msg_vtcam_bind_req req = {1432 .vtcam_id = __cpu_to_le32(vtcam_id),1433 .type = __cpu_to_le16(iface->type),1434 .pcl_id = __cpu_to_le16(pcl_id)1435 };1436 1437 if (iface->type == PRESTERA_ACL_IFACE_TYPE_PORT) {1438 req.port.dev_id = __cpu_to_le32(iface->port->dev_id);1439 req.port.hw_id = __cpu_to_le32(iface->port->hw_id);1440 } else {1441 req.index = __cpu_to_le32(iface->index);1442 }1443 1444 return prestera_cmd(sw, PRESTERA_CMD_TYPE_VTCAM_IFACE_BIND,1445 &req.cmd, sizeof(req));1446}1447 1448int prestera_hw_vtcam_iface_unbind(struct prestera_switch *sw,1449 struct prestera_acl_iface *iface,1450 u32 vtcam_id)1451{1452 struct prestera_msg_vtcam_bind_req req = {1453 .vtcam_id = __cpu_to_le32(vtcam_id),1454 .type = __cpu_to_le16(iface->type)1455 };1456 1457 if (iface->type == PRESTERA_ACL_IFACE_TYPE_PORT) {1458 req.port.dev_id = __cpu_to_le32(iface->port->dev_id);1459 req.port.hw_id = __cpu_to_le32(iface->port->hw_id);1460 } else {1461 req.index = __cpu_to_le32(iface->index);1462 }1463 1464 return prestera_cmd(sw, PRESTERA_CMD_TYPE_VTCAM_IFACE_UNBIND,1465 &req.cmd, sizeof(req));1466}1467 1468int prestera_hw_span_get(const struct prestera_port *port, u8 *span_id)1469{1470 struct prestera_msg_span_resp resp;1471 struct prestera_msg_span_req req = {1472 .port = __cpu_to_le32(port->hw_id),1473 .dev = __cpu_to_le32(port->dev_id),1474 };1475 int err;1476 1477 err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_SPAN_GET,1478 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));1479 if (err)1480 return err;1481 1482 *span_id = resp.id;1483 1484 return 0;1485}1486 1487int prestera_hw_span_bind(const struct prestera_port *port, u8 span_id,1488 bool ingress)1489{1490 struct prestera_msg_span_req req = {1491 .port = __cpu_to_le32(port->hw_id),1492 .dev = __cpu_to_le32(port->dev_id),1493 .id = span_id,1494 };1495 enum prestera_cmd_type_t cmd_type;1496 1497 if (ingress)1498 cmd_type = PRESTERA_CMD_TYPE_SPAN_INGRESS_BIND;1499 else1500 cmd_type = PRESTERA_CMD_TYPE_SPAN_EGRESS_BIND;1501 1502 return prestera_cmd(port->sw, cmd_type, &req.cmd, sizeof(req));1503 1504}1505 1506int prestera_hw_span_unbind(const struct prestera_port *port, bool ingress)1507{1508 struct prestera_msg_span_req req = {1509 .port = __cpu_to_le32(port->hw_id),1510 .dev = __cpu_to_le32(port->dev_id),1511 };1512 enum prestera_cmd_type_t cmd_type;1513 1514 if (ingress)1515 cmd_type = PRESTERA_CMD_TYPE_SPAN_INGRESS_UNBIND;1516 else1517 cmd_type = PRESTERA_CMD_TYPE_SPAN_EGRESS_UNBIND;1518 1519 return prestera_cmd(port->sw, cmd_type, &req.cmd, sizeof(req));1520}1521 1522int prestera_hw_span_release(struct prestera_switch *sw, u8 span_id)1523{1524 struct prestera_msg_span_req req = {1525 .id = span_id1526 };1527 1528 return prestera_cmd(sw, PRESTERA_CMD_TYPE_SPAN_RELEASE,1529 &req.cmd, sizeof(req));1530}1531 1532int prestera_hw_port_type_get(const struct prestera_port *port, u8 *type)1533{1534 struct prestera_msg_port_attr_req req = {1535 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_TYPE),1536 .port = __cpu_to_le32(port->hw_id),1537 .dev = __cpu_to_le32(port->dev_id),1538 };1539 struct prestera_msg_port_attr_resp resp;1540 int err;1541 1542 err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,1543 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));1544 if (err)1545 return err;1546 1547 *type = resp.param.type;1548 1549 return 0;1550}1551 1552int prestera_hw_port_speed_get(const struct prestera_port *port, u32 *speed)1553{1554 struct prestera_msg_port_attr_req req = {1555 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_SPEED),1556 .port = __cpu_to_le32(port->hw_id),1557 .dev = __cpu_to_le32(port->dev_id),1558 };1559 struct prestera_msg_port_attr_resp resp;1560 int err;1561 1562 err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,1563 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));1564 if (err)1565 return err;1566 1567 *speed = __le32_to_cpu(resp.param.speed);1568 1569 return 0;1570}1571 1572int prestera_hw_port_autoneg_restart(struct prestera_port *port)1573{1574 struct prestera_msg_port_attr_req req = {1575 .attr =1576 __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_PHY_AUTONEG_RESTART),1577 .port = __cpu_to_le32(port->hw_id),1578 .dev = __cpu_to_le32(port->dev_id),1579 };1580 1581 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,1582 &req.cmd, sizeof(req));1583}1584 1585int prestera_hw_port_stats_get(const struct prestera_port *port,1586 struct prestera_port_stats *st)1587{1588 struct prestera_msg_port_attr_req req = {1589 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_STATS),1590 .port = __cpu_to_le32(port->hw_id),1591 .dev = __cpu_to_le32(port->dev_id),1592 };1593 struct prestera_msg_port_stats_resp resp;1594 __le64 *hw = resp.stats;1595 int err;1596 1597 err = prestera_cmd_ret(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_GET,1598 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));1599 if (err)1600 return err;1601 1602 st->good_octets_received =1603 __le64_to_cpu(hw[PRESTERA_PORT_GOOD_OCTETS_RCV_CNT]);1604 st->bad_octets_received =1605 __le64_to_cpu(hw[PRESTERA_PORT_BAD_OCTETS_RCV_CNT]);1606 st->mac_trans_error =1607 __le64_to_cpu(hw[PRESTERA_PORT_MAC_TRANSMIT_ERR_CNT]);1608 st->broadcast_frames_received =1609 __le64_to_cpu(hw[PRESTERA_PORT_BRDC_PKTS_RCV_CNT]);1610 st->multicast_frames_received =1611 __le64_to_cpu(hw[PRESTERA_PORT_MC_PKTS_RCV_CNT]);1612 st->frames_64_octets = __le64_to_cpu(hw[PRESTERA_PORT_PKTS_64L_CNT]);1613 st->frames_65_to_127_octets =1614 __le64_to_cpu(hw[PRESTERA_PORT_PKTS_65TO127L_CNT]);1615 st->frames_128_to_255_octets =1616 __le64_to_cpu(hw[PRESTERA_PORT_PKTS_128TO255L_CNT]);1617 st->frames_256_to_511_octets =1618 __le64_to_cpu(hw[PRESTERA_PORT_PKTS_256TO511L_CNT]);1619 st->frames_512_to_1023_octets =1620 __le64_to_cpu(hw[PRESTERA_PORT_PKTS_512TO1023L_CNT]);1621 st->frames_1024_to_max_octets =1622 __le64_to_cpu(hw[PRESTERA_PORT_PKTS_1024TOMAXL_CNT]);1623 st->excessive_collision =1624 __le64_to_cpu(hw[PRESTERA_PORT_EXCESSIVE_COLLISIONS_CNT]);1625 st->multicast_frames_sent =1626 __le64_to_cpu(hw[PRESTERA_PORT_MC_PKTS_SENT_CNT]);1627 st->broadcast_frames_sent =1628 __le64_to_cpu(hw[PRESTERA_PORT_BRDC_PKTS_SENT_CNT]);1629 st->fc_sent = __le64_to_cpu(hw[PRESTERA_PORT_FC_SENT_CNT]);1630 st->fc_received = __le64_to_cpu(hw[PRESTERA_PORT_GOOD_FC_RCV_CNT]);1631 st->buffer_overrun = __le64_to_cpu(hw[PRESTERA_PORT_DROP_EVENTS_CNT]);1632 st->undersize = __le64_to_cpu(hw[PRESTERA_PORT_UNDERSIZE_PKTS_CNT]);1633 st->fragments = __le64_to_cpu(hw[PRESTERA_PORT_FRAGMENTS_PKTS_CNT]);1634 st->oversize = __le64_to_cpu(hw[PRESTERA_PORT_OVERSIZE_PKTS_CNT]);1635 st->jabber = __le64_to_cpu(hw[PRESTERA_PORT_JABBER_PKTS_CNT]);1636 st->rx_error_frame_received =1637 __le64_to_cpu(hw[PRESTERA_PORT_MAC_RCV_ERROR_CNT]);1638 st->bad_crc = __le64_to_cpu(hw[PRESTERA_PORT_BAD_CRC_CNT]);1639 st->collisions = __le64_to_cpu(hw[PRESTERA_PORT_COLLISIONS_CNT]);1640 st->late_collision =1641 __le64_to_cpu(hw[PRESTERA_PORT_LATE_COLLISIONS_CNT]);1642 st->unicast_frames_received =1643 __le64_to_cpu(hw[PRESTERA_PORT_GOOD_UC_PKTS_RCV_CNT]);1644 st->unicast_frames_sent =1645 __le64_to_cpu(hw[PRESTERA_PORT_GOOD_UC_PKTS_SENT_CNT]);1646 st->sent_multiple =1647 __le64_to_cpu(hw[PRESTERA_PORT_MULTIPLE_PKTS_SENT_CNT]);1648 st->sent_deferred =1649 __le64_to_cpu(hw[PRESTERA_PORT_DEFERRED_PKTS_SENT_CNT]);1650 st->good_octets_sent =1651 __le64_to_cpu(hw[PRESTERA_PORT_GOOD_OCTETS_SENT_CNT]);1652 1653 return 0;1654}1655 1656int prestera_hw_port_learning_set(struct prestera_port *port, bool enable)1657{1658 struct prestera_msg_port_attr_req req = {1659 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_LEARNING),1660 .port = __cpu_to_le32(port->hw_id),1661 .dev = __cpu_to_le32(port->dev_id),1662 .param = {1663 .learning = enable,1664 }1665 };1666 1667 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,1668 &req.cmd, sizeof(req));1669}1670 1671int prestera_hw_port_uc_flood_set(const struct prestera_port *port, bool flood)1672{1673 struct prestera_msg_port_attr_req req = {1674 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_FLOOD),1675 .port = __cpu_to_le32(port->hw_id),1676 .dev = __cpu_to_le32(port->dev_id),1677 .param = {1678 .flood_ext = {1679 .type = PRESTERA_PORT_FLOOD_TYPE_UC,1680 .enable = flood,1681 }1682 }1683 };1684 1685 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,1686 &req.cmd, sizeof(req));1687}1688 1689int prestera_hw_port_mc_flood_set(const struct prestera_port *port, bool flood)1690{1691 struct prestera_msg_port_attr_req req = {1692 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_FLOOD),1693 .port = __cpu_to_le32(port->hw_id),1694 .dev = __cpu_to_le32(port->dev_id),1695 .param = {1696 .flood_ext = {1697 .type = PRESTERA_PORT_FLOOD_TYPE_MC,1698 .enable = flood,1699 }1700 }1701 };1702 1703 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,1704 &req.cmd, sizeof(req));1705}1706 1707int prestera_hw_port_br_locked_set(const struct prestera_port *port,1708 bool br_locked)1709{1710 struct prestera_msg_port_attr_req req = {1711 .attr = __cpu_to_le32(PRESTERA_CMD_PORT_ATTR_LOCKED),1712 .port = __cpu_to_le32(port->hw_id),1713 .dev = __cpu_to_le32(port->dev_id),1714 .param = {1715 .br_locked = br_locked,1716 }1717 };1718 1719 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_PORT_ATTR_SET,1720 &req.cmd, sizeof(req));1721}1722 1723int prestera_hw_vlan_create(struct prestera_switch *sw, u16 vid)1724{1725 struct prestera_msg_vlan_req req = {1726 .vid = __cpu_to_le16(vid),1727 };1728 1729 return prestera_cmd(sw, PRESTERA_CMD_TYPE_VLAN_CREATE,1730 &req.cmd, sizeof(req));1731}1732 1733int prestera_hw_vlan_delete(struct prestera_switch *sw, u16 vid)1734{1735 struct prestera_msg_vlan_req req = {1736 .vid = __cpu_to_le16(vid),1737 };1738 1739 return prestera_cmd(sw, PRESTERA_CMD_TYPE_VLAN_DELETE,1740 &req.cmd, sizeof(req));1741}1742 1743int prestera_hw_vlan_port_set(struct prestera_port *port, u16 vid,1744 bool is_member, bool untagged)1745{1746 struct prestera_msg_vlan_req req = {1747 .port = __cpu_to_le32(port->hw_id),1748 .dev = __cpu_to_le32(port->dev_id),1749 .vid = __cpu_to_le16(vid),1750 .is_member = is_member,1751 .is_tagged = !untagged,1752 };1753 1754 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_VLAN_PORT_SET,1755 &req.cmd, sizeof(req));1756}1757 1758int prestera_hw_vlan_port_vid_set(struct prestera_port *port, u16 vid)1759{1760 struct prestera_msg_vlan_req req = {1761 .port = __cpu_to_le32(port->hw_id),1762 .dev = __cpu_to_le32(port->dev_id),1763 .vid = __cpu_to_le16(vid),1764 };1765 1766 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_VLAN_PVID_SET,1767 &req.cmd, sizeof(req));1768}1769 1770int prestera_hw_vlan_port_stp_set(struct prestera_port *port, u16 vid, u8 state)1771{1772 struct prestera_msg_stp_req req = {1773 .port = __cpu_to_le32(port->hw_id),1774 .dev = __cpu_to_le32(port->dev_id),1775 .vid = __cpu_to_le16(vid),1776 .state = state,1777 };1778 1779 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_STP_PORT_SET,1780 &req.cmd, sizeof(req));1781}1782 1783int prestera_hw_fdb_add(struct prestera_port *port, const unsigned char *mac,1784 u16 vid, bool dynamic)1785{1786 struct prestera_msg_fdb_req req = {1787 .dest = {1788 .dev = __cpu_to_le32(port->dev_id),1789 .port = __cpu_to_le32(port->hw_id),1790 },1791 .vid = __cpu_to_le16(vid),1792 .dynamic = dynamic,1793 };1794 1795 ether_addr_copy(req.mac, mac);1796 1797 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_FDB_ADD,1798 &req.cmd, sizeof(req));1799}1800 1801int prestera_hw_fdb_del(struct prestera_port *port, const unsigned char *mac,1802 u16 vid)1803{1804 struct prestera_msg_fdb_req req = {1805 .dest = {1806 .dev = __cpu_to_le32(port->dev_id),1807 .port = __cpu_to_le32(port->hw_id),1808 },1809 .vid = __cpu_to_le16(vid),1810 };1811 1812 ether_addr_copy(req.mac, mac);1813 1814 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_FDB_DELETE,1815 &req.cmd, sizeof(req));1816}1817 1818int prestera_hw_lag_fdb_add(struct prestera_switch *sw, u16 lag_id,1819 const unsigned char *mac, u16 vid, bool dynamic)1820{1821 struct prestera_msg_fdb_req req = {1822 .dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,1823 .dest = {1824 .lag_id = __cpu_to_le16(lag_id),1825 },1826 .vid = __cpu_to_le16(vid),1827 .dynamic = dynamic,1828 };1829 1830 ether_addr_copy(req.mac, mac);1831 1832 return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_ADD,1833 &req.cmd, sizeof(req));1834}1835 1836int prestera_hw_lag_fdb_del(struct prestera_switch *sw, u16 lag_id,1837 const unsigned char *mac, u16 vid)1838{1839 struct prestera_msg_fdb_req req = {1840 .dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,1841 .dest = {1842 .lag_id = __cpu_to_le16(lag_id),1843 },1844 .vid = __cpu_to_le16(vid),1845 };1846 1847 ether_addr_copy(req.mac, mac);1848 1849 return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_DELETE,1850 &req.cmd, sizeof(req));1851}1852 1853int prestera_hw_fdb_flush_port(struct prestera_port *port, u32 mode)1854{1855 struct prestera_msg_fdb_req req = {1856 .dest = {1857 .dev = __cpu_to_le32(port->dev_id),1858 .port = __cpu_to_le32(port->hw_id),1859 },1860 .flush_mode = __cpu_to_le32(mode),1861 };1862 1863 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT,1864 &req.cmd, sizeof(req));1865}1866 1867int prestera_hw_fdb_flush_vlan(struct prestera_switch *sw, u16 vid, u32 mode)1868{1869 struct prestera_msg_fdb_req req = {1870 .vid = __cpu_to_le16(vid),1871 .flush_mode = __cpu_to_le32(mode),1872 };1873 1874 return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_FLUSH_VLAN,1875 &req.cmd, sizeof(req));1876}1877 1878int prestera_hw_fdb_flush_port_vlan(struct prestera_port *port, u16 vid,1879 u32 mode)1880{1881 struct prestera_msg_fdb_req req = {1882 .dest = {1883 .dev = __cpu_to_le32(port->dev_id),1884 .port = __cpu_to_le32(port->hw_id),1885 },1886 .vid = __cpu_to_le16(vid),1887 .flush_mode = __cpu_to_le32(mode),1888 };1889 1890 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT_VLAN,1891 &req.cmd, sizeof(req));1892}1893 1894int prestera_hw_fdb_flush_lag(struct prestera_switch *sw, u16 lag_id,1895 u32 mode)1896{1897 struct prestera_msg_fdb_req req = {1898 .dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,1899 .dest = {1900 .lag_id = __cpu_to_le16(lag_id),1901 },1902 .flush_mode = __cpu_to_le32(mode),1903 };1904 1905 return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT,1906 &req.cmd, sizeof(req));1907}1908 1909int prestera_hw_fdb_flush_lag_vlan(struct prestera_switch *sw,1910 u16 lag_id, u16 vid, u32 mode)1911{1912 struct prestera_msg_fdb_req req = {1913 .dest_type = PRESTERA_HW_FDB_ENTRY_TYPE_LAG,1914 .dest = {1915 .lag_id = __cpu_to_le16(lag_id),1916 },1917 .vid = __cpu_to_le16(vid),1918 .flush_mode = __cpu_to_le32(mode),1919 };1920 1921 return prestera_cmd(sw, PRESTERA_CMD_TYPE_FDB_FLUSH_PORT_VLAN,1922 &req.cmd, sizeof(req));1923}1924 1925int prestera_hw_bridge_create(struct prestera_switch *sw, u16 *bridge_id)1926{1927 struct prestera_msg_bridge_resp resp;1928 struct prestera_msg_bridge_req req;1929 int err;1930 1931 err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_BRIDGE_CREATE,1932 &req.cmd, sizeof(req),1933 &resp.ret, sizeof(resp));1934 if (err)1935 return err;1936 1937 *bridge_id = __le16_to_cpu(resp.bridge);1938 1939 return 0;1940}1941 1942int prestera_hw_bridge_delete(struct prestera_switch *sw, u16 bridge_id)1943{1944 struct prestera_msg_bridge_req req = {1945 .bridge = __cpu_to_le16(bridge_id),1946 };1947 1948 return prestera_cmd(sw, PRESTERA_CMD_TYPE_BRIDGE_DELETE,1949 &req.cmd, sizeof(req));1950}1951 1952int prestera_hw_bridge_port_add(struct prestera_port *port, u16 bridge_id)1953{1954 struct prestera_msg_bridge_req req = {1955 .bridge = __cpu_to_le16(bridge_id),1956 .port = __cpu_to_le32(port->hw_id),1957 .dev = __cpu_to_le32(port->dev_id),1958 };1959 1960 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_BRIDGE_PORT_ADD,1961 &req.cmd, sizeof(req));1962}1963 1964int prestera_hw_bridge_port_delete(struct prestera_port *port, u16 bridge_id)1965{1966 struct prestera_msg_bridge_req req = {1967 .bridge = __cpu_to_le16(bridge_id),1968 .port = __cpu_to_le32(port->hw_id),1969 .dev = __cpu_to_le32(port->dev_id),1970 };1971 1972 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_BRIDGE_PORT_DELETE,1973 &req.cmd, sizeof(req));1974}1975 1976static int prestera_iface_to_msg(struct prestera_iface *iface,1977 struct prestera_msg_iface *msg_if)1978{1979 switch (iface->type) {1980 case PRESTERA_IF_PORT_E:1981 case PRESTERA_IF_VID_E:1982 msg_if->port = __cpu_to_le32(iface->dev_port.port_num);1983 msg_if->dev = __cpu_to_le32(iface->dev_port.hw_dev_num);1984 break;1985 case PRESTERA_IF_LAG_E:1986 msg_if->lag_id = __cpu_to_le16(iface->lag_id);1987 break;1988 default:1989 return -EOPNOTSUPP;1990 }1991 1992 msg_if->vr_id = __cpu_to_le16(iface->vr_id);1993 msg_if->vid = __cpu_to_le16(iface->vlan_id);1994 msg_if->type = iface->type;1995 return 0;1996}1997 1998int prestera_hw_rif_create(struct prestera_switch *sw,1999 struct prestera_iface *iif, u8 *mac, u16 *rif_id)2000{2001 struct prestera_msg_rif_resp resp;2002 struct prestera_msg_rif_req req;2003 int err;2004 2005 memcpy(req.mac, mac, ETH_ALEN);2006 2007 err = prestera_iface_to_msg(iif, &req.iif);2008 if (err)2009 return err;2010 2011 err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ROUTER_RIF_CREATE,2012 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));2013 if (err)2014 return err;2015 2016 *rif_id = __le16_to_cpu(resp.rif_id);2017 return err;2018}2019 2020int prestera_hw_rif_delete(struct prestera_switch *sw, u16 rif_id,2021 struct prestera_iface *iif)2022{2023 struct prestera_msg_rif_req req = {2024 .rif_id = __cpu_to_le16(rif_id),2025 };2026 int err;2027 2028 err = prestera_iface_to_msg(iif, &req.iif);2029 if (err)2030 return err;2031 2032 return prestera_cmd(sw, PRESTERA_CMD_TYPE_ROUTER_RIF_DELETE, &req.cmd,2033 sizeof(req));2034}2035 2036int prestera_hw_vr_create(struct prestera_switch *sw, u16 *vr_id)2037{2038 struct prestera_msg_vr_resp resp;2039 struct prestera_msg_vr_req req;2040 int err;2041 2042 err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ROUTER_VR_CREATE,2043 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));2044 if (err)2045 return err;2046 2047 *vr_id = __le16_to_cpu(resp.vr_id);2048 return err;2049}2050 2051int prestera_hw_vr_delete(struct prestera_switch *sw, u16 vr_id)2052{2053 struct prestera_msg_vr_req req = {2054 .vr_id = __cpu_to_le16(vr_id),2055 };2056 2057 return prestera_cmd(sw, PRESTERA_CMD_TYPE_ROUTER_VR_DELETE, &req.cmd,2058 sizeof(req));2059}2060 2061int prestera_hw_lpm_add(struct prestera_switch *sw, u16 vr_id,2062 __be32 dst, u32 dst_len, u32 grp_id)2063{2064 struct prestera_msg_lpm_req req = {2065 .dst_len = __cpu_to_le32(dst_len),2066 .vr_id = __cpu_to_le16(vr_id),2067 .grp_id = __cpu_to_le32(grp_id),2068 .dst.u.ipv4 = dst2069 };2070 2071 return prestera_cmd(sw, PRESTERA_CMD_TYPE_ROUTER_LPM_ADD, &req.cmd,2072 sizeof(req));2073}2074 2075int prestera_hw_lpm_del(struct prestera_switch *sw, u16 vr_id,2076 __be32 dst, u32 dst_len)2077{2078 struct prestera_msg_lpm_req req = {2079 .dst_len = __cpu_to_le32(dst_len),2080 .vr_id = __cpu_to_le16(vr_id),2081 .dst.u.ipv4 = dst2082 };2083 2084 return prestera_cmd(sw, PRESTERA_CMD_TYPE_ROUTER_LPM_DELETE, &req.cmd,2085 sizeof(req));2086}2087 2088int prestera_hw_nh_entries_set(struct prestera_switch *sw, int count,2089 struct prestera_neigh_info *nhs, u32 grp_id)2090{2091 struct prestera_msg_nh_req req = { .size = __cpu_to_le32((u32)count),2092 .grp_id = __cpu_to_le32(grp_id) };2093 int i, err;2094 2095 for (i = 0; i < count; i++) {2096 req.nh[i].is_active = nhs[i].connected;2097 memcpy(&req.nh[i].mac, nhs[i].ha, ETH_ALEN);2098 err = prestera_iface_to_msg(&nhs[i].iface, &req.nh[i].oif);2099 if (err)2100 return err;2101 }2102 2103 return prestera_cmd(sw, PRESTERA_CMD_TYPE_ROUTER_NH_GRP_SET, &req.cmd,2104 sizeof(req));2105}2106 2107int prestera_hw_nhgrp_blk_get(struct prestera_switch *sw,2108 u8 *hw_state, u32 buf_size /* Buffer in bytes */)2109{2110 static struct prestera_msg_nh_chunk_resp resp;2111 struct prestera_msg_nh_chunk_req req;2112 u32 buf_offset;2113 int err;2114 2115 memset(&hw_state[0], 0, buf_size);2116 buf_offset = 0;2117 while (1) {2118 if (buf_offset >= buf_size)2119 break;2120 2121 memset(&req, 0, sizeof(req));2122 req.offset = __cpu_to_le32(buf_offset * 8); /* 8 bits in u8 */2123 err = prestera_cmd_ret(sw,2124 PRESTERA_CMD_TYPE_ROUTER_NH_GRP_BLK_GET,2125 &req.cmd, sizeof(req), &resp.ret,2126 sizeof(resp));2127 if (err)2128 return err;2129 2130 memcpy(&hw_state[buf_offset], &resp.hw_state[0],2131 buf_offset + PRESTERA_MSG_CHUNK_SIZE > buf_size ?2132 buf_size - buf_offset : PRESTERA_MSG_CHUNK_SIZE);2133 buf_offset += PRESTERA_MSG_CHUNK_SIZE;2134 }2135 2136 return 0;2137}2138 2139int prestera_hw_nh_group_create(struct prestera_switch *sw, u16 nh_count,2140 u32 *grp_id)2141{2142 struct prestera_msg_nh_grp_req req = { .size = __cpu_to_le32((u32)nh_count) };2143 struct prestera_msg_nh_grp_resp resp;2144 int err;2145 2146 err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_ROUTER_NH_GRP_ADD,2147 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));2148 if (err)2149 return err;2150 2151 *grp_id = __le32_to_cpu(resp.grp_id);2152 return err;2153}2154 2155int prestera_hw_nh_group_delete(struct prestera_switch *sw, u16 nh_count,2156 u32 grp_id)2157{2158 struct prestera_msg_nh_grp_req req = {2159 .grp_id = __cpu_to_le32(grp_id),2160 .size = __cpu_to_le32(nh_count)2161 };2162 2163 return prestera_cmd(sw, PRESTERA_CMD_TYPE_ROUTER_NH_GRP_DELETE,2164 &req.cmd, sizeof(req));2165}2166 2167int prestera_hw_rxtx_init(struct prestera_switch *sw,2168 struct prestera_rxtx_params *params)2169{2170 struct prestera_msg_rxtx_resp resp;2171 struct prestera_msg_rxtx_req req;2172 int err;2173 2174 req.use_sdma = params->use_sdma;2175 2176 err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_RXTX_INIT,2177 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));2178 if (err)2179 return err;2180 2181 params->map_addr = __le32_to_cpu(resp.map_addr);2182 2183 return 0;2184}2185 2186int prestera_hw_lag_member_add(struct prestera_port *port, u16 lag_id)2187{2188 struct prestera_msg_lag_req req = {2189 .port = __cpu_to_le32(port->hw_id),2190 .dev = __cpu_to_le32(port->dev_id),2191 .lag_id = __cpu_to_le16(lag_id),2192 };2193 2194 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_LAG_MEMBER_ADD,2195 &req.cmd, sizeof(req));2196}2197 2198int prestera_hw_lag_member_del(struct prestera_port *port, u16 lag_id)2199{2200 struct prestera_msg_lag_req req = {2201 .port = __cpu_to_le32(port->hw_id),2202 .dev = __cpu_to_le32(port->dev_id),2203 .lag_id = __cpu_to_le16(lag_id),2204 };2205 2206 return prestera_cmd(port->sw, PRESTERA_CMD_TYPE_LAG_MEMBER_DELETE,2207 &req.cmd, sizeof(req));2208}2209 2210int prestera_hw_lag_member_enable(struct prestera_port *port, u16 lag_id,2211 bool enable)2212{2213 struct prestera_msg_lag_req req = {2214 .port = __cpu_to_le32(port->hw_id),2215 .dev = __cpu_to_le32(port->dev_id),2216 .lag_id = __cpu_to_le16(lag_id),2217 };2218 u32 cmd;2219 2220 cmd = enable ? PRESTERA_CMD_TYPE_LAG_MEMBER_ENABLE :2221 PRESTERA_CMD_TYPE_LAG_MEMBER_DISABLE;2222 2223 return prestera_cmd(port->sw, cmd, &req.cmd, sizeof(req));2224}2225 2226int2227prestera_hw_cpu_code_counters_get(struct prestera_switch *sw, u8 code,2228 enum prestera_hw_cpu_code_cnt_t counter_type,2229 u64 *packet_count)2230{2231 struct prestera_msg_cpu_code_counter_req req = {2232 .counter_type = counter_type,2233 .code = code,2234 };2235 struct mvsw_msg_cpu_code_counter_ret resp;2236 int err;2237 2238 err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_CPU_CODE_COUNTERS_GET,2239 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));2240 if (err)2241 return err;2242 2243 *packet_count = __le64_to_cpu(resp.packet_count);2244 2245 return 0;2246}2247 2248int prestera_hw_event_handler_register(struct prestera_switch *sw,2249 enum prestera_event_type type,2250 prestera_event_cb_t fn,2251 void *arg)2252{2253 struct prestera_fw_event_handler *eh;2254 2255 eh = __find_event_handler(sw, type);2256 if (eh)2257 return -EEXIST;2258 2259 eh = kmalloc(sizeof(*eh), GFP_KERNEL);2260 if (!eh)2261 return -ENOMEM;2262 2263 eh->type = type;2264 eh->func = fn;2265 eh->arg = arg;2266 2267 INIT_LIST_HEAD(&eh->list);2268 2269 list_add_rcu(&eh->list, &sw->event_handlers);2270 2271 return 0;2272}2273 2274void prestera_hw_event_handler_unregister(struct prestera_switch *sw,2275 enum prestera_event_type type,2276 prestera_event_cb_t fn)2277{2278 struct prestera_fw_event_handler *eh;2279 2280 eh = __find_event_handler(sw, type);2281 if (!eh)2282 return;2283 2284 list_del_rcu(&eh->list);2285 kfree_rcu(eh, rcu);2286}2287 2288int prestera_hw_counter_trigger(struct prestera_switch *sw, u32 block_id)2289{2290 struct prestera_msg_counter_req req = {2291 .block_id = __cpu_to_le32(block_id)2292 };2293 2294 return prestera_cmd(sw, PRESTERA_CMD_TYPE_COUNTER_TRIGGER,2295 &req.cmd, sizeof(req));2296}2297 2298int prestera_hw_counter_abort(struct prestera_switch *sw)2299{2300 struct prestera_msg_counter_req req;2301 2302 return prestera_cmd(sw, PRESTERA_CMD_TYPE_COUNTER_ABORT,2303 &req.cmd, sizeof(req));2304}2305 2306int prestera_hw_counters_get(struct prestera_switch *sw, u32 idx,2307 u32 *len, bool *done,2308 struct prestera_counter_stats *stats)2309{2310 struct prestera_msg_counter_resp *resp;2311 struct prestera_msg_counter_req req = {2312 .block_id = __cpu_to_le32(idx),2313 .num_counters = __cpu_to_le32(*len),2314 };2315 size_t size = struct_size(resp, stats, *len);2316 int err, i;2317 2318 resp = kmalloc(size, GFP_KERNEL);2319 if (!resp)2320 return -ENOMEM;2321 2322 err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_COUNTER_GET,2323 &req.cmd, sizeof(req), &resp->ret, size);2324 if (err)2325 goto free_buff;2326 2327 for (i = 0; i < __le32_to_cpu(resp->num_counters); i++) {2328 stats[i].packets += __le64_to_cpu(resp->stats[i].packets);2329 stats[i].bytes += __le64_to_cpu(resp->stats[i].bytes);2330 }2331 2332 *len = __le32_to_cpu(resp->num_counters);2333 *done = __le32_to_cpu(resp->done);2334 2335free_buff:2336 kfree(resp);2337 return err;2338}2339 2340int prestera_hw_counter_block_get(struct prestera_switch *sw,2341 u32 client, u32 *block_id, u32 *offset,2342 u32 *num_counters)2343{2344 struct prestera_msg_counter_resp resp;2345 struct prestera_msg_counter_req req = {2346 .client = __cpu_to_le32(client)2347 };2348 int err;2349 2350 err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_COUNTER_BLOCK_GET,2351 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));2352 if (err)2353 return err;2354 2355 *block_id = __le32_to_cpu(resp.block_id);2356 *offset = __le32_to_cpu(resp.offset);2357 *num_counters = __le32_to_cpu(resp.num_counters);2358 2359 return 0;2360}2361 2362int prestera_hw_counter_block_release(struct prestera_switch *sw,2363 u32 block_id)2364{2365 struct prestera_msg_counter_req req = {2366 .block_id = __cpu_to_le32(block_id)2367 };2368 2369 return prestera_cmd(sw, PRESTERA_CMD_TYPE_COUNTER_BLOCK_RELEASE,2370 &req.cmd, sizeof(req));2371}2372 2373int prestera_hw_counter_clear(struct prestera_switch *sw, u32 block_id,2374 u32 counter_id)2375{2376 struct prestera_msg_counter_req req = {2377 .block_id = __cpu_to_le32(block_id),2378 .num_counters = __cpu_to_le32(counter_id)2379 };2380 2381 return prestera_cmd(sw, PRESTERA_CMD_TYPE_COUNTER_CLEAR,2382 &req.cmd, sizeof(req));2383}2384 2385int prestera_hw_policer_create(struct prestera_switch *sw, u8 type,2386 u32 *policer_id)2387{2388 struct prestera_msg_policer_resp resp;2389 struct prestera_msg_policer_req req = {2390 .type = type2391 };2392 int err;2393 2394 err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_POLICER_CREATE,2395 &req.cmd, sizeof(req), &resp.ret, sizeof(resp));2396 if (err)2397 return err;2398 2399 *policer_id = __le32_to_cpu(resp.id);2400 return 0;2401}2402 2403int prestera_hw_policer_release(struct prestera_switch *sw,2404 u32 policer_id)2405{2406 struct prestera_msg_policer_req req = {2407 .id = __cpu_to_le32(policer_id)2408 };2409 2410 return prestera_cmd(sw, PRESTERA_CMD_TYPE_POLICER_RELEASE,2411 &req.cmd, sizeof(req));2412}2413 2414int prestera_hw_policer_sr_tcm_set(struct prestera_switch *sw,2415 u32 policer_id, u64 cir, u32 cbs)2416{2417 struct prestera_msg_policer_req req = {2418 .mode = PRESTERA_POLICER_MODE_SR_TCM,2419 .id = __cpu_to_le32(policer_id),2420 .sr_tcm = {2421 .cir = __cpu_to_le64(cir),2422 .cbs = __cpu_to_le32(cbs)2423 }2424 };2425 2426 return prestera_cmd(sw, PRESTERA_CMD_TYPE_POLICER_SET,2427 &req.cmd, sizeof(req));2428}2429 2430int prestera_hw_flood_domain_create(struct prestera_flood_domain *domain)2431{2432 struct prestera_msg_flood_domain_create_resp resp;2433 struct prestera_msg_flood_domain_create_req req;2434 int err;2435 2436 err = prestera_cmd_ret(domain->sw,2437 PRESTERA_CMD_TYPE_FLOOD_DOMAIN_CREATE, &req.cmd,2438 sizeof(req), &resp.ret, sizeof(resp));2439 if (err)2440 return err;2441 2442 domain->idx = __le32_to_cpu(resp.flood_domain_idx);2443 2444 return 0;2445}2446 2447int prestera_hw_flood_domain_destroy(struct prestera_flood_domain *domain)2448{2449 struct prestera_msg_flood_domain_destroy_req req = {2450 .flood_domain_idx = __cpu_to_le32(domain->idx),2451 };2452 2453 return prestera_cmd(domain->sw, PRESTERA_CMD_TYPE_FLOOD_DOMAIN_DESTROY,2454 &req.cmd, sizeof(req));2455}2456 2457int prestera_hw_flood_domain_ports_set(struct prestera_flood_domain *domain)2458{2459 struct prestera_flood_domain_port *flood_domain_port;2460 struct prestera_msg_flood_domain_ports_set_req *req;2461 struct prestera_switch *sw = domain->sw;2462 struct prestera_port *port;2463 u32 ports_num = 0;2464 size_t buf_size;2465 u16 lag_id;2466 int err;2467 int i = 0;2468 2469 list_for_each_entry(flood_domain_port, &domain->flood_domain_port_list,2470 flood_domain_port_node)2471 ports_num++;2472 2473 if (!ports_num)2474 return -EINVAL;2475 2476 buf_size = struct_size(req, ports, ports_num);2477 req = kmalloc(buf_size, GFP_KERNEL);2478 if (!req)2479 return -ENOMEM;2480 2481 req->flood_domain_idx = __cpu_to_le32(domain->idx);2482 req->ports_num = __cpu_to_le32(ports_num);2483 2484 list_for_each_entry(flood_domain_port, &domain->flood_domain_port_list,2485 flood_domain_port_node) {2486 if (netif_is_lag_master(flood_domain_port->dev)) {2487 if (prestera_lag_id(sw, flood_domain_port->dev,2488 &lag_id)) {2489 kfree(req);2490 return -EINVAL;2491 }2492 2493 req->ports[i].port_type =2494 __cpu_to_le16(PRESTERA_HW_FLOOD_DOMAIN_PORT_TYPE_LAG);2495 req->ports[i].lag_id = __cpu_to_le16(lag_id);2496 } else {2497 port = prestera_port_dev_lower_find(flood_domain_port->dev);2498 2499 req->ports[i].port_type =2500 __cpu_to_le16(PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT);2501 req->ports[i].dev_num = __cpu_to_le32(port->dev_id);2502 req->ports[i].port_num = __cpu_to_le32(port->hw_id);2503 }2504 2505 req->ports[i].vid = __cpu_to_le16(flood_domain_port->vid);2506 i++;2507 }2508 2509 err = prestera_cmd(sw, PRESTERA_CMD_TYPE_FLOOD_DOMAIN_PORTS_SET,2510 &req->cmd, buf_size);2511 2512 kfree(req);2513 2514 return err;2515}2516 2517int prestera_hw_flood_domain_ports_reset(struct prestera_flood_domain *domain)2518{2519 struct prestera_msg_flood_domain_ports_reset_req req = {2520 .flood_domain_idx = __cpu_to_le32(domain->idx),2521 };2522 2523 return prestera_cmd(domain->sw,2524 PRESTERA_CMD_TYPE_FLOOD_DOMAIN_PORTS_RESET, &req.cmd,2525 sizeof(req));2526}2527 2528int prestera_hw_mdb_create(struct prestera_mdb_entry *mdb)2529{2530 struct prestera_msg_mdb_create_req req = {2531 .flood_domain_idx = __cpu_to_le32(mdb->flood_domain->idx),2532 .vid = __cpu_to_le16(mdb->vid),2533 };2534 2535 memcpy(req.mac, mdb->addr, ETH_ALEN);2536 2537 return prestera_cmd(mdb->sw, PRESTERA_CMD_TYPE_MDB_CREATE, &req.cmd,2538 sizeof(req));2539}2540 2541int prestera_hw_mdb_destroy(struct prestera_mdb_entry *mdb)2542{2543 struct prestera_msg_mdb_destroy_req req = {2544 .flood_domain_idx = __cpu_to_le32(mdb->flood_domain->idx),2545 .vid = __cpu_to_le16(mdb->vid),2546 };2547 2548 memcpy(req.mac, mdb->addr, ETH_ALEN);2549 2550 return prestera_cmd(mdb->sw, PRESTERA_CMD_TYPE_MDB_DESTROY, &req.cmd,2551 sizeof(req));2552}2553