162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/kernel.h> 562306a36Sopenharmony_ci#include <linux/module.h> 662306a36Sopenharmony_ci#include <linux/types.h> 762306a36Sopenharmony_ci#include <linux/pci.h> 862306a36Sopenharmony_ci#include <linux/netdevice.h> 962306a36Sopenharmony_ci#include <linux/etherdevice.h> 1062306a36Sopenharmony_ci#include <linux/ethtool.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/skbuff.h> 1462306a36Sopenharmony_ci#include <linux/if_vlan.h> 1562306a36Sopenharmony_ci#include <linux/if_bridge.h> 1662306a36Sopenharmony_ci#include <linux/workqueue.h> 1762306a36Sopenharmony_ci#include <linux/jiffies.h> 1862306a36Sopenharmony_ci#include <linux/bitops.h> 1962306a36Sopenharmony_ci#include <linux/list.h> 2062306a36Sopenharmony_ci#include <linux/notifier.h> 2162306a36Sopenharmony_ci#include <linux/dcbnl.h> 2262306a36Sopenharmony_ci#include <linux/inetdevice.h> 2362306a36Sopenharmony_ci#include <linux/netlink.h> 2462306a36Sopenharmony_ci#include <linux/jhash.h> 2562306a36Sopenharmony_ci#include <linux/log2.h> 2662306a36Sopenharmony_ci#include <linux/refcount.h> 2762306a36Sopenharmony_ci#include <linux/rhashtable.h> 2862306a36Sopenharmony_ci#include <net/switchdev.h> 2962306a36Sopenharmony_ci#include <net/pkt_cls.h> 3062306a36Sopenharmony_ci#include <net/netevent.h> 3162306a36Sopenharmony_ci#include <net/addrconf.h> 3262306a36Sopenharmony_ci#include <linux/ptp_classify.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include "spectrum.h" 3562306a36Sopenharmony_ci#include "pci.h" 3662306a36Sopenharmony_ci#include "core.h" 3762306a36Sopenharmony_ci#include "core_env.h" 3862306a36Sopenharmony_ci#include "reg.h" 3962306a36Sopenharmony_ci#include "port.h" 4062306a36Sopenharmony_ci#include "trap.h" 4162306a36Sopenharmony_ci#include "txheader.h" 4262306a36Sopenharmony_ci#include "spectrum_cnt.h" 4362306a36Sopenharmony_ci#include "spectrum_dpipe.h" 4462306a36Sopenharmony_ci#include "spectrum_acl_flex_actions.h" 4562306a36Sopenharmony_ci#include "spectrum_span.h" 4662306a36Sopenharmony_ci#include "spectrum_ptp.h" 4762306a36Sopenharmony_ci#include "spectrum_trap.h" 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define MLXSW_SP_FWREV_MINOR 2010 5062306a36Sopenharmony_ci#define MLXSW_SP_FWREV_SUBMINOR 1006 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define MLXSW_SP1_FWREV_MAJOR 13 5362306a36Sopenharmony_ci#define MLXSW_SP1_FWREV_CAN_RESET_MINOR 1702 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = { 5662306a36Sopenharmony_ci .major = MLXSW_SP1_FWREV_MAJOR, 5762306a36Sopenharmony_ci .minor = MLXSW_SP_FWREV_MINOR, 5862306a36Sopenharmony_ci .subminor = MLXSW_SP_FWREV_SUBMINOR, 5962306a36Sopenharmony_ci .can_reset_minor = MLXSW_SP1_FWREV_CAN_RESET_MINOR, 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define MLXSW_SP1_FW_FILENAME \ 6362306a36Sopenharmony_ci "mellanox/mlxsw_spectrum-" __stringify(MLXSW_SP1_FWREV_MAJOR) \ 6462306a36Sopenharmony_ci "." __stringify(MLXSW_SP_FWREV_MINOR) \ 6562306a36Sopenharmony_ci "." __stringify(MLXSW_SP_FWREV_SUBMINOR) ".mfa2" 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define MLXSW_SP2_FWREV_MAJOR 29 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic const struct mlxsw_fw_rev mlxsw_sp2_fw_rev = { 7062306a36Sopenharmony_ci .major = MLXSW_SP2_FWREV_MAJOR, 7162306a36Sopenharmony_ci .minor = MLXSW_SP_FWREV_MINOR, 7262306a36Sopenharmony_ci .subminor = MLXSW_SP_FWREV_SUBMINOR, 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define MLXSW_SP2_FW_FILENAME \ 7662306a36Sopenharmony_ci "mellanox/mlxsw_spectrum2-" __stringify(MLXSW_SP2_FWREV_MAJOR) \ 7762306a36Sopenharmony_ci "." __stringify(MLXSW_SP_FWREV_MINOR) \ 7862306a36Sopenharmony_ci "." __stringify(MLXSW_SP_FWREV_SUBMINOR) ".mfa2" 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define MLXSW_SP3_FWREV_MAJOR 30 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic const struct mlxsw_fw_rev mlxsw_sp3_fw_rev = { 8362306a36Sopenharmony_ci .major = MLXSW_SP3_FWREV_MAJOR, 8462306a36Sopenharmony_ci .minor = MLXSW_SP_FWREV_MINOR, 8562306a36Sopenharmony_ci .subminor = MLXSW_SP_FWREV_SUBMINOR, 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define MLXSW_SP3_FW_FILENAME \ 8962306a36Sopenharmony_ci "mellanox/mlxsw_spectrum3-" __stringify(MLXSW_SP3_FWREV_MAJOR) \ 9062306a36Sopenharmony_ci "." __stringify(MLXSW_SP_FWREV_MINOR) \ 9162306a36Sopenharmony_ci "." __stringify(MLXSW_SP_FWREV_SUBMINOR) ".mfa2" 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define MLXSW_SP_LINECARDS_INI_BUNDLE_FILENAME \ 9462306a36Sopenharmony_ci "mellanox/lc_ini_bundle_" \ 9562306a36Sopenharmony_ci __stringify(MLXSW_SP_FWREV_MINOR) "_" \ 9662306a36Sopenharmony_ci __stringify(MLXSW_SP_FWREV_SUBMINOR) ".bin" 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic const char mlxsw_sp1_driver_name[] = "mlxsw_spectrum"; 9962306a36Sopenharmony_cistatic const char mlxsw_sp2_driver_name[] = "mlxsw_spectrum2"; 10062306a36Sopenharmony_cistatic const char mlxsw_sp3_driver_name[] = "mlxsw_spectrum3"; 10162306a36Sopenharmony_cistatic const char mlxsw_sp4_driver_name[] = "mlxsw_spectrum4"; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic const unsigned char mlxsw_sp1_mac_mask[ETH_ALEN] = { 10462306a36Sopenharmony_ci 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_cistatic const unsigned char mlxsw_sp2_mac_mask[ETH_ALEN] = { 10762306a36Sopenharmony_ci 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/* tx_hdr_version 11162306a36Sopenharmony_ci * Tx header version. 11262306a36Sopenharmony_ci * Must be set to 1. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ciMLXSW_ITEM32(tx, hdr, version, 0x00, 28, 4); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/* tx_hdr_ctl 11762306a36Sopenharmony_ci * Packet control type. 11862306a36Sopenharmony_ci * 0 - Ethernet control (e.g. EMADs, LACP) 11962306a36Sopenharmony_ci * 1 - Ethernet data 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ciMLXSW_ITEM32(tx, hdr, ctl, 0x00, 26, 2); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* tx_hdr_proto 12462306a36Sopenharmony_ci * Packet protocol type. Must be set to 1 (Ethernet). 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ciMLXSW_ITEM32(tx, hdr, proto, 0x00, 21, 3); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* tx_hdr_rx_is_router 12962306a36Sopenharmony_ci * Packet is sent from the router. Valid for data packets only. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ciMLXSW_ITEM32(tx, hdr, rx_is_router, 0x00, 19, 1); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* tx_hdr_fid_valid 13462306a36Sopenharmony_ci * Indicates if the 'fid' field is valid and should be used for 13562306a36Sopenharmony_ci * forwarding lookup. Valid for data packets only. 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_ciMLXSW_ITEM32(tx, hdr, fid_valid, 0x00, 16, 1); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* tx_hdr_swid 14062306a36Sopenharmony_ci * Switch partition ID. Must be set to 0. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ciMLXSW_ITEM32(tx, hdr, swid, 0x00, 12, 3); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* tx_hdr_control_tclass 14562306a36Sopenharmony_ci * Indicates if the packet should use the control TClass and not one 14662306a36Sopenharmony_ci * of the data TClasses. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ciMLXSW_ITEM32(tx, hdr, control_tclass, 0x00, 6, 1); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* tx_hdr_etclass 15162306a36Sopenharmony_ci * Egress TClass to be used on the egress device on the egress port. 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_ciMLXSW_ITEM32(tx, hdr, etclass, 0x00, 0, 4); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* tx_hdr_port_mid 15662306a36Sopenharmony_ci * Destination local port for unicast packets. 15762306a36Sopenharmony_ci * Destination multicast ID for multicast packets. 15862306a36Sopenharmony_ci * 15962306a36Sopenharmony_ci * Control packets are directed to a specific egress port, while data 16062306a36Sopenharmony_ci * packets are transmitted through the CPU port (0) into the switch partition, 16162306a36Sopenharmony_ci * where forwarding rules are applied. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ciMLXSW_ITEM32(tx, hdr, port_mid, 0x04, 16, 16); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* tx_hdr_fid 16662306a36Sopenharmony_ci * Forwarding ID used for L2 forwarding lookup. Valid only if 'fid_valid' is 16762306a36Sopenharmony_ci * set, otherwise calculated based on the packet's VID using VID to FID mapping. 16862306a36Sopenharmony_ci * Valid for data packets only. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ciMLXSW_ITEM32(tx, hdr, fid, 0x08, 16, 16); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* tx_hdr_type 17362306a36Sopenharmony_ci * 0 - Data packets 17462306a36Sopenharmony_ci * 6 - Control packets 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_ciMLXSW_ITEM32(tx, hdr, type, 0x0C, 0, 4); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ciint mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp, 17962306a36Sopenharmony_ci unsigned int counter_index, u64 *packets, 18062306a36Sopenharmony_ci u64 *bytes) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci char mgpc_pl[MLXSW_REG_MGPC_LEN]; 18362306a36Sopenharmony_ci int err; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_NOP, 18662306a36Sopenharmony_ci MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES); 18762306a36Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl); 18862306a36Sopenharmony_ci if (err) 18962306a36Sopenharmony_ci return err; 19062306a36Sopenharmony_ci if (packets) 19162306a36Sopenharmony_ci *packets = mlxsw_reg_mgpc_packet_counter_get(mgpc_pl); 19262306a36Sopenharmony_ci if (bytes) 19362306a36Sopenharmony_ci *bytes = mlxsw_reg_mgpc_byte_counter_get(mgpc_pl); 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int mlxsw_sp_flow_counter_clear(struct mlxsw_sp *mlxsw_sp, 19862306a36Sopenharmony_ci unsigned int counter_index) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci char mgpc_pl[MLXSW_REG_MGPC_LEN]; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_CLEAR, 20362306a36Sopenharmony_ci MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES); 20462306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ciint mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp, 20862306a36Sopenharmony_ci unsigned int *p_counter_index) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci int err; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci err = mlxsw_sp_counter_alloc(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW, 21362306a36Sopenharmony_ci p_counter_index); 21462306a36Sopenharmony_ci if (err) 21562306a36Sopenharmony_ci return err; 21662306a36Sopenharmony_ci err = mlxsw_sp_flow_counter_clear(mlxsw_sp, *p_counter_index); 21762306a36Sopenharmony_ci if (err) 21862306a36Sopenharmony_ci goto err_counter_clear; 21962306a36Sopenharmony_ci return 0; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cierr_counter_clear: 22262306a36Sopenharmony_ci mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW, 22362306a36Sopenharmony_ci *p_counter_index); 22462306a36Sopenharmony_ci return err; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_civoid mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp, 22862306a36Sopenharmony_ci unsigned int counter_index) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW, 23162306a36Sopenharmony_ci counter_index); 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_civoid mlxsw_sp_txhdr_construct(struct sk_buff *skb, 23562306a36Sopenharmony_ci const struct mlxsw_tx_info *tx_info) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci memset(txhdr, 0, MLXSW_TXHDR_LEN); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci mlxsw_tx_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1); 24262306a36Sopenharmony_ci mlxsw_tx_hdr_ctl_set(txhdr, MLXSW_TXHDR_ETH_CTL); 24362306a36Sopenharmony_ci mlxsw_tx_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH); 24462306a36Sopenharmony_ci mlxsw_tx_hdr_swid_set(txhdr, 0); 24562306a36Sopenharmony_ci mlxsw_tx_hdr_control_tclass_set(txhdr, 1); 24662306a36Sopenharmony_ci mlxsw_tx_hdr_port_mid_set(txhdr, tx_info->local_port); 24762306a36Sopenharmony_ci mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ciint 25162306a36Sopenharmony_cimlxsw_sp_txhdr_ptp_data_construct(struct mlxsw_core *mlxsw_core, 25262306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, 25362306a36Sopenharmony_ci struct sk_buff *skb, 25462306a36Sopenharmony_ci const struct mlxsw_tx_info *tx_info) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci char *txhdr; 25762306a36Sopenharmony_ci u16 max_fid; 25862306a36Sopenharmony_ci int err; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) { 26162306a36Sopenharmony_ci err = -ENOMEM; 26262306a36Sopenharmony_ci goto err_skb_cow_head; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, FID)) { 26662306a36Sopenharmony_ci err = -EIO; 26762306a36Sopenharmony_ci goto err_res_valid; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci max_fid = MLXSW_CORE_RES_GET(mlxsw_core, FID); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci txhdr = skb_push(skb, MLXSW_TXHDR_LEN); 27262306a36Sopenharmony_ci memset(txhdr, 0, MLXSW_TXHDR_LEN); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci mlxsw_tx_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1); 27562306a36Sopenharmony_ci mlxsw_tx_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH); 27662306a36Sopenharmony_ci mlxsw_tx_hdr_rx_is_router_set(txhdr, true); 27762306a36Sopenharmony_ci mlxsw_tx_hdr_fid_valid_set(txhdr, true); 27862306a36Sopenharmony_ci mlxsw_tx_hdr_fid_set(txhdr, max_fid + tx_info->local_port - 1); 27962306a36Sopenharmony_ci mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_DATA); 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cierr_res_valid: 28362306a36Sopenharmony_cierr_skb_cow_head: 28462306a36Sopenharmony_ci this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped); 28562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 28662306a36Sopenharmony_ci return err; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic bool mlxsw_sp_skb_requires_ts(struct sk_buff *skb) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci unsigned int type; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) 29462306a36Sopenharmony_ci return false; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci type = ptp_classify_raw(skb); 29762306a36Sopenharmony_ci return !!ptp_parse_header(skb, type); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic int mlxsw_sp_txhdr_handle(struct mlxsw_core *mlxsw_core, 30162306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, 30262306a36Sopenharmony_ci struct sk_buff *skb, 30362306a36Sopenharmony_ci const struct mlxsw_tx_info *tx_info) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* In Spectrum-2 and Spectrum-3, PTP events that require a time stamp 30862306a36Sopenharmony_ci * need special handling and cannot be transmitted as regular control 30962306a36Sopenharmony_ci * packets. 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_ci if (unlikely(mlxsw_sp_skb_requires_ts(skb))) 31262306a36Sopenharmony_ci return mlxsw_sp->ptp_ops->txhdr_construct(mlxsw_core, 31362306a36Sopenharmony_ci mlxsw_sp_port, skb, 31462306a36Sopenharmony_ci tx_info); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) { 31762306a36Sopenharmony_ci this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped); 31862306a36Sopenharmony_ci dev_kfree_skb_any(skb); 31962306a36Sopenharmony_ci return -ENOMEM; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci mlxsw_sp_txhdr_construct(skb, tx_info); 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cienum mlxsw_reg_spms_state mlxsw_sp_stp_spms_state(u8 state) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci switch (state) { 32962306a36Sopenharmony_ci case BR_STATE_FORWARDING: 33062306a36Sopenharmony_ci return MLXSW_REG_SPMS_STATE_FORWARDING; 33162306a36Sopenharmony_ci case BR_STATE_LEARNING: 33262306a36Sopenharmony_ci return MLXSW_REG_SPMS_STATE_LEARNING; 33362306a36Sopenharmony_ci case BR_STATE_LISTENING: 33462306a36Sopenharmony_ci case BR_STATE_DISABLED: 33562306a36Sopenharmony_ci case BR_STATE_BLOCKING: 33662306a36Sopenharmony_ci return MLXSW_REG_SPMS_STATE_DISCARDING; 33762306a36Sopenharmony_ci default: 33862306a36Sopenharmony_ci BUG(); 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ciint mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, 34362306a36Sopenharmony_ci u8 state) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci enum mlxsw_reg_spms_state spms_state = mlxsw_sp_stp_spms_state(state); 34662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 34762306a36Sopenharmony_ci char *spms_pl; 34862306a36Sopenharmony_ci int err; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL); 35162306a36Sopenharmony_ci if (!spms_pl) 35262306a36Sopenharmony_ci return -ENOMEM; 35362306a36Sopenharmony_ci mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port); 35462306a36Sopenharmony_ci mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl); 35762306a36Sopenharmony_ci kfree(spms_pl); 35862306a36Sopenharmony_ci return err; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int mlxsw_sp_base_mac_get(struct mlxsw_sp *mlxsw_sp) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci char spad_pl[MLXSW_REG_SPAD_LEN] = {0}; 36462306a36Sopenharmony_ci int err; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(spad), spad_pl); 36762306a36Sopenharmony_ci if (err) 36862306a36Sopenharmony_ci return err; 36962306a36Sopenharmony_ci mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_sp->base_mac); 37062306a36Sopenharmony_ci return 0; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ciint mlxsw_sp_port_admin_status_set(struct mlxsw_sp_port *mlxsw_sp_port, 37462306a36Sopenharmony_ci bool is_up) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 37762306a36Sopenharmony_ci char paos_pl[MLXSW_REG_PAOS_LEN]; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci mlxsw_reg_paos_pack(paos_pl, mlxsw_sp_port->local_port, 38062306a36Sopenharmony_ci is_up ? MLXSW_PORT_ADMIN_STATUS_UP : 38162306a36Sopenharmony_ci MLXSW_PORT_ADMIN_STATUS_DOWN); 38262306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(paos), paos_pl); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic int mlxsw_sp_port_dev_addr_set(struct mlxsw_sp_port *mlxsw_sp_port, 38662306a36Sopenharmony_ci const unsigned char *addr) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 38962306a36Sopenharmony_ci char ppad_pl[MLXSW_REG_PPAD_LEN]; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci mlxsw_reg_ppad_pack(ppad_pl, true, mlxsw_sp_port->local_port); 39262306a36Sopenharmony_ci mlxsw_reg_ppad_mac_memcpy_to(ppad_pl, addr); 39362306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ppad), ppad_pl); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int mlxsw_sp_port_dev_addr_init(struct mlxsw_sp_port *mlxsw_sp_port) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci eth_hw_addr_gen(mlxsw_sp_port->dev, mlxsw_sp->base_mac, 40162306a36Sopenharmony_ci mlxsw_sp_port->local_port); 40262306a36Sopenharmony_ci return mlxsw_sp_port_dev_addr_set(mlxsw_sp_port, 40362306a36Sopenharmony_ci mlxsw_sp_port->dev->dev_addr); 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic int mlxsw_sp_port_max_mtu_get(struct mlxsw_sp_port *mlxsw_sp_port, int *p_max_mtu) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 40962306a36Sopenharmony_ci char pmtu_pl[MLXSW_REG_PMTU_LEN]; 41062306a36Sopenharmony_ci int err; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sp_port->local_port, 0); 41362306a36Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl); 41462306a36Sopenharmony_ci if (err) 41562306a36Sopenharmony_ci return err; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci *p_max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl); 41862306a36Sopenharmony_ci return 0; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic int mlxsw_sp_port_mtu_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 42462306a36Sopenharmony_ci char pmtu_pl[MLXSW_REG_PMTU_LEN]; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci mtu += MLXSW_TXHDR_LEN + ETH_HLEN; 42762306a36Sopenharmony_ci if (mtu > mlxsw_sp_port->max_mtu) 42862306a36Sopenharmony_ci return -EINVAL; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sp_port->local_port, mtu); 43162306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic int mlxsw_sp_port_swid_set(struct mlxsw_sp *mlxsw_sp, 43562306a36Sopenharmony_ci u16 local_port, u8 swid) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci char pspa_pl[MLXSW_REG_PSPA_LEN]; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci mlxsw_reg_pspa_pack(pspa_pl, swid, local_port); 44062306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pspa), pspa_pl); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ciint mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 44662306a36Sopenharmony_ci char svpe_pl[MLXSW_REG_SVPE_LEN]; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci mlxsw_reg_svpe_pack(svpe_pl, mlxsw_sp_port->local_port, enable); 44962306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svpe), svpe_pl); 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ciint mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, 45362306a36Sopenharmony_ci bool learn_enable) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 45662306a36Sopenharmony_ci char *spvmlr_pl; 45762306a36Sopenharmony_ci int err; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci spvmlr_pl = kmalloc(MLXSW_REG_SPVMLR_LEN, GFP_KERNEL); 46062306a36Sopenharmony_ci if (!spvmlr_pl) 46162306a36Sopenharmony_ci return -ENOMEM; 46262306a36Sopenharmony_ci mlxsw_reg_spvmlr_pack(spvmlr_pl, mlxsw_sp_port->local_port, vid, vid, 46362306a36Sopenharmony_ci learn_enable); 46462306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvmlr), spvmlr_pl); 46562306a36Sopenharmony_ci kfree(spvmlr_pl); 46662306a36Sopenharmony_ci return err; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ciint mlxsw_sp_port_security_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 47262306a36Sopenharmony_ci char spfsr_pl[MLXSW_REG_SPFSR_LEN]; 47362306a36Sopenharmony_ci int err; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (mlxsw_sp_port->security == enable) 47662306a36Sopenharmony_ci return 0; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci mlxsw_reg_spfsr_pack(spfsr_pl, mlxsw_sp_port->local_port, enable); 47962306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spfsr), spfsr_pl); 48062306a36Sopenharmony_ci if (err) 48162306a36Sopenharmony_ci return err; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci mlxsw_sp_port->security = enable; 48462306a36Sopenharmony_ci return 0; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ciint mlxsw_sp_ethtype_to_sver_type(u16 ethtype, u8 *p_sver_type) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci switch (ethtype) { 49062306a36Sopenharmony_ci case ETH_P_8021Q: 49162306a36Sopenharmony_ci *p_sver_type = 0; 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci case ETH_P_8021AD: 49462306a36Sopenharmony_ci *p_sver_type = 1; 49562306a36Sopenharmony_ci break; 49662306a36Sopenharmony_ci default: 49762306a36Sopenharmony_ci return -EINVAL; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ciint mlxsw_sp_port_egress_ethtype_set(struct mlxsw_sp_port *mlxsw_sp_port, 50462306a36Sopenharmony_ci u16 ethtype) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 50762306a36Sopenharmony_ci char spevet_pl[MLXSW_REG_SPEVET_LEN]; 50862306a36Sopenharmony_ci u8 sver_type; 50962306a36Sopenharmony_ci int err; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci err = mlxsw_sp_ethtype_to_sver_type(ethtype, &sver_type); 51262306a36Sopenharmony_ci if (err) 51362306a36Sopenharmony_ci return err; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci mlxsw_reg_spevet_pack(spevet_pl, mlxsw_sp_port->local_port, sver_type); 51662306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spevet), spevet_pl); 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, 52062306a36Sopenharmony_ci u16 vid, u16 ethtype) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 52362306a36Sopenharmony_ci char spvid_pl[MLXSW_REG_SPVID_LEN]; 52462306a36Sopenharmony_ci u8 sver_type; 52562306a36Sopenharmony_ci int err; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci err = mlxsw_sp_ethtype_to_sver_type(ethtype, &sver_type); 52862306a36Sopenharmony_ci if (err) 52962306a36Sopenharmony_ci return err; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci mlxsw_reg_spvid_pack(spvid_pl, mlxsw_sp_port->local_port, vid, 53262306a36Sopenharmony_ci sver_type); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl); 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic int mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port *mlxsw_sp_port, 53862306a36Sopenharmony_ci bool allow) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 54162306a36Sopenharmony_ci char spaft_pl[MLXSW_REG_SPAFT_LEN]; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci mlxsw_reg_spaft_pack(spaft_pl, mlxsw_sp_port->local_port, allow); 54462306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spaft), spaft_pl); 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ciint mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, 54862306a36Sopenharmony_ci u16 ethtype) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci int err; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (!vid) { 55362306a36Sopenharmony_ci err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, false); 55462306a36Sopenharmony_ci if (err) 55562306a36Sopenharmony_ci return err; 55662306a36Sopenharmony_ci } else { 55762306a36Sopenharmony_ci err = __mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid, ethtype); 55862306a36Sopenharmony_ci if (err) 55962306a36Sopenharmony_ci return err; 56062306a36Sopenharmony_ci err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, true); 56162306a36Sopenharmony_ci if (err) 56262306a36Sopenharmony_ci goto err_port_allow_untagged_set; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci mlxsw_sp_port->pvid = vid; 56662306a36Sopenharmony_ci return 0; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cierr_port_allow_untagged_set: 56962306a36Sopenharmony_ci __mlxsw_sp_port_pvid_set(mlxsw_sp_port, mlxsw_sp_port->pvid, ethtype); 57062306a36Sopenharmony_ci return err; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic int 57462306a36Sopenharmony_cimlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 57762306a36Sopenharmony_ci char sspr_pl[MLXSW_REG_SSPR_LEN]; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci mlxsw_reg_sspr_pack(sspr_pl, mlxsw_sp_port->local_port); 58062306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sspr), sspr_pl); 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic int 58462306a36Sopenharmony_cimlxsw_sp_port_module_info_parse(struct mlxsw_sp *mlxsw_sp, 58562306a36Sopenharmony_ci u16 local_port, char *pmlp_pl, 58662306a36Sopenharmony_ci struct mlxsw_sp_port_mapping *port_mapping) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci bool separate_rxtx; 58962306a36Sopenharmony_ci u8 first_lane; 59062306a36Sopenharmony_ci u8 slot_index; 59162306a36Sopenharmony_ci u8 module; 59262306a36Sopenharmony_ci u8 width; 59362306a36Sopenharmony_ci int i; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); 59662306a36Sopenharmony_ci slot_index = mlxsw_reg_pmlp_slot_index_get(pmlp_pl, 0); 59762306a36Sopenharmony_ci width = mlxsw_reg_pmlp_width_get(pmlp_pl); 59862306a36Sopenharmony_ci separate_rxtx = mlxsw_reg_pmlp_rxtx_get(pmlp_pl); 59962306a36Sopenharmony_ci first_lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (width && !is_power_of_2(width)) { 60262306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: width value is not power of 2\n", 60362306a36Sopenharmony_ci local_port); 60462306a36Sopenharmony_ci return -EINVAL; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci for (i = 0; i < width; i++) { 60862306a36Sopenharmony_ci if (mlxsw_reg_pmlp_module_get(pmlp_pl, i) != module) { 60962306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: contains multiple modules\n", 61062306a36Sopenharmony_ci local_port); 61162306a36Sopenharmony_ci return -EINVAL; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci if (mlxsw_reg_pmlp_slot_index_get(pmlp_pl, i) != slot_index) { 61462306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: contains multiple slot indexes\n", 61562306a36Sopenharmony_ci local_port); 61662306a36Sopenharmony_ci return -EINVAL; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci if (separate_rxtx && 61962306a36Sopenharmony_ci mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) != 62062306a36Sopenharmony_ci mlxsw_reg_pmlp_rx_lane_get(pmlp_pl, i)) { 62162306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are different\n", 62262306a36Sopenharmony_ci local_port); 62362306a36Sopenharmony_ci return -EINVAL; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci if (mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) != i + first_lane) { 62662306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are not sequential\n", 62762306a36Sopenharmony_ci local_port); 62862306a36Sopenharmony_ci return -EINVAL; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci port_mapping->module = module; 63362306a36Sopenharmony_ci port_mapping->slot_index = slot_index; 63462306a36Sopenharmony_ci port_mapping->width = width; 63562306a36Sopenharmony_ci port_mapping->module_width = width; 63662306a36Sopenharmony_ci port_mapping->lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0); 63762306a36Sopenharmony_ci return 0; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic int 64162306a36Sopenharmony_cimlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, u16 local_port, 64262306a36Sopenharmony_ci struct mlxsw_sp_port_mapping *port_mapping) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci char pmlp_pl[MLXSW_REG_PMLP_LEN]; 64562306a36Sopenharmony_ci int err; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci mlxsw_reg_pmlp_pack(pmlp_pl, local_port); 64862306a36Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl); 64962306a36Sopenharmony_ci if (err) 65062306a36Sopenharmony_ci return err; 65162306a36Sopenharmony_ci return mlxsw_sp_port_module_info_parse(mlxsw_sp, local_port, 65262306a36Sopenharmony_ci pmlp_pl, port_mapping); 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_cistatic int 65662306a36Sopenharmony_cimlxsw_sp_port_module_map(struct mlxsw_sp *mlxsw_sp, u16 local_port, 65762306a36Sopenharmony_ci const struct mlxsw_sp_port_mapping *port_mapping) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci char pmlp_pl[MLXSW_REG_PMLP_LEN]; 66062306a36Sopenharmony_ci int i, err; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci mlxsw_env_module_port_map(mlxsw_sp->core, port_mapping->slot_index, 66362306a36Sopenharmony_ci port_mapping->module); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci mlxsw_reg_pmlp_pack(pmlp_pl, local_port); 66662306a36Sopenharmony_ci mlxsw_reg_pmlp_width_set(pmlp_pl, port_mapping->width); 66762306a36Sopenharmony_ci for (i = 0; i < port_mapping->width; i++) { 66862306a36Sopenharmony_ci mlxsw_reg_pmlp_slot_index_set(pmlp_pl, i, 66962306a36Sopenharmony_ci port_mapping->slot_index); 67062306a36Sopenharmony_ci mlxsw_reg_pmlp_module_set(pmlp_pl, i, port_mapping->module); 67162306a36Sopenharmony_ci mlxsw_reg_pmlp_tx_lane_set(pmlp_pl, i, port_mapping->lane + i); /* Rx & Tx */ 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl); 67562306a36Sopenharmony_ci if (err) 67662306a36Sopenharmony_ci goto err_pmlp_write; 67762306a36Sopenharmony_ci return 0; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cierr_pmlp_write: 68062306a36Sopenharmony_ci mlxsw_env_module_port_unmap(mlxsw_sp->core, port_mapping->slot_index, 68162306a36Sopenharmony_ci port_mapping->module); 68262306a36Sopenharmony_ci return err; 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic void mlxsw_sp_port_module_unmap(struct mlxsw_sp *mlxsw_sp, u16 local_port, 68662306a36Sopenharmony_ci u8 slot_index, u8 module) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci char pmlp_pl[MLXSW_REG_PMLP_LEN]; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci mlxsw_reg_pmlp_pack(pmlp_pl, local_port); 69162306a36Sopenharmony_ci mlxsw_reg_pmlp_width_set(pmlp_pl, 0); 69262306a36Sopenharmony_ci mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl); 69362306a36Sopenharmony_ci mlxsw_env_module_port_unmap(mlxsw_sp->core, slot_index, module); 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic int mlxsw_sp_port_open(struct net_device *dev) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 69962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 70062306a36Sopenharmony_ci int err; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci err = mlxsw_env_module_port_up(mlxsw_sp->core, 70362306a36Sopenharmony_ci mlxsw_sp_port->mapping.slot_index, 70462306a36Sopenharmony_ci mlxsw_sp_port->mapping.module); 70562306a36Sopenharmony_ci if (err) 70662306a36Sopenharmony_ci return err; 70762306a36Sopenharmony_ci err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true); 70862306a36Sopenharmony_ci if (err) 70962306a36Sopenharmony_ci goto err_port_admin_status_set; 71062306a36Sopenharmony_ci netif_start_queue(dev); 71162306a36Sopenharmony_ci return 0; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cierr_port_admin_status_set: 71462306a36Sopenharmony_ci mlxsw_env_module_port_down(mlxsw_sp->core, 71562306a36Sopenharmony_ci mlxsw_sp_port->mapping.slot_index, 71662306a36Sopenharmony_ci mlxsw_sp_port->mapping.module); 71762306a36Sopenharmony_ci return err; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic int mlxsw_sp_port_stop(struct net_device *dev) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 72362306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci netif_stop_queue(dev); 72662306a36Sopenharmony_ci mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false); 72762306a36Sopenharmony_ci mlxsw_env_module_port_down(mlxsw_sp->core, 72862306a36Sopenharmony_ci mlxsw_sp_port->mapping.slot_index, 72962306a36Sopenharmony_ci mlxsw_sp_port->mapping.module); 73062306a36Sopenharmony_ci return 0; 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb, 73462306a36Sopenharmony_ci struct net_device *dev) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 73762306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 73862306a36Sopenharmony_ci struct mlxsw_sp_port_pcpu_stats *pcpu_stats; 73962306a36Sopenharmony_ci const struct mlxsw_tx_info tx_info = { 74062306a36Sopenharmony_ci .local_port = mlxsw_sp_port->local_port, 74162306a36Sopenharmony_ci .is_emad = false, 74262306a36Sopenharmony_ci }; 74362306a36Sopenharmony_ci u64 len; 74462306a36Sopenharmony_ci int err; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb)); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (mlxsw_core_skb_transmit_busy(mlxsw_sp->core, &tx_info)) 74962306a36Sopenharmony_ci return NETDEV_TX_BUSY; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (eth_skb_pad(skb)) { 75262306a36Sopenharmony_ci this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped); 75362306a36Sopenharmony_ci return NETDEV_TX_OK; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci err = mlxsw_sp_txhdr_handle(mlxsw_sp->core, mlxsw_sp_port, skb, 75762306a36Sopenharmony_ci &tx_info); 75862306a36Sopenharmony_ci if (err) 75962306a36Sopenharmony_ci return NETDEV_TX_OK; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* TX header is consumed by HW on the way so we shouldn't count its 76262306a36Sopenharmony_ci * bytes as being sent. 76362306a36Sopenharmony_ci */ 76462306a36Sopenharmony_ci len = skb->len - MLXSW_TXHDR_LEN; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* Due to a race we might fail here because of a full queue. In that 76762306a36Sopenharmony_ci * unlikely case we simply drop the packet. 76862306a36Sopenharmony_ci */ 76962306a36Sopenharmony_ci err = mlxsw_core_skb_transmit(mlxsw_sp->core, skb, &tx_info); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (!err) { 77262306a36Sopenharmony_ci pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats); 77362306a36Sopenharmony_ci u64_stats_update_begin(&pcpu_stats->syncp); 77462306a36Sopenharmony_ci pcpu_stats->tx_packets++; 77562306a36Sopenharmony_ci pcpu_stats->tx_bytes += len; 77662306a36Sopenharmony_ci u64_stats_update_end(&pcpu_stats->syncp); 77762306a36Sopenharmony_ci } else { 77862306a36Sopenharmony_ci this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped); 77962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci return NETDEV_TX_OK; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic void mlxsw_sp_set_rx_mode(struct net_device *dev) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic int mlxsw_sp_port_set_mac_address(struct net_device *dev, void *p) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 79162306a36Sopenharmony_ci struct sockaddr *addr = p; 79262306a36Sopenharmony_ci int err; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 79562306a36Sopenharmony_ci return -EADDRNOTAVAIL; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci err = mlxsw_sp_port_dev_addr_set(mlxsw_sp_port, addr->sa_data); 79862306a36Sopenharmony_ci if (err) 79962306a36Sopenharmony_ci return err; 80062306a36Sopenharmony_ci eth_hw_addr_set(dev, addr->sa_data); 80162306a36Sopenharmony_ci return 0; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic int mlxsw_sp_port_change_mtu(struct net_device *dev, int mtu) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 80762306a36Sopenharmony_ci struct mlxsw_sp_hdroom orig_hdroom; 80862306a36Sopenharmony_ci struct mlxsw_sp_hdroom hdroom; 80962306a36Sopenharmony_ci int err; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci orig_hdroom = *mlxsw_sp_port->hdroom; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci hdroom = orig_hdroom; 81462306a36Sopenharmony_ci hdroom.mtu = mtu; 81562306a36Sopenharmony_ci mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom); 81862306a36Sopenharmony_ci if (err) { 81962306a36Sopenharmony_ci netdev_err(dev, "Failed to configure port's headroom\n"); 82062306a36Sopenharmony_ci return err; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, mtu); 82462306a36Sopenharmony_ci if (err) 82562306a36Sopenharmony_ci goto err_port_mtu_set; 82662306a36Sopenharmony_ci dev->mtu = mtu; 82762306a36Sopenharmony_ci return 0; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cierr_port_mtu_set: 83062306a36Sopenharmony_ci mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom); 83162306a36Sopenharmony_ci return err; 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic int 83562306a36Sopenharmony_cimlxsw_sp_port_get_sw_stats64(const struct net_device *dev, 83662306a36Sopenharmony_ci struct rtnl_link_stats64 *stats) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 83962306a36Sopenharmony_ci struct mlxsw_sp_port_pcpu_stats *p; 84062306a36Sopenharmony_ci u64 rx_packets, rx_bytes, tx_packets, tx_bytes; 84162306a36Sopenharmony_ci u32 tx_dropped = 0; 84262306a36Sopenharmony_ci unsigned int start; 84362306a36Sopenharmony_ci int i; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci for_each_possible_cpu(i) { 84662306a36Sopenharmony_ci p = per_cpu_ptr(mlxsw_sp_port->pcpu_stats, i); 84762306a36Sopenharmony_ci do { 84862306a36Sopenharmony_ci start = u64_stats_fetch_begin(&p->syncp); 84962306a36Sopenharmony_ci rx_packets = p->rx_packets; 85062306a36Sopenharmony_ci rx_bytes = p->rx_bytes; 85162306a36Sopenharmony_ci tx_packets = p->tx_packets; 85262306a36Sopenharmony_ci tx_bytes = p->tx_bytes; 85362306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&p->syncp, start)); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci stats->rx_packets += rx_packets; 85662306a36Sopenharmony_ci stats->rx_bytes += rx_bytes; 85762306a36Sopenharmony_ci stats->tx_packets += tx_packets; 85862306a36Sopenharmony_ci stats->tx_bytes += tx_bytes; 85962306a36Sopenharmony_ci /* tx_dropped is u32, updated without syncp protection. */ 86062306a36Sopenharmony_ci tx_dropped += p->tx_dropped; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci stats->tx_dropped = tx_dropped; 86362306a36Sopenharmony_ci return 0; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic bool mlxsw_sp_port_has_offload_stats(const struct net_device *dev, int attr_id) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci switch (attr_id) { 86962306a36Sopenharmony_ci case IFLA_OFFLOAD_XSTATS_CPU_HIT: 87062306a36Sopenharmony_ci return true; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci return false; 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic int mlxsw_sp_port_get_offload_stats(int attr_id, const struct net_device *dev, 87762306a36Sopenharmony_ci void *sp) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci switch (attr_id) { 88062306a36Sopenharmony_ci case IFLA_OFFLOAD_XSTATS_CPU_HIT: 88162306a36Sopenharmony_ci return mlxsw_sp_port_get_sw_stats64(dev, sp); 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci return -EINVAL; 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ciint mlxsw_sp_port_get_stats_raw(struct net_device *dev, int grp, 88862306a36Sopenharmony_ci int prio, char *ppcnt_pl) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 89162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sp_port->local_port, grp, prio); 89462306a36Sopenharmony_ci return mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ppcnt), ppcnt_pl); 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic int mlxsw_sp_port_get_hw_stats(struct net_device *dev, 89862306a36Sopenharmony_ci struct rtnl_link_stats64 *stats) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci char ppcnt_pl[MLXSW_REG_PPCNT_LEN]; 90162306a36Sopenharmony_ci int err; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT, 90462306a36Sopenharmony_ci 0, ppcnt_pl); 90562306a36Sopenharmony_ci if (err) 90662306a36Sopenharmony_ci goto out; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci stats->tx_packets = 90962306a36Sopenharmony_ci mlxsw_reg_ppcnt_a_frames_transmitted_ok_get(ppcnt_pl); 91062306a36Sopenharmony_ci stats->rx_packets = 91162306a36Sopenharmony_ci mlxsw_reg_ppcnt_a_frames_received_ok_get(ppcnt_pl); 91262306a36Sopenharmony_ci stats->tx_bytes = 91362306a36Sopenharmony_ci mlxsw_reg_ppcnt_a_octets_transmitted_ok_get(ppcnt_pl); 91462306a36Sopenharmony_ci stats->rx_bytes = 91562306a36Sopenharmony_ci mlxsw_reg_ppcnt_a_octets_received_ok_get(ppcnt_pl); 91662306a36Sopenharmony_ci stats->multicast = 91762306a36Sopenharmony_ci mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get(ppcnt_pl); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci stats->rx_crc_errors = 92062306a36Sopenharmony_ci mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get(ppcnt_pl); 92162306a36Sopenharmony_ci stats->rx_frame_errors = 92262306a36Sopenharmony_ci mlxsw_reg_ppcnt_a_alignment_errors_get(ppcnt_pl); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci stats->rx_length_errors = ( 92562306a36Sopenharmony_ci mlxsw_reg_ppcnt_a_in_range_length_errors_get(ppcnt_pl) + 92662306a36Sopenharmony_ci mlxsw_reg_ppcnt_a_out_of_range_length_field_get(ppcnt_pl) + 92762306a36Sopenharmony_ci mlxsw_reg_ppcnt_a_frame_too_long_errors_get(ppcnt_pl)); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci stats->rx_errors = (stats->rx_crc_errors + 93062306a36Sopenharmony_ci stats->rx_frame_errors + stats->rx_length_errors); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ciout: 93362306a36Sopenharmony_ci return err; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_cistatic void 93762306a36Sopenharmony_cimlxsw_sp_port_get_hw_xstats(struct net_device *dev, 93862306a36Sopenharmony_ci struct mlxsw_sp_port_xstats *xstats) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci char ppcnt_pl[MLXSW_REG_PPCNT_LEN]; 94162306a36Sopenharmony_ci int err, i; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_EXT_CNT, 0, 94462306a36Sopenharmony_ci ppcnt_pl); 94562306a36Sopenharmony_ci if (!err) 94662306a36Sopenharmony_ci xstats->ecn = mlxsw_reg_ppcnt_ecn_marked_get(ppcnt_pl); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci for (i = 0; i < TC_MAX_QUEUE; i++) { 94962306a36Sopenharmony_ci err = mlxsw_sp_port_get_stats_raw(dev, 95062306a36Sopenharmony_ci MLXSW_REG_PPCNT_TC_CONG_CNT, 95162306a36Sopenharmony_ci i, ppcnt_pl); 95262306a36Sopenharmony_ci if (err) 95362306a36Sopenharmony_ci goto tc_cnt; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci xstats->wred_drop[i] = 95662306a36Sopenharmony_ci mlxsw_reg_ppcnt_wred_discard_get(ppcnt_pl); 95762306a36Sopenharmony_ci xstats->tc_ecn[i] = mlxsw_reg_ppcnt_ecn_marked_tc_get(ppcnt_pl); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_citc_cnt: 96062306a36Sopenharmony_ci err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_TC_CNT, 96162306a36Sopenharmony_ci i, ppcnt_pl); 96262306a36Sopenharmony_ci if (err) 96362306a36Sopenharmony_ci continue; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci xstats->backlog[i] = 96662306a36Sopenharmony_ci mlxsw_reg_ppcnt_tc_transmit_queue_get(ppcnt_pl); 96762306a36Sopenharmony_ci xstats->tail_drop[i] = 96862306a36Sopenharmony_ci mlxsw_reg_ppcnt_tc_no_buffer_discard_uc_get(ppcnt_pl); 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 97262306a36Sopenharmony_ci err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_PRIO_CNT, 97362306a36Sopenharmony_ci i, ppcnt_pl); 97462306a36Sopenharmony_ci if (err) 97562306a36Sopenharmony_ci continue; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci xstats->tx_packets[i] = mlxsw_reg_ppcnt_tx_frames_get(ppcnt_pl); 97862306a36Sopenharmony_ci xstats->tx_bytes[i] = mlxsw_reg_ppcnt_tx_octets_get(ppcnt_pl); 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_cistatic void update_stats_cache(struct work_struct *work) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = 98562306a36Sopenharmony_ci container_of(work, struct mlxsw_sp_port, 98662306a36Sopenharmony_ci periodic_hw_stats.update_dw.work); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci if (!netif_carrier_ok(mlxsw_sp_port->dev)) 98962306a36Sopenharmony_ci /* Note: mlxsw_sp_port_down_wipe_counters() clears the cache as 99062306a36Sopenharmony_ci * necessary when port goes down. 99162306a36Sopenharmony_ci */ 99262306a36Sopenharmony_ci goto out; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci mlxsw_sp_port_get_hw_stats(mlxsw_sp_port->dev, 99562306a36Sopenharmony_ci &mlxsw_sp_port->periodic_hw_stats.stats); 99662306a36Sopenharmony_ci mlxsw_sp_port_get_hw_xstats(mlxsw_sp_port->dev, 99762306a36Sopenharmony_ci &mlxsw_sp_port->periodic_hw_stats.xstats); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ciout: 100062306a36Sopenharmony_ci mlxsw_core_schedule_dw(&mlxsw_sp_port->periodic_hw_stats.update_dw, 100162306a36Sopenharmony_ci MLXSW_HW_STATS_UPDATE_TIME); 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci/* Return the stats from a cache that is updated periodically, 100562306a36Sopenharmony_ci * as this function might get called in an atomic context. 100662306a36Sopenharmony_ci */ 100762306a36Sopenharmony_cistatic void 100862306a36Sopenharmony_cimlxsw_sp_port_get_stats64(struct net_device *dev, 100962306a36Sopenharmony_ci struct rtnl_link_stats64 *stats) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci memcpy(stats, &mlxsw_sp_port->periodic_hw_stats.stats, sizeof(*stats)); 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_cistatic int __mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, 101762306a36Sopenharmony_ci u16 vid_begin, u16 vid_end, 101862306a36Sopenharmony_ci bool is_member, bool untagged) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 102162306a36Sopenharmony_ci char *spvm_pl; 102262306a36Sopenharmony_ci int err; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci spvm_pl = kmalloc(MLXSW_REG_SPVM_LEN, GFP_KERNEL); 102562306a36Sopenharmony_ci if (!spvm_pl) 102662306a36Sopenharmony_ci return -ENOMEM; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci mlxsw_reg_spvm_pack(spvm_pl, mlxsw_sp_port->local_port, vid_begin, 102962306a36Sopenharmony_ci vid_end, is_member, untagged); 103062306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvm), spvm_pl); 103162306a36Sopenharmony_ci kfree(spvm_pl); 103262306a36Sopenharmony_ci return err; 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ciint mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, 103662306a36Sopenharmony_ci u16 vid_end, bool is_member, bool untagged) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci u16 vid, vid_e; 103962306a36Sopenharmony_ci int err; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci for (vid = vid_begin; vid <= vid_end; 104262306a36Sopenharmony_ci vid += MLXSW_REG_SPVM_REC_MAX_COUNT) { 104362306a36Sopenharmony_ci vid_e = min((u16) (vid + MLXSW_REG_SPVM_REC_MAX_COUNT - 1), 104462306a36Sopenharmony_ci vid_end); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci err = __mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid_e, 104762306a36Sopenharmony_ci is_member, untagged); 104862306a36Sopenharmony_ci if (err) 104962306a36Sopenharmony_ci return err; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci return 0; 105362306a36Sopenharmony_ci} 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_cistatic void mlxsw_sp_port_vlan_flush(struct mlxsw_sp_port *mlxsw_sp_port, 105662306a36Sopenharmony_ci bool flush_default) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, *tmp; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci list_for_each_entry_safe(mlxsw_sp_port_vlan, tmp, 106162306a36Sopenharmony_ci &mlxsw_sp_port->vlans_list, list) { 106262306a36Sopenharmony_ci if (!flush_default && 106362306a36Sopenharmony_ci mlxsw_sp_port_vlan->vid == MLXSW_SP_DEFAULT_VID) 106462306a36Sopenharmony_ci continue; 106562306a36Sopenharmony_ci mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_cistatic void 107062306a36Sopenharmony_cimlxsw_sp_port_vlan_cleanup(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) 107162306a36Sopenharmony_ci{ 107262306a36Sopenharmony_ci if (mlxsw_sp_port_vlan->bridge_port) 107362306a36Sopenharmony_ci mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); 107462306a36Sopenharmony_ci else if (mlxsw_sp_port_vlan->fid) 107562306a36Sopenharmony_ci mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cistruct mlxsw_sp_port_vlan * 107962306a36Sopenharmony_cimlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 108262306a36Sopenharmony_ci bool untagged = vid == MLXSW_SP_DEFAULT_VID; 108362306a36Sopenharmony_ci int err; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); 108662306a36Sopenharmony_ci if (mlxsw_sp_port_vlan) 108762306a36Sopenharmony_ci return ERR_PTR(-EEXIST); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true, untagged); 109062306a36Sopenharmony_ci if (err) 109162306a36Sopenharmony_ci return ERR_PTR(err); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci mlxsw_sp_port_vlan = kzalloc(sizeof(*mlxsw_sp_port_vlan), GFP_KERNEL); 109462306a36Sopenharmony_ci if (!mlxsw_sp_port_vlan) { 109562306a36Sopenharmony_ci err = -ENOMEM; 109662306a36Sopenharmony_ci goto err_port_vlan_alloc; 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port; 110062306a36Sopenharmony_ci mlxsw_sp_port_vlan->vid = vid; 110162306a36Sopenharmony_ci list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci return mlxsw_sp_port_vlan; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cierr_port_vlan_alloc: 110662306a36Sopenharmony_ci mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); 110762306a36Sopenharmony_ci return ERR_PTR(err); 110862306a36Sopenharmony_ci} 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_civoid mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) 111162306a36Sopenharmony_ci{ 111262306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; 111362306a36Sopenharmony_ci u16 vid = mlxsw_sp_port_vlan->vid; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci mlxsw_sp_port_vlan_cleanup(mlxsw_sp_port_vlan); 111662306a36Sopenharmony_ci list_del(&mlxsw_sp_port_vlan->list); 111762306a36Sopenharmony_ci kfree(mlxsw_sp_port_vlan); 111862306a36Sopenharmony_ci mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false); 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_cistatic int mlxsw_sp_port_add_vid(struct net_device *dev, 112262306a36Sopenharmony_ci __be16 __always_unused proto, u16 vid) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci /* VLAN 0 is added to HW filter when device goes up, but it is 112762306a36Sopenharmony_ci * reserved in our case, so simply return. 112862306a36Sopenharmony_ci */ 112962306a36Sopenharmony_ci if (!vid) 113062306a36Sopenharmony_ci return 0; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid)); 113362306a36Sopenharmony_ci} 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ciint mlxsw_sp_port_kill_vid(struct net_device *dev, 113662306a36Sopenharmony_ci __be16 __always_unused proto, u16 vid) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 113962306a36Sopenharmony_ci struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci /* VLAN 0 is removed from HW filter when device goes down, but 114262306a36Sopenharmony_ci * it is reserved in our case, so simply return. 114362306a36Sopenharmony_ci */ 114462306a36Sopenharmony_ci if (!vid) 114562306a36Sopenharmony_ci return 0; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); 114862306a36Sopenharmony_ci if (!mlxsw_sp_port_vlan) 114962306a36Sopenharmony_ci return 0; 115062306a36Sopenharmony_ci mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci return 0; 115362306a36Sopenharmony_ci} 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_cistatic int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port, 115662306a36Sopenharmony_ci struct flow_block_offload *f) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci switch (f->binder_type) { 115962306a36Sopenharmony_ci case FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS: 116062306a36Sopenharmony_ci return mlxsw_sp_setup_tc_block_clsact(mlxsw_sp_port, f, true); 116162306a36Sopenharmony_ci case FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS: 116262306a36Sopenharmony_ci return mlxsw_sp_setup_tc_block_clsact(mlxsw_sp_port, f, false); 116362306a36Sopenharmony_ci case FLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP: 116462306a36Sopenharmony_ci return mlxsw_sp_setup_tc_block_qevent_early_drop(mlxsw_sp_port, f); 116562306a36Sopenharmony_ci case FLOW_BLOCK_BINDER_TYPE_RED_MARK: 116662306a36Sopenharmony_ci return mlxsw_sp_setup_tc_block_qevent_mark(mlxsw_sp_port, f); 116762306a36Sopenharmony_ci default: 116862306a36Sopenharmony_ci return -EOPNOTSUPP; 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_cistatic int mlxsw_sp_setup_tc(struct net_device *dev, enum tc_setup_type type, 117362306a36Sopenharmony_ci void *type_data) 117462306a36Sopenharmony_ci{ 117562306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci switch (type) { 117862306a36Sopenharmony_ci case TC_SETUP_BLOCK: 117962306a36Sopenharmony_ci return mlxsw_sp_setup_tc_block(mlxsw_sp_port, type_data); 118062306a36Sopenharmony_ci case TC_SETUP_QDISC_RED: 118162306a36Sopenharmony_ci return mlxsw_sp_setup_tc_red(mlxsw_sp_port, type_data); 118262306a36Sopenharmony_ci case TC_SETUP_QDISC_PRIO: 118362306a36Sopenharmony_ci return mlxsw_sp_setup_tc_prio(mlxsw_sp_port, type_data); 118462306a36Sopenharmony_ci case TC_SETUP_QDISC_ETS: 118562306a36Sopenharmony_ci return mlxsw_sp_setup_tc_ets(mlxsw_sp_port, type_data); 118662306a36Sopenharmony_ci case TC_SETUP_QDISC_TBF: 118762306a36Sopenharmony_ci return mlxsw_sp_setup_tc_tbf(mlxsw_sp_port, type_data); 118862306a36Sopenharmony_ci case TC_SETUP_QDISC_FIFO: 118962306a36Sopenharmony_ci return mlxsw_sp_setup_tc_fifo(mlxsw_sp_port, type_data); 119062306a36Sopenharmony_ci default: 119162306a36Sopenharmony_ci return -EOPNOTSUPP; 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistatic int mlxsw_sp_feature_hw_tc(struct net_device *dev, bool enable) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci if (!enable) { 120062306a36Sopenharmony_ci if (mlxsw_sp_flow_block_rule_count(mlxsw_sp_port->ing_flow_block) || 120162306a36Sopenharmony_ci mlxsw_sp_flow_block_rule_count(mlxsw_sp_port->eg_flow_block)) { 120262306a36Sopenharmony_ci netdev_err(dev, "Active offloaded tc filters, can't turn hw_tc_offload off\n"); 120362306a36Sopenharmony_ci return -EINVAL; 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci mlxsw_sp_flow_block_disable_inc(mlxsw_sp_port->ing_flow_block); 120662306a36Sopenharmony_ci mlxsw_sp_flow_block_disable_inc(mlxsw_sp_port->eg_flow_block); 120762306a36Sopenharmony_ci } else { 120862306a36Sopenharmony_ci mlxsw_sp_flow_block_disable_dec(mlxsw_sp_port->ing_flow_block); 120962306a36Sopenharmony_ci mlxsw_sp_flow_block_disable_dec(mlxsw_sp_port->eg_flow_block); 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci return 0; 121262306a36Sopenharmony_ci} 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_cistatic int mlxsw_sp_feature_loopback(struct net_device *dev, bool enable) 121562306a36Sopenharmony_ci{ 121662306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 121762306a36Sopenharmony_ci char pplr_pl[MLXSW_REG_PPLR_LEN]; 121862306a36Sopenharmony_ci int err; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (netif_running(dev)) 122162306a36Sopenharmony_ci mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci mlxsw_reg_pplr_pack(pplr_pl, mlxsw_sp_port->local_port, enable); 122462306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pplr), 122562306a36Sopenharmony_ci pplr_pl); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci if (netif_running(dev)) 122862306a36Sopenharmony_ci mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci return err; 123162306a36Sopenharmony_ci} 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_citypedef int (*mlxsw_sp_feature_handler)(struct net_device *dev, bool enable); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic int mlxsw_sp_handle_feature(struct net_device *dev, 123662306a36Sopenharmony_ci netdev_features_t wanted_features, 123762306a36Sopenharmony_ci netdev_features_t feature, 123862306a36Sopenharmony_ci mlxsw_sp_feature_handler feature_handler) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci netdev_features_t changes = wanted_features ^ dev->features; 124162306a36Sopenharmony_ci bool enable = !!(wanted_features & feature); 124262306a36Sopenharmony_ci int err; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci if (!(changes & feature)) 124562306a36Sopenharmony_ci return 0; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci err = feature_handler(dev, enable); 124862306a36Sopenharmony_ci if (err) { 124962306a36Sopenharmony_ci netdev_err(dev, "%s feature %pNF failed, err %d\n", 125062306a36Sopenharmony_ci enable ? "Enable" : "Disable", &feature, err); 125162306a36Sopenharmony_ci return err; 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci if (enable) 125562306a36Sopenharmony_ci dev->features |= feature; 125662306a36Sopenharmony_ci else 125762306a36Sopenharmony_ci dev->features &= ~feature; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci return 0; 126062306a36Sopenharmony_ci} 126162306a36Sopenharmony_cistatic int mlxsw_sp_set_features(struct net_device *dev, 126262306a36Sopenharmony_ci netdev_features_t features) 126362306a36Sopenharmony_ci{ 126462306a36Sopenharmony_ci netdev_features_t oper_features = dev->features; 126562306a36Sopenharmony_ci int err = 0; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci err |= mlxsw_sp_handle_feature(dev, features, NETIF_F_HW_TC, 126862306a36Sopenharmony_ci mlxsw_sp_feature_hw_tc); 126962306a36Sopenharmony_ci err |= mlxsw_sp_handle_feature(dev, features, NETIF_F_LOOPBACK, 127062306a36Sopenharmony_ci mlxsw_sp_feature_loopback); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci if (err) { 127362306a36Sopenharmony_ci dev->features = oper_features; 127462306a36Sopenharmony_ci return -EINVAL; 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci return 0; 127862306a36Sopenharmony_ci} 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_cistatic int mlxsw_sp_port_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port, 128162306a36Sopenharmony_ci struct ifreq *ifr) 128262306a36Sopenharmony_ci{ 128362306a36Sopenharmony_ci struct hwtstamp_config config; 128462306a36Sopenharmony_ci int err; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) 128762306a36Sopenharmony_ci return -EFAULT; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port, 129062306a36Sopenharmony_ci &config); 129162306a36Sopenharmony_ci if (err) 129262306a36Sopenharmony_ci return err; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci if (copy_to_user(ifr->ifr_data, &config, sizeof(config))) 129562306a36Sopenharmony_ci return -EFAULT; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci return 0; 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic int mlxsw_sp_port_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port, 130162306a36Sopenharmony_ci struct ifreq *ifr) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci struct hwtstamp_config config; 130462306a36Sopenharmony_ci int err; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_get(mlxsw_sp_port, 130762306a36Sopenharmony_ci &config); 130862306a36Sopenharmony_ci if (err) 130962306a36Sopenharmony_ci return err; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (copy_to_user(ifr->ifr_data, &config, sizeof(config))) 131262306a36Sopenharmony_ci return -EFAULT; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci return 0; 131562306a36Sopenharmony_ci} 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_cistatic inline void mlxsw_sp_port_ptp_clear(struct mlxsw_sp_port *mlxsw_sp_port) 131862306a36Sopenharmony_ci{ 131962306a36Sopenharmony_ci struct hwtstamp_config config = {0}; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port, &config); 132262306a36Sopenharmony_ci} 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_cistatic int 132562306a36Sopenharmony_cimlxsw_sp_port_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 132662306a36Sopenharmony_ci{ 132762306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci switch (cmd) { 133062306a36Sopenharmony_ci case SIOCSHWTSTAMP: 133162306a36Sopenharmony_ci return mlxsw_sp_port_hwtstamp_set(mlxsw_sp_port, ifr); 133262306a36Sopenharmony_ci case SIOCGHWTSTAMP: 133362306a36Sopenharmony_ci return mlxsw_sp_port_hwtstamp_get(mlxsw_sp_port, ifr); 133462306a36Sopenharmony_ci default: 133562306a36Sopenharmony_ci return -EOPNOTSUPP; 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci} 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_cistatic const struct net_device_ops mlxsw_sp_port_netdev_ops = { 134062306a36Sopenharmony_ci .ndo_open = mlxsw_sp_port_open, 134162306a36Sopenharmony_ci .ndo_stop = mlxsw_sp_port_stop, 134262306a36Sopenharmony_ci .ndo_start_xmit = mlxsw_sp_port_xmit, 134362306a36Sopenharmony_ci .ndo_setup_tc = mlxsw_sp_setup_tc, 134462306a36Sopenharmony_ci .ndo_set_rx_mode = mlxsw_sp_set_rx_mode, 134562306a36Sopenharmony_ci .ndo_set_mac_address = mlxsw_sp_port_set_mac_address, 134662306a36Sopenharmony_ci .ndo_change_mtu = mlxsw_sp_port_change_mtu, 134762306a36Sopenharmony_ci .ndo_get_stats64 = mlxsw_sp_port_get_stats64, 134862306a36Sopenharmony_ci .ndo_has_offload_stats = mlxsw_sp_port_has_offload_stats, 134962306a36Sopenharmony_ci .ndo_get_offload_stats = mlxsw_sp_port_get_offload_stats, 135062306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = mlxsw_sp_port_add_vid, 135162306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = mlxsw_sp_port_kill_vid, 135262306a36Sopenharmony_ci .ndo_set_features = mlxsw_sp_set_features, 135362306a36Sopenharmony_ci .ndo_eth_ioctl = mlxsw_sp_port_ioctl, 135462306a36Sopenharmony_ci}; 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_cistatic int 135762306a36Sopenharmony_cimlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port) 135862306a36Sopenharmony_ci{ 135962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 136062306a36Sopenharmony_ci u32 eth_proto_cap, eth_proto_admin, eth_proto_oper; 136162306a36Sopenharmony_ci const struct mlxsw_sp_port_type_speed_ops *ops; 136262306a36Sopenharmony_ci char ptys_pl[MLXSW_REG_PTYS_LEN]; 136362306a36Sopenharmony_ci u32 eth_proto_cap_masked; 136462306a36Sopenharmony_ci int err; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci ops = mlxsw_sp->port_type_speed_ops; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci /* Set advertised speeds to speeds supported by both the driver 136962306a36Sopenharmony_ci * and the device. 137062306a36Sopenharmony_ci */ 137162306a36Sopenharmony_ci ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, 137262306a36Sopenharmony_ci 0, false); 137362306a36Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl); 137462306a36Sopenharmony_ci if (err) 137562306a36Sopenharmony_ci return err; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, ð_proto_cap, 137862306a36Sopenharmony_ci ð_proto_admin, ð_proto_oper); 137962306a36Sopenharmony_ci eth_proto_cap_masked = ops->ptys_proto_cap_masked_get(eth_proto_cap); 138062306a36Sopenharmony_ci ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, 138162306a36Sopenharmony_ci eth_proto_cap_masked, 138262306a36Sopenharmony_ci mlxsw_sp_port->link.autoneg); 138362306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl); 138462306a36Sopenharmony_ci} 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ciint mlxsw_sp_port_speed_get(struct mlxsw_sp_port *mlxsw_sp_port, u32 *speed) 138762306a36Sopenharmony_ci{ 138862306a36Sopenharmony_ci const struct mlxsw_sp_port_type_speed_ops *port_type_speed_ops; 138962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 139062306a36Sopenharmony_ci char ptys_pl[MLXSW_REG_PTYS_LEN]; 139162306a36Sopenharmony_ci u32 eth_proto_oper; 139262306a36Sopenharmony_ci int err; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci port_type_speed_ops = mlxsw_sp->port_type_speed_ops; 139562306a36Sopenharmony_ci port_type_speed_ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, 139662306a36Sopenharmony_ci mlxsw_sp_port->local_port, 0, 139762306a36Sopenharmony_ci false); 139862306a36Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl); 139962306a36Sopenharmony_ci if (err) 140062306a36Sopenharmony_ci return err; 140162306a36Sopenharmony_ci port_type_speed_ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, NULL, NULL, 140262306a36Sopenharmony_ci ð_proto_oper); 140362306a36Sopenharmony_ci *speed = port_type_speed_ops->from_ptys_speed(mlxsw_sp, eth_proto_oper); 140462306a36Sopenharmony_ci return 0; 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ciint mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port, 140862306a36Sopenharmony_ci enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index, 140962306a36Sopenharmony_ci bool dwrr, u8 dwrr_weight) 141062306a36Sopenharmony_ci{ 141162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 141262306a36Sopenharmony_ci char qeec_pl[MLXSW_REG_QEEC_LEN]; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index, 141562306a36Sopenharmony_ci next_index); 141662306a36Sopenharmony_ci mlxsw_reg_qeec_de_set(qeec_pl, true); 141762306a36Sopenharmony_ci mlxsw_reg_qeec_dwrr_set(qeec_pl, dwrr); 141862306a36Sopenharmony_ci mlxsw_reg_qeec_dwrr_weight_set(qeec_pl, dwrr_weight); 141962306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl); 142062306a36Sopenharmony_ci} 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ciint mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port, 142362306a36Sopenharmony_ci enum mlxsw_reg_qeec_hr hr, u8 index, 142462306a36Sopenharmony_ci u8 next_index, u32 maxrate, u8 burst_size) 142562306a36Sopenharmony_ci{ 142662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 142762306a36Sopenharmony_ci char qeec_pl[MLXSW_REG_QEEC_LEN]; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index, 143062306a36Sopenharmony_ci next_index); 143162306a36Sopenharmony_ci mlxsw_reg_qeec_mase_set(qeec_pl, true); 143262306a36Sopenharmony_ci mlxsw_reg_qeec_max_shaper_rate_set(qeec_pl, maxrate); 143362306a36Sopenharmony_ci mlxsw_reg_qeec_max_shaper_bs_set(qeec_pl, burst_size); 143462306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl); 143562306a36Sopenharmony_ci} 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_cistatic int mlxsw_sp_port_min_bw_set(struct mlxsw_sp_port *mlxsw_sp_port, 143862306a36Sopenharmony_ci enum mlxsw_reg_qeec_hr hr, u8 index, 143962306a36Sopenharmony_ci u8 next_index, u32 minrate) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 144262306a36Sopenharmony_ci char qeec_pl[MLXSW_REG_QEEC_LEN]; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index, 144562306a36Sopenharmony_ci next_index); 144662306a36Sopenharmony_ci mlxsw_reg_qeec_mise_set(qeec_pl, true); 144762306a36Sopenharmony_ci mlxsw_reg_qeec_min_shaper_rate_set(qeec_pl, minrate); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl); 145062306a36Sopenharmony_ci} 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ciint mlxsw_sp_port_prio_tc_set(struct mlxsw_sp_port *mlxsw_sp_port, 145362306a36Sopenharmony_ci u8 switch_prio, u8 tclass) 145462306a36Sopenharmony_ci{ 145562306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 145662306a36Sopenharmony_ci char qtct_pl[MLXSW_REG_QTCT_LEN]; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci mlxsw_reg_qtct_pack(qtct_pl, mlxsw_sp_port->local_port, switch_prio, 145962306a36Sopenharmony_ci tclass); 146062306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qtct), qtct_pl); 146162306a36Sopenharmony_ci} 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_cistatic int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port) 146462306a36Sopenharmony_ci{ 146562306a36Sopenharmony_ci int err, i; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci /* Setup the elements hierarcy, so that each TC is linked to 146862306a36Sopenharmony_ci * one subgroup, which are all member in the same group. 146962306a36Sopenharmony_ci */ 147062306a36Sopenharmony_ci err = mlxsw_sp_port_ets_set(mlxsw_sp_port, 147162306a36Sopenharmony_ci MLXSW_REG_QEEC_HR_GROUP, 0, 0, false, 0); 147262306a36Sopenharmony_ci if (err) 147362306a36Sopenharmony_ci return err; 147462306a36Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 147562306a36Sopenharmony_ci err = mlxsw_sp_port_ets_set(mlxsw_sp_port, 147662306a36Sopenharmony_ci MLXSW_REG_QEEC_HR_SUBGROUP, i, 147762306a36Sopenharmony_ci 0, false, 0); 147862306a36Sopenharmony_ci if (err) 147962306a36Sopenharmony_ci return err; 148062306a36Sopenharmony_ci } 148162306a36Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 148262306a36Sopenharmony_ci err = mlxsw_sp_port_ets_set(mlxsw_sp_port, 148362306a36Sopenharmony_ci MLXSW_REG_QEEC_HR_TC, i, i, 148462306a36Sopenharmony_ci false, 0); 148562306a36Sopenharmony_ci if (err) 148662306a36Sopenharmony_ci return err; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci err = mlxsw_sp_port_ets_set(mlxsw_sp_port, 148962306a36Sopenharmony_ci MLXSW_REG_QEEC_HR_TC, 149062306a36Sopenharmony_ci i + 8, i, 149162306a36Sopenharmony_ci true, 100); 149262306a36Sopenharmony_ci if (err) 149362306a36Sopenharmony_ci return err; 149462306a36Sopenharmony_ci } 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci /* Make sure the max shaper is disabled in all hierarchies that support 149762306a36Sopenharmony_ci * it. Note that this disables ptps (PTP shaper), but that is intended 149862306a36Sopenharmony_ci * for the initial configuration. 149962306a36Sopenharmony_ci */ 150062306a36Sopenharmony_ci err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, 150162306a36Sopenharmony_ci MLXSW_REG_QEEC_HR_PORT, 0, 0, 150262306a36Sopenharmony_ci MLXSW_REG_QEEC_MAS_DIS, 0); 150362306a36Sopenharmony_ci if (err) 150462306a36Sopenharmony_ci return err; 150562306a36Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 150662306a36Sopenharmony_ci err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, 150762306a36Sopenharmony_ci MLXSW_REG_QEEC_HR_SUBGROUP, 150862306a36Sopenharmony_ci i, 0, 150962306a36Sopenharmony_ci MLXSW_REG_QEEC_MAS_DIS, 0); 151062306a36Sopenharmony_ci if (err) 151162306a36Sopenharmony_ci return err; 151262306a36Sopenharmony_ci } 151362306a36Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 151462306a36Sopenharmony_ci err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, 151562306a36Sopenharmony_ci MLXSW_REG_QEEC_HR_TC, 151662306a36Sopenharmony_ci i, i, 151762306a36Sopenharmony_ci MLXSW_REG_QEEC_MAS_DIS, 0); 151862306a36Sopenharmony_ci if (err) 151962306a36Sopenharmony_ci return err; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port, 152262306a36Sopenharmony_ci MLXSW_REG_QEEC_HR_TC, 152362306a36Sopenharmony_ci i + 8, i, 152462306a36Sopenharmony_ci MLXSW_REG_QEEC_MAS_DIS, 0); 152562306a36Sopenharmony_ci if (err) 152662306a36Sopenharmony_ci return err; 152762306a36Sopenharmony_ci } 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci /* Configure the min shaper for multicast TCs. */ 153062306a36Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 153162306a36Sopenharmony_ci err = mlxsw_sp_port_min_bw_set(mlxsw_sp_port, 153262306a36Sopenharmony_ci MLXSW_REG_QEEC_HR_TC, 153362306a36Sopenharmony_ci i + 8, i, 153462306a36Sopenharmony_ci MLXSW_REG_QEEC_MIS_MIN); 153562306a36Sopenharmony_ci if (err) 153662306a36Sopenharmony_ci return err; 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci /* Map all priorities to traffic class 0. */ 154062306a36Sopenharmony_ci for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 154162306a36Sopenharmony_ci err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, 0); 154262306a36Sopenharmony_ci if (err) 154362306a36Sopenharmony_ci return err; 154462306a36Sopenharmony_ci } 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci return 0; 154762306a36Sopenharmony_ci} 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_cistatic int mlxsw_sp_port_tc_mc_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, 155062306a36Sopenharmony_ci bool enable) 155162306a36Sopenharmony_ci{ 155262306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 155362306a36Sopenharmony_ci char qtctm_pl[MLXSW_REG_QTCTM_LEN]; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci mlxsw_reg_qtctm_pack(qtctm_pl, mlxsw_sp_port->local_port, enable); 155662306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qtctm), qtctm_pl); 155762306a36Sopenharmony_ci} 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_cistatic int mlxsw_sp_port_overheat_init_val_set(struct mlxsw_sp_port *mlxsw_sp_port) 156062306a36Sopenharmony_ci{ 156162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 156262306a36Sopenharmony_ci u8 slot_index = mlxsw_sp_port->mapping.slot_index; 156362306a36Sopenharmony_ci u8 module = mlxsw_sp_port->mapping.module; 156462306a36Sopenharmony_ci u64 overheat_counter; 156562306a36Sopenharmony_ci int err; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci err = mlxsw_env_module_overheat_counter_get(mlxsw_sp->core, slot_index, 156862306a36Sopenharmony_ci module, &overheat_counter); 156962306a36Sopenharmony_ci if (err) 157062306a36Sopenharmony_ci return err; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci mlxsw_sp_port->module_overheat_initial_val = overheat_counter; 157362306a36Sopenharmony_ci return 0; 157462306a36Sopenharmony_ci} 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ciint 157762306a36Sopenharmony_cimlxsw_sp_port_vlan_classification_set(struct mlxsw_sp_port *mlxsw_sp_port, 157862306a36Sopenharmony_ci bool is_8021ad_tagged, 157962306a36Sopenharmony_ci bool is_8021q_tagged) 158062306a36Sopenharmony_ci{ 158162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 158262306a36Sopenharmony_ci char spvc_pl[MLXSW_REG_SPVC_LEN]; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci mlxsw_reg_spvc_pack(spvc_pl, mlxsw_sp_port->local_port, 158562306a36Sopenharmony_ci is_8021ad_tagged, is_8021q_tagged); 158662306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvc), spvc_pl); 158762306a36Sopenharmony_ci} 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_cistatic int mlxsw_sp_port_label_info_get(struct mlxsw_sp *mlxsw_sp, 159062306a36Sopenharmony_ci u16 local_port, u8 *port_number, 159162306a36Sopenharmony_ci u8 *split_port_subnumber, 159262306a36Sopenharmony_ci u8 *slot_index) 159362306a36Sopenharmony_ci{ 159462306a36Sopenharmony_ci char pllp_pl[MLXSW_REG_PLLP_LEN]; 159562306a36Sopenharmony_ci int err; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci mlxsw_reg_pllp_pack(pllp_pl, local_port); 159862306a36Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pllp), pllp_pl); 159962306a36Sopenharmony_ci if (err) 160062306a36Sopenharmony_ci return err; 160162306a36Sopenharmony_ci mlxsw_reg_pllp_unpack(pllp_pl, port_number, 160262306a36Sopenharmony_ci split_port_subnumber, slot_index); 160362306a36Sopenharmony_ci return 0; 160462306a36Sopenharmony_ci} 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_cistatic int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u16 local_port, 160762306a36Sopenharmony_ci bool split, 160862306a36Sopenharmony_ci struct mlxsw_sp_port_mapping *port_mapping) 160962306a36Sopenharmony_ci{ 161062306a36Sopenharmony_ci struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 161162306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 161262306a36Sopenharmony_ci u32 lanes = port_mapping->width; 161362306a36Sopenharmony_ci u8 split_port_subnumber; 161462306a36Sopenharmony_ci struct net_device *dev; 161562306a36Sopenharmony_ci u8 port_number; 161662306a36Sopenharmony_ci u8 slot_index; 161762306a36Sopenharmony_ci bool splittable; 161862306a36Sopenharmony_ci int err; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci err = mlxsw_sp_port_module_map(mlxsw_sp, local_port, port_mapping); 162162306a36Sopenharmony_ci if (err) { 162262306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to map module\n", 162362306a36Sopenharmony_ci local_port); 162462306a36Sopenharmony_ci return err; 162562306a36Sopenharmony_ci } 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci err = mlxsw_sp_port_swid_set(mlxsw_sp, local_port, 0); 162862306a36Sopenharmony_ci if (err) { 162962306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set SWID\n", 163062306a36Sopenharmony_ci local_port); 163162306a36Sopenharmony_ci goto err_port_swid_set; 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci err = mlxsw_sp_port_label_info_get(mlxsw_sp, local_port, &port_number, 163562306a36Sopenharmony_ci &split_port_subnumber, &slot_index); 163662306a36Sopenharmony_ci if (err) { 163762306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get port label information\n", 163862306a36Sopenharmony_ci local_port); 163962306a36Sopenharmony_ci goto err_port_label_info_get; 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci splittable = lanes > 1 && !split; 164362306a36Sopenharmony_ci err = mlxsw_core_port_init(mlxsw_sp->core, local_port, slot_index, 164462306a36Sopenharmony_ci port_number, split, split_port_subnumber, 164562306a36Sopenharmony_ci splittable, lanes, mlxsw_sp->base_mac, 164662306a36Sopenharmony_ci sizeof(mlxsw_sp->base_mac)); 164762306a36Sopenharmony_ci if (err) { 164862306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to init core port\n", 164962306a36Sopenharmony_ci local_port); 165062306a36Sopenharmony_ci goto err_core_port_init; 165162306a36Sopenharmony_ci } 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci dev = alloc_etherdev(sizeof(struct mlxsw_sp_port)); 165462306a36Sopenharmony_ci if (!dev) { 165562306a36Sopenharmony_ci err = -ENOMEM; 165662306a36Sopenharmony_ci goto err_alloc_etherdev; 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci SET_NETDEV_DEV(dev, mlxsw_sp->bus_info->dev); 165962306a36Sopenharmony_ci dev_net_set(dev, mlxsw_sp_net(mlxsw_sp)); 166062306a36Sopenharmony_ci mlxsw_sp_port = netdev_priv(dev); 166162306a36Sopenharmony_ci mlxsw_core_port_netdev_link(mlxsw_sp->core, local_port, 166262306a36Sopenharmony_ci mlxsw_sp_port, dev); 166362306a36Sopenharmony_ci mlxsw_sp_port->dev = dev; 166462306a36Sopenharmony_ci mlxsw_sp_port->mlxsw_sp = mlxsw_sp; 166562306a36Sopenharmony_ci mlxsw_sp_port->local_port = local_port; 166662306a36Sopenharmony_ci mlxsw_sp_port->pvid = MLXSW_SP_DEFAULT_VID; 166762306a36Sopenharmony_ci mlxsw_sp_port->split = split; 166862306a36Sopenharmony_ci mlxsw_sp_port->mapping = *port_mapping; 166962306a36Sopenharmony_ci mlxsw_sp_port->link.autoneg = 1; 167062306a36Sopenharmony_ci INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list); 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci mlxsw_sp_port->pcpu_stats = 167362306a36Sopenharmony_ci netdev_alloc_pcpu_stats(struct mlxsw_sp_port_pcpu_stats); 167462306a36Sopenharmony_ci if (!mlxsw_sp_port->pcpu_stats) { 167562306a36Sopenharmony_ci err = -ENOMEM; 167662306a36Sopenharmony_ci goto err_alloc_stats; 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci INIT_DELAYED_WORK(&mlxsw_sp_port->periodic_hw_stats.update_dw, 168062306a36Sopenharmony_ci &update_stats_cache); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci dev->netdev_ops = &mlxsw_sp_port_netdev_ops; 168362306a36Sopenharmony_ci dev->ethtool_ops = &mlxsw_sp_port_ethtool_ops; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci err = mlxsw_sp_port_dev_addr_init(mlxsw_sp_port); 168662306a36Sopenharmony_ci if (err) { 168762306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unable to init port mac address\n", 168862306a36Sopenharmony_ci mlxsw_sp_port->local_port); 168962306a36Sopenharmony_ci goto err_dev_addr_init; 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci netif_carrier_off(dev); 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_LLTX | NETIF_F_SG | 169562306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC; 169662306a36Sopenharmony_ci dev->hw_features |= NETIF_F_HW_TC | NETIF_F_LOOPBACK; 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci dev->min_mtu = 0; 169962306a36Sopenharmony_ci dev->max_mtu = ETH_MAX_MTU; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci /* Each packet needs to have a Tx header (metadata) on top all other 170262306a36Sopenharmony_ci * headers. 170362306a36Sopenharmony_ci */ 170462306a36Sopenharmony_ci dev->needed_headroom = MLXSW_TXHDR_LEN; 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci err = mlxsw_sp_port_system_port_mapping_set(mlxsw_sp_port); 170762306a36Sopenharmony_ci if (err) { 170862306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set system port mapping\n", 170962306a36Sopenharmony_ci mlxsw_sp_port->local_port); 171062306a36Sopenharmony_ci goto err_port_system_port_mapping_set; 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci err = mlxsw_sp_port_speed_by_width_set(mlxsw_sp_port); 171462306a36Sopenharmony_ci if (err) { 171562306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to enable speeds\n", 171662306a36Sopenharmony_ci mlxsw_sp_port->local_port); 171762306a36Sopenharmony_ci goto err_port_speed_by_width_set; 171862306a36Sopenharmony_ci } 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci err = mlxsw_sp->port_type_speed_ops->ptys_max_speed(mlxsw_sp_port, 172162306a36Sopenharmony_ci &mlxsw_sp_port->max_speed); 172262306a36Sopenharmony_ci if (err) { 172362306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get maximum speed\n", 172462306a36Sopenharmony_ci mlxsw_sp_port->local_port); 172562306a36Sopenharmony_ci goto err_max_speed_get; 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci err = mlxsw_sp_port_max_mtu_get(mlxsw_sp_port, &mlxsw_sp_port->max_mtu); 172962306a36Sopenharmony_ci if (err) { 173062306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get maximum MTU\n", 173162306a36Sopenharmony_ci mlxsw_sp_port->local_port); 173262306a36Sopenharmony_ci goto err_port_max_mtu_get; 173362306a36Sopenharmony_ci } 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, ETH_DATA_LEN); 173662306a36Sopenharmony_ci if (err) { 173762306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set MTU\n", 173862306a36Sopenharmony_ci mlxsw_sp_port->local_port); 173962306a36Sopenharmony_ci goto err_port_mtu_set; 174062306a36Sopenharmony_ci } 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false); 174362306a36Sopenharmony_ci if (err) 174462306a36Sopenharmony_ci goto err_port_admin_status_set; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci err = mlxsw_sp_port_buffers_init(mlxsw_sp_port); 174762306a36Sopenharmony_ci if (err) { 174862306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize buffers\n", 174962306a36Sopenharmony_ci mlxsw_sp_port->local_port); 175062306a36Sopenharmony_ci goto err_port_buffers_init; 175162306a36Sopenharmony_ci } 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci err = mlxsw_sp_port_ets_init(mlxsw_sp_port); 175462306a36Sopenharmony_ci if (err) { 175562306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize ETS\n", 175662306a36Sopenharmony_ci mlxsw_sp_port->local_port); 175762306a36Sopenharmony_ci goto err_port_ets_init; 175862306a36Sopenharmony_ci } 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci err = mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, true); 176162306a36Sopenharmony_ci if (err) { 176262306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize TC MC mode\n", 176362306a36Sopenharmony_ci mlxsw_sp_port->local_port); 176462306a36Sopenharmony_ci goto err_port_tc_mc_mode; 176562306a36Sopenharmony_ci } 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci /* ETS and buffers must be initialized before DCB. */ 176862306a36Sopenharmony_ci err = mlxsw_sp_port_dcb_init(mlxsw_sp_port); 176962306a36Sopenharmony_ci if (err) { 177062306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize DCB\n", 177162306a36Sopenharmony_ci mlxsw_sp_port->local_port); 177262306a36Sopenharmony_ci goto err_port_dcb_init; 177362306a36Sopenharmony_ci } 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci err = mlxsw_sp_port_fids_init(mlxsw_sp_port); 177662306a36Sopenharmony_ci if (err) { 177762306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize FIDs\n", 177862306a36Sopenharmony_ci mlxsw_sp_port->local_port); 177962306a36Sopenharmony_ci goto err_port_fids_init; 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci err = mlxsw_sp_tc_qdisc_init(mlxsw_sp_port); 178362306a36Sopenharmony_ci if (err) { 178462306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize TC qdiscs\n", 178562306a36Sopenharmony_ci mlxsw_sp_port->local_port); 178662306a36Sopenharmony_ci goto err_port_qdiscs_init; 178762306a36Sopenharmony_ci } 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 0, VLAN_N_VID - 1, false, 179062306a36Sopenharmony_ci false); 179162306a36Sopenharmony_ci if (err) { 179262306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to clear VLAN filter\n", 179362306a36Sopenharmony_ci mlxsw_sp_port->local_port); 179462306a36Sopenharmony_ci goto err_port_vlan_clear; 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci err = mlxsw_sp_port_nve_init(mlxsw_sp_port); 179862306a36Sopenharmony_ci if (err) { 179962306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize NVE\n", 180062306a36Sopenharmony_ci mlxsw_sp_port->local_port); 180162306a36Sopenharmony_ci goto err_port_nve_init; 180262306a36Sopenharmony_ci } 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID, 180562306a36Sopenharmony_ci ETH_P_8021Q); 180662306a36Sopenharmony_ci if (err) { 180762306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set PVID\n", 180862306a36Sopenharmony_ci mlxsw_sp_port->local_port); 180962306a36Sopenharmony_ci goto err_port_pvid_set; 181062306a36Sopenharmony_ci } 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_create(mlxsw_sp_port, 181362306a36Sopenharmony_ci MLXSW_SP_DEFAULT_VID); 181462306a36Sopenharmony_ci if (IS_ERR(mlxsw_sp_port_vlan)) { 181562306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n", 181662306a36Sopenharmony_ci mlxsw_sp_port->local_port); 181762306a36Sopenharmony_ci err = PTR_ERR(mlxsw_sp_port_vlan); 181862306a36Sopenharmony_ci goto err_port_vlan_create; 181962306a36Sopenharmony_ci } 182062306a36Sopenharmony_ci mlxsw_sp_port->default_vlan = mlxsw_sp_port_vlan; 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci /* Set SPVC.et0=true and SPVC.et1=false to make the local port to treat 182362306a36Sopenharmony_ci * only packets with 802.1q header as tagged packets. 182462306a36Sopenharmony_ci */ 182562306a36Sopenharmony_ci err = mlxsw_sp_port_vlan_classification_set(mlxsw_sp_port, false, true); 182662306a36Sopenharmony_ci if (err) { 182762306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set default VLAN classification\n", 182862306a36Sopenharmony_ci local_port); 182962306a36Sopenharmony_ci goto err_port_vlan_classification_set; 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci INIT_DELAYED_WORK(&mlxsw_sp_port->ptp.shaper_dw, 183362306a36Sopenharmony_ci mlxsw_sp->ptp_ops->shaper_work); 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci mlxsw_sp->ports[local_port] = mlxsw_sp_port; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci err = mlxsw_sp_port_overheat_init_val_set(mlxsw_sp_port); 183862306a36Sopenharmony_ci if (err) { 183962306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set overheat initial value\n", 184062306a36Sopenharmony_ci mlxsw_sp_port->local_port); 184162306a36Sopenharmony_ci goto err_port_overheat_init_val_set; 184262306a36Sopenharmony_ci } 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci err = register_netdev(dev); 184562306a36Sopenharmony_ci if (err) { 184662306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to register netdev\n", 184762306a36Sopenharmony_ci mlxsw_sp_port->local_port); 184862306a36Sopenharmony_ci goto err_register_netdev; 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci mlxsw_core_schedule_dw(&mlxsw_sp_port->periodic_hw_stats.update_dw, 0); 185262306a36Sopenharmony_ci return 0; 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_cierr_register_netdev: 185562306a36Sopenharmony_cierr_port_overheat_init_val_set: 185662306a36Sopenharmony_ci mlxsw_sp_port_vlan_classification_set(mlxsw_sp_port, true, true); 185762306a36Sopenharmony_cierr_port_vlan_classification_set: 185862306a36Sopenharmony_ci mlxsw_sp->ports[local_port] = NULL; 185962306a36Sopenharmony_ci mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); 186062306a36Sopenharmony_cierr_port_vlan_create: 186162306a36Sopenharmony_cierr_port_pvid_set: 186262306a36Sopenharmony_ci mlxsw_sp_port_nve_fini(mlxsw_sp_port); 186362306a36Sopenharmony_cierr_port_nve_init: 186462306a36Sopenharmony_cierr_port_vlan_clear: 186562306a36Sopenharmony_ci mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port); 186662306a36Sopenharmony_cierr_port_qdiscs_init: 186762306a36Sopenharmony_ci mlxsw_sp_port_fids_fini(mlxsw_sp_port); 186862306a36Sopenharmony_cierr_port_fids_init: 186962306a36Sopenharmony_ci mlxsw_sp_port_dcb_fini(mlxsw_sp_port); 187062306a36Sopenharmony_cierr_port_dcb_init: 187162306a36Sopenharmony_ci mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false); 187262306a36Sopenharmony_cierr_port_tc_mc_mode: 187362306a36Sopenharmony_cierr_port_ets_init: 187462306a36Sopenharmony_ci mlxsw_sp_port_buffers_fini(mlxsw_sp_port); 187562306a36Sopenharmony_cierr_port_buffers_init: 187662306a36Sopenharmony_cierr_port_admin_status_set: 187762306a36Sopenharmony_cierr_port_mtu_set: 187862306a36Sopenharmony_cierr_port_max_mtu_get: 187962306a36Sopenharmony_cierr_max_speed_get: 188062306a36Sopenharmony_cierr_port_speed_by_width_set: 188162306a36Sopenharmony_cierr_port_system_port_mapping_set: 188262306a36Sopenharmony_cierr_dev_addr_init: 188362306a36Sopenharmony_ci free_percpu(mlxsw_sp_port->pcpu_stats); 188462306a36Sopenharmony_cierr_alloc_stats: 188562306a36Sopenharmony_ci free_netdev(dev); 188662306a36Sopenharmony_cierr_alloc_etherdev: 188762306a36Sopenharmony_ci mlxsw_core_port_fini(mlxsw_sp->core, local_port); 188862306a36Sopenharmony_cierr_core_port_init: 188962306a36Sopenharmony_cierr_port_label_info_get: 189062306a36Sopenharmony_ci mlxsw_sp_port_swid_set(mlxsw_sp, local_port, 189162306a36Sopenharmony_ci MLXSW_PORT_SWID_DISABLED_PORT); 189262306a36Sopenharmony_cierr_port_swid_set: 189362306a36Sopenharmony_ci mlxsw_sp_port_module_unmap(mlxsw_sp, local_port, 189462306a36Sopenharmony_ci port_mapping->slot_index, 189562306a36Sopenharmony_ci port_mapping->module); 189662306a36Sopenharmony_ci return err; 189762306a36Sopenharmony_ci} 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_cistatic void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u16 local_port) 190062306a36Sopenharmony_ci{ 190162306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port]; 190262306a36Sopenharmony_ci u8 slot_index = mlxsw_sp_port->mapping.slot_index; 190362306a36Sopenharmony_ci u8 module = mlxsw_sp_port->mapping.module; 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci cancel_delayed_work_sync(&mlxsw_sp_port->periodic_hw_stats.update_dw); 190662306a36Sopenharmony_ci cancel_delayed_work_sync(&mlxsw_sp_port->ptp.shaper_dw); 190762306a36Sopenharmony_ci unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */ 190862306a36Sopenharmony_ci mlxsw_sp_port_ptp_clear(mlxsw_sp_port); 190962306a36Sopenharmony_ci mlxsw_sp_port_vlan_classification_set(mlxsw_sp_port, true, true); 191062306a36Sopenharmony_ci mlxsw_sp->ports[local_port] = NULL; 191162306a36Sopenharmony_ci mlxsw_sp_port_vlan_flush(mlxsw_sp_port, true); 191262306a36Sopenharmony_ci mlxsw_sp_port_nve_fini(mlxsw_sp_port); 191362306a36Sopenharmony_ci mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port); 191462306a36Sopenharmony_ci mlxsw_sp_port_fids_fini(mlxsw_sp_port); 191562306a36Sopenharmony_ci mlxsw_sp_port_dcb_fini(mlxsw_sp_port); 191662306a36Sopenharmony_ci mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false); 191762306a36Sopenharmony_ci mlxsw_sp_port_buffers_fini(mlxsw_sp_port); 191862306a36Sopenharmony_ci free_percpu(mlxsw_sp_port->pcpu_stats); 191962306a36Sopenharmony_ci WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vlans_list)); 192062306a36Sopenharmony_ci free_netdev(mlxsw_sp_port->dev); 192162306a36Sopenharmony_ci mlxsw_core_port_fini(mlxsw_sp->core, local_port); 192262306a36Sopenharmony_ci mlxsw_sp_port_swid_set(mlxsw_sp, local_port, 192362306a36Sopenharmony_ci MLXSW_PORT_SWID_DISABLED_PORT); 192462306a36Sopenharmony_ci mlxsw_sp_port_module_unmap(mlxsw_sp, local_port, slot_index, module); 192562306a36Sopenharmony_ci} 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_cistatic int mlxsw_sp_cpu_port_create(struct mlxsw_sp *mlxsw_sp) 192862306a36Sopenharmony_ci{ 192962306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 193062306a36Sopenharmony_ci int err; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci mlxsw_sp_port = kzalloc(sizeof(*mlxsw_sp_port), GFP_KERNEL); 193362306a36Sopenharmony_ci if (!mlxsw_sp_port) 193462306a36Sopenharmony_ci return -ENOMEM; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci mlxsw_sp_port->mlxsw_sp = mlxsw_sp; 193762306a36Sopenharmony_ci mlxsw_sp_port->local_port = MLXSW_PORT_CPU_PORT; 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci err = mlxsw_core_cpu_port_init(mlxsw_sp->core, 194062306a36Sopenharmony_ci mlxsw_sp_port, 194162306a36Sopenharmony_ci mlxsw_sp->base_mac, 194262306a36Sopenharmony_ci sizeof(mlxsw_sp->base_mac)); 194362306a36Sopenharmony_ci if (err) { 194462306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize core CPU port\n"); 194562306a36Sopenharmony_ci goto err_core_cpu_port_init; 194662306a36Sopenharmony_ci } 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = mlxsw_sp_port; 194962306a36Sopenharmony_ci return 0; 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_cierr_core_cpu_port_init: 195262306a36Sopenharmony_ci kfree(mlxsw_sp_port); 195362306a36Sopenharmony_ci return err; 195462306a36Sopenharmony_ci} 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_cistatic void mlxsw_sp_cpu_port_remove(struct mlxsw_sp *mlxsw_sp) 195762306a36Sopenharmony_ci{ 195862306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = 195962306a36Sopenharmony_ci mlxsw_sp->ports[MLXSW_PORT_CPU_PORT]; 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci mlxsw_core_cpu_port_fini(mlxsw_sp->core); 196262306a36Sopenharmony_ci mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = NULL; 196362306a36Sopenharmony_ci kfree(mlxsw_sp_port); 196462306a36Sopenharmony_ci} 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_cistatic bool mlxsw_sp_local_port_valid(u16 local_port) 196762306a36Sopenharmony_ci{ 196862306a36Sopenharmony_ci return local_port != MLXSW_PORT_CPU_PORT; 196962306a36Sopenharmony_ci} 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_cistatic bool mlxsw_sp_port_created(struct mlxsw_sp *mlxsw_sp, u16 local_port) 197262306a36Sopenharmony_ci{ 197362306a36Sopenharmony_ci if (!mlxsw_sp_local_port_valid(local_port)) 197462306a36Sopenharmony_ci return false; 197562306a36Sopenharmony_ci return mlxsw_sp->ports[local_port] != NULL; 197662306a36Sopenharmony_ci} 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_cistatic int mlxsw_sp_port_mapping_event_set(struct mlxsw_sp *mlxsw_sp, 197962306a36Sopenharmony_ci u16 local_port, bool enable) 198062306a36Sopenharmony_ci{ 198162306a36Sopenharmony_ci char pmecr_pl[MLXSW_REG_PMECR_LEN]; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci mlxsw_reg_pmecr_pack(pmecr_pl, local_port, 198462306a36Sopenharmony_ci enable ? MLXSW_REG_PMECR_E_GENERATE_EVENT : 198562306a36Sopenharmony_ci MLXSW_REG_PMECR_E_DO_NOT_GENERATE_EVENT); 198662306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmecr), pmecr_pl); 198762306a36Sopenharmony_ci} 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_cistruct mlxsw_sp_port_mapping_event { 199062306a36Sopenharmony_ci struct list_head list; 199162306a36Sopenharmony_ci char pmlp_pl[MLXSW_REG_PMLP_LEN]; 199262306a36Sopenharmony_ci}; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_cistatic void mlxsw_sp_port_mapping_events_work(struct work_struct *work) 199562306a36Sopenharmony_ci{ 199662306a36Sopenharmony_ci struct mlxsw_sp_port_mapping_event *event, *next_event; 199762306a36Sopenharmony_ci struct mlxsw_sp_port_mapping_events *events; 199862306a36Sopenharmony_ci struct mlxsw_sp_port_mapping port_mapping; 199962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp; 200062306a36Sopenharmony_ci struct devlink *devlink; 200162306a36Sopenharmony_ci LIST_HEAD(event_queue); 200262306a36Sopenharmony_ci u16 local_port; 200362306a36Sopenharmony_ci int err; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci events = container_of(work, struct mlxsw_sp_port_mapping_events, work); 200662306a36Sopenharmony_ci mlxsw_sp = container_of(events, struct mlxsw_sp, port_mapping_events); 200762306a36Sopenharmony_ci devlink = priv_to_devlink(mlxsw_sp->core); 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci spin_lock_bh(&events->queue_lock); 201062306a36Sopenharmony_ci list_splice_init(&events->queue, &event_queue); 201162306a36Sopenharmony_ci spin_unlock_bh(&events->queue_lock); 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci list_for_each_entry_safe(event, next_event, &event_queue, list) { 201462306a36Sopenharmony_ci local_port = mlxsw_reg_pmlp_local_port_get(event->pmlp_pl); 201562306a36Sopenharmony_ci err = mlxsw_sp_port_module_info_parse(mlxsw_sp, local_port, 201662306a36Sopenharmony_ci event->pmlp_pl, &port_mapping); 201762306a36Sopenharmony_ci if (err) 201862306a36Sopenharmony_ci goto out; 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci if (WARN_ON_ONCE(!port_mapping.width)) 202162306a36Sopenharmony_ci goto out; 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci devl_lock(devlink); 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci if (!mlxsw_sp_port_created(mlxsw_sp, local_port)) 202662306a36Sopenharmony_ci mlxsw_sp_port_create(mlxsw_sp, local_port, 202762306a36Sopenharmony_ci false, &port_mapping); 202862306a36Sopenharmony_ci else 202962306a36Sopenharmony_ci WARN_ON_ONCE(1); 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci devl_unlock(devlink); 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci mlxsw_sp->port_mapping[local_port] = port_mapping; 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ciout: 203662306a36Sopenharmony_ci kfree(event); 203762306a36Sopenharmony_ci } 203862306a36Sopenharmony_ci} 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_cistatic void 204162306a36Sopenharmony_cimlxsw_sp_port_mapping_listener_func(const struct mlxsw_reg_info *reg, 204262306a36Sopenharmony_ci char *pmlp_pl, void *priv) 204362306a36Sopenharmony_ci{ 204462306a36Sopenharmony_ci struct mlxsw_sp_port_mapping_events *events; 204562306a36Sopenharmony_ci struct mlxsw_sp_port_mapping_event *event; 204662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 204762306a36Sopenharmony_ci u16 local_port; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci local_port = mlxsw_reg_pmlp_local_port_get(pmlp_pl); 205062306a36Sopenharmony_ci if (WARN_ON_ONCE(!mlxsw_sp_local_port_is_valid(mlxsw_sp, local_port))) 205162306a36Sopenharmony_ci return; 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci events = &mlxsw_sp->port_mapping_events; 205462306a36Sopenharmony_ci event = kmalloc(sizeof(*event), GFP_ATOMIC); 205562306a36Sopenharmony_ci if (!event) 205662306a36Sopenharmony_ci return; 205762306a36Sopenharmony_ci memcpy(event->pmlp_pl, pmlp_pl, sizeof(event->pmlp_pl)); 205862306a36Sopenharmony_ci spin_lock(&events->queue_lock); 205962306a36Sopenharmony_ci list_add_tail(&event->list, &events->queue); 206062306a36Sopenharmony_ci spin_unlock(&events->queue_lock); 206162306a36Sopenharmony_ci mlxsw_core_schedule_work(&events->work); 206262306a36Sopenharmony_ci} 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_cistatic void 206562306a36Sopenharmony_ci__mlxsw_sp_port_mapping_events_cancel(struct mlxsw_sp *mlxsw_sp) 206662306a36Sopenharmony_ci{ 206762306a36Sopenharmony_ci struct mlxsw_sp_port_mapping_event *event, *next_event; 206862306a36Sopenharmony_ci struct mlxsw_sp_port_mapping_events *events; 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci events = &mlxsw_sp->port_mapping_events; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci /* Caller needs to make sure that no new event is going to appear. */ 207362306a36Sopenharmony_ci cancel_work_sync(&events->work); 207462306a36Sopenharmony_ci list_for_each_entry_safe(event, next_event, &events->queue, list) { 207562306a36Sopenharmony_ci list_del(&event->list); 207662306a36Sopenharmony_ci kfree(event); 207762306a36Sopenharmony_ci } 207862306a36Sopenharmony_ci} 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_cistatic void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp) 208162306a36Sopenharmony_ci{ 208262306a36Sopenharmony_ci unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); 208362306a36Sopenharmony_ci int i; 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci for (i = 1; i < max_ports; i++) 208662306a36Sopenharmony_ci mlxsw_sp_port_mapping_event_set(mlxsw_sp, i, false); 208762306a36Sopenharmony_ci /* Make sure all scheduled events are processed */ 208862306a36Sopenharmony_ci __mlxsw_sp_port_mapping_events_cancel(mlxsw_sp); 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci for (i = 1; i < max_ports; i++) 209162306a36Sopenharmony_ci if (mlxsw_sp_port_created(mlxsw_sp, i)) 209262306a36Sopenharmony_ci mlxsw_sp_port_remove(mlxsw_sp, i); 209362306a36Sopenharmony_ci mlxsw_sp_cpu_port_remove(mlxsw_sp); 209462306a36Sopenharmony_ci kfree(mlxsw_sp->ports); 209562306a36Sopenharmony_ci mlxsw_sp->ports = NULL; 209662306a36Sopenharmony_ci} 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_cistatic void 209962306a36Sopenharmony_cimlxsw_sp_ports_remove_selected(struct mlxsw_core *mlxsw_core, 210062306a36Sopenharmony_ci bool (*selector)(void *priv, u16 local_port), 210162306a36Sopenharmony_ci void *priv) 210262306a36Sopenharmony_ci{ 210362306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 210462306a36Sopenharmony_ci unsigned int max_ports = mlxsw_core_max_ports(mlxsw_core); 210562306a36Sopenharmony_ci int i; 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci for (i = 1; i < max_ports; i++) 210862306a36Sopenharmony_ci if (mlxsw_sp_port_created(mlxsw_sp, i) && selector(priv, i)) 210962306a36Sopenharmony_ci mlxsw_sp_port_remove(mlxsw_sp, i); 211062306a36Sopenharmony_ci} 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_cistatic int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp) 211362306a36Sopenharmony_ci{ 211462306a36Sopenharmony_ci unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); 211562306a36Sopenharmony_ci struct mlxsw_sp_port_mapping_events *events; 211662306a36Sopenharmony_ci struct mlxsw_sp_port_mapping *port_mapping; 211762306a36Sopenharmony_ci size_t alloc_size; 211862306a36Sopenharmony_ci int i; 211962306a36Sopenharmony_ci int err; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci alloc_size = sizeof(struct mlxsw_sp_port *) * max_ports; 212262306a36Sopenharmony_ci mlxsw_sp->ports = kzalloc(alloc_size, GFP_KERNEL); 212362306a36Sopenharmony_ci if (!mlxsw_sp->ports) 212462306a36Sopenharmony_ci return -ENOMEM; 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci events = &mlxsw_sp->port_mapping_events; 212762306a36Sopenharmony_ci INIT_LIST_HEAD(&events->queue); 212862306a36Sopenharmony_ci spin_lock_init(&events->queue_lock); 212962306a36Sopenharmony_ci INIT_WORK(&events->work, mlxsw_sp_port_mapping_events_work); 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ci for (i = 1; i < max_ports; i++) { 213262306a36Sopenharmony_ci err = mlxsw_sp_port_mapping_event_set(mlxsw_sp, i, true); 213362306a36Sopenharmony_ci if (err) 213462306a36Sopenharmony_ci goto err_event_enable; 213562306a36Sopenharmony_ci } 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci err = mlxsw_sp_cpu_port_create(mlxsw_sp); 213862306a36Sopenharmony_ci if (err) 213962306a36Sopenharmony_ci goto err_cpu_port_create; 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci for (i = 1; i < max_ports; i++) { 214262306a36Sopenharmony_ci port_mapping = &mlxsw_sp->port_mapping[i]; 214362306a36Sopenharmony_ci if (!port_mapping->width) 214462306a36Sopenharmony_ci continue; 214562306a36Sopenharmony_ci err = mlxsw_sp_port_create(mlxsw_sp, i, false, port_mapping); 214662306a36Sopenharmony_ci if (err) 214762306a36Sopenharmony_ci goto err_port_create; 214862306a36Sopenharmony_ci } 214962306a36Sopenharmony_ci return 0; 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_cierr_port_create: 215262306a36Sopenharmony_ci for (i--; i >= 1; i--) 215362306a36Sopenharmony_ci if (mlxsw_sp_port_created(mlxsw_sp, i)) 215462306a36Sopenharmony_ci mlxsw_sp_port_remove(mlxsw_sp, i); 215562306a36Sopenharmony_ci i = max_ports; 215662306a36Sopenharmony_ci mlxsw_sp_cpu_port_remove(mlxsw_sp); 215762306a36Sopenharmony_cierr_cpu_port_create: 215862306a36Sopenharmony_cierr_event_enable: 215962306a36Sopenharmony_ci for (i--; i >= 1; i--) 216062306a36Sopenharmony_ci mlxsw_sp_port_mapping_event_set(mlxsw_sp, i, false); 216162306a36Sopenharmony_ci /* Make sure all scheduled events are processed */ 216262306a36Sopenharmony_ci __mlxsw_sp_port_mapping_events_cancel(mlxsw_sp); 216362306a36Sopenharmony_ci kfree(mlxsw_sp->ports); 216462306a36Sopenharmony_ci mlxsw_sp->ports = NULL; 216562306a36Sopenharmony_ci return err; 216662306a36Sopenharmony_ci} 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_cistatic int mlxsw_sp_port_module_info_init(struct mlxsw_sp *mlxsw_sp) 216962306a36Sopenharmony_ci{ 217062306a36Sopenharmony_ci unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); 217162306a36Sopenharmony_ci struct mlxsw_sp_port_mapping *port_mapping; 217262306a36Sopenharmony_ci int i; 217362306a36Sopenharmony_ci int err; 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci mlxsw_sp->port_mapping = kcalloc(max_ports, 217662306a36Sopenharmony_ci sizeof(struct mlxsw_sp_port_mapping), 217762306a36Sopenharmony_ci GFP_KERNEL); 217862306a36Sopenharmony_ci if (!mlxsw_sp->port_mapping) 217962306a36Sopenharmony_ci return -ENOMEM; 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci for (i = 1; i < max_ports; i++) { 218262306a36Sopenharmony_ci port_mapping = &mlxsw_sp->port_mapping[i]; 218362306a36Sopenharmony_ci err = mlxsw_sp_port_module_info_get(mlxsw_sp, i, port_mapping); 218462306a36Sopenharmony_ci if (err) 218562306a36Sopenharmony_ci goto err_port_module_info_get; 218662306a36Sopenharmony_ci } 218762306a36Sopenharmony_ci return 0; 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_cierr_port_module_info_get: 219062306a36Sopenharmony_ci kfree(mlxsw_sp->port_mapping); 219162306a36Sopenharmony_ci return err; 219262306a36Sopenharmony_ci} 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_cistatic void mlxsw_sp_port_module_info_fini(struct mlxsw_sp *mlxsw_sp) 219562306a36Sopenharmony_ci{ 219662306a36Sopenharmony_ci kfree(mlxsw_sp->port_mapping); 219762306a36Sopenharmony_ci} 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_cistatic int 220062306a36Sopenharmony_cimlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, 220162306a36Sopenharmony_ci struct mlxsw_sp_port_mapping *port_mapping, 220262306a36Sopenharmony_ci unsigned int count, const char *pmtdb_pl) 220362306a36Sopenharmony_ci{ 220462306a36Sopenharmony_ci struct mlxsw_sp_port_mapping split_port_mapping; 220562306a36Sopenharmony_ci int err, i; 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci split_port_mapping = *port_mapping; 220862306a36Sopenharmony_ci split_port_mapping.width /= count; 220962306a36Sopenharmony_ci for (i = 0; i < count; i++) { 221062306a36Sopenharmony_ci u16 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i); 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci if (!mlxsw_sp_local_port_valid(s_local_port)) 221362306a36Sopenharmony_ci continue; 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci err = mlxsw_sp_port_create(mlxsw_sp, s_local_port, 221662306a36Sopenharmony_ci true, &split_port_mapping); 221762306a36Sopenharmony_ci if (err) 221862306a36Sopenharmony_ci goto err_port_create; 221962306a36Sopenharmony_ci split_port_mapping.lane += split_port_mapping.width; 222062306a36Sopenharmony_ci } 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci return 0; 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_cierr_port_create: 222562306a36Sopenharmony_ci for (i--; i >= 0; i--) { 222662306a36Sopenharmony_ci u16 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i); 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci if (mlxsw_sp_port_created(mlxsw_sp, s_local_port)) 222962306a36Sopenharmony_ci mlxsw_sp_port_remove(mlxsw_sp, s_local_port); 223062306a36Sopenharmony_ci } 223162306a36Sopenharmony_ci return err; 223262306a36Sopenharmony_ci} 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_cistatic void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp, 223562306a36Sopenharmony_ci unsigned int count, 223662306a36Sopenharmony_ci const char *pmtdb_pl) 223762306a36Sopenharmony_ci{ 223862306a36Sopenharmony_ci struct mlxsw_sp_port_mapping *port_mapping; 223962306a36Sopenharmony_ci int i; 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci /* Go over original unsplit ports in the gap and recreate them. */ 224262306a36Sopenharmony_ci for (i = 0; i < count; i++) { 224362306a36Sopenharmony_ci u16 local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i); 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci port_mapping = &mlxsw_sp->port_mapping[local_port]; 224662306a36Sopenharmony_ci if (!port_mapping->width || !mlxsw_sp_local_port_valid(local_port)) 224762306a36Sopenharmony_ci continue; 224862306a36Sopenharmony_ci mlxsw_sp_port_create(mlxsw_sp, local_port, 224962306a36Sopenharmony_ci false, port_mapping); 225062306a36Sopenharmony_ci } 225162306a36Sopenharmony_ci} 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_cistatic struct mlxsw_sp_port * 225462306a36Sopenharmony_cimlxsw_sp_port_get_by_local_port(struct mlxsw_sp *mlxsw_sp, u16 local_port) 225562306a36Sopenharmony_ci{ 225662306a36Sopenharmony_ci if (mlxsw_sp->ports && mlxsw_sp->ports[local_port]) 225762306a36Sopenharmony_ci return mlxsw_sp->ports[local_port]; 225862306a36Sopenharmony_ci return NULL; 225962306a36Sopenharmony_ci} 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_cistatic int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u16 local_port, 226262306a36Sopenharmony_ci unsigned int count, 226362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 226462306a36Sopenharmony_ci{ 226562306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 226662306a36Sopenharmony_ci struct mlxsw_sp_port_mapping port_mapping; 226762306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 226862306a36Sopenharmony_ci enum mlxsw_reg_pmtdb_status status; 226962306a36Sopenharmony_ci char pmtdb_pl[MLXSW_REG_PMTDB_LEN]; 227062306a36Sopenharmony_ci int i; 227162306a36Sopenharmony_ci int err; 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port); 227462306a36Sopenharmony_ci if (!mlxsw_sp_port) { 227562306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n", 227662306a36Sopenharmony_ci local_port); 227762306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Port number does not exist"); 227862306a36Sopenharmony_ci return -EINVAL; 227962306a36Sopenharmony_ci } 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci if (mlxsw_sp_port->split) { 228262306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Port is already split"); 228362306a36Sopenharmony_ci return -EINVAL; 228462306a36Sopenharmony_ci } 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci mlxsw_reg_pmtdb_pack(pmtdb_pl, mlxsw_sp_port->mapping.slot_index, 228762306a36Sopenharmony_ci mlxsw_sp_port->mapping.module, 228862306a36Sopenharmony_ci mlxsw_sp_port->mapping.module_width / count, 228962306a36Sopenharmony_ci count); 229062306a36Sopenharmony_ci err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtdb), pmtdb_pl); 229162306a36Sopenharmony_ci if (err) { 229262306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to query split info"); 229362306a36Sopenharmony_ci return err; 229462306a36Sopenharmony_ci } 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci status = mlxsw_reg_pmtdb_status_get(pmtdb_pl); 229762306a36Sopenharmony_ci if (status != MLXSW_REG_PMTDB_STATUS_SUCCESS) { 229862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unsupported split configuration"); 229962306a36Sopenharmony_ci return -EINVAL; 230062306a36Sopenharmony_ci } 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci port_mapping = mlxsw_sp_port->mapping; 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci for (i = 0; i < count; i++) { 230562306a36Sopenharmony_ci u16 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i); 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci if (mlxsw_sp_port_created(mlxsw_sp, s_local_port)) 230862306a36Sopenharmony_ci mlxsw_sp_port_remove(mlxsw_sp, s_local_port); 230962306a36Sopenharmony_ci } 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci err = mlxsw_sp_port_split_create(mlxsw_sp, &port_mapping, 231262306a36Sopenharmony_ci count, pmtdb_pl); 231362306a36Sopenharmony_ci if (err) { 231462306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to create split ports\n"); 231562306a36Sopenharmony_ci goto err_port_split_create; 231662306a36Sopenharmony_ci } 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci return 0; 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_cierr_port_split_create: 232162306a36Sopenharmony_ci mlxsw_sp_port_unsplit_create(mlxsw_sp, count, pmtdb_pl); 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_ci return err; 232462306a36Sopenharmony_ci} 232562306a36Sopenharmony_ci 232662306a36Sopenharmony_cistatic int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u16 local_port, 232762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 232862306a36Sopenharmony_ci{ 232962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 233062306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 233162306a36Sopenharmony_ci char pmtdb_pl[MLXSW_REG_PMTDB_LEN]; 233262306a36Sopenharmony_ci unsigned int count; 233362306a36Sopenharmony_ci int i; 233462306a36Sopenharmony_ci int err; 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port); 233762306a36Sopenharmony_ci if (!mlxsw_sp_port) { 233862306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n", 233962306a36Sopenharmony_ci local_port); 234062306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Port number does not exist"); 234162306a36Sopenharmony_ci return -EINVAL; 234262306a36Sopenharmony_ci } 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci if (!mlxsw_sp_port->split) { 234562306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Port was not split"); 234662306a36Sopenharmony_ci return -EINVAL; 234762306a36Sopenharmony_ci } 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci count = mlxsw_sp_port->mapping.module_width / 235062306a36Sopenharmony_ci mlxsw_sp_port->mapping.width; 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci mlxsw_reg_pmtdb_pack(pmtdb_pl, mlxsw_sp_port->mapping.slot_index, 235362306a36Sopenharmony_ci mlxsw_sp_port->mapping.module, 235462306a36Sopenharmony_ci mlxsw_sp_port->mapping.module_width / count, 235562306a36Sopenharmony_ci count); 235662306a36Sopenharmony_ci err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtdb), pmtdb_pl); 235762306a36Sopenharmony_ci if (err) { 235862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to query split info"); 235962306a36Sopenharmony_ci return err; 236062306a36Sopenharmony_ci } 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci for (i = 0; i < count; i++) { 236362306a36Sopenharmony_ci u16 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i); 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci if (mlxsw_sp_port_created(mlxsw_sp, s_local_port)) 236662306a36Sopenharmony_ci mlxsw_sp_port_remove(mlxsw_sp, s_local_port); 236762306a36Sopenharmony_ci } 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci mlxsw_sp_port_unsplit_create(mlxsw_sp, count, pmtdb_pl); 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci return 0; 237262306a36Sopenharmony_ci} 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_cistatic void 237562306a36Sopenharmony_cimlxsw_sp_port_down_wipe_counters(struct mlxsw_sp_port *mlxsw_sp_port) 237662306a36Sopenharmony_ci{ 237762306a36Sopenharmony_ci int i; 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci for (i = 0; i < TC_MAX_QUEUE; i++) 238062306a36Sopenharmony_ci mlxsw_sp_port->periodic_hw_stats.xstats.backlog[i] = 0; 238162306a36Sopenharmony_ci} 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_cistatic void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg, 238462306a36Sopenharmony_ci char *pude_pl, void *priv) 238562306a36Sopenharmony_ci{ 238662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 238762306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 238862306a36Sopenharmony_ci enum mlxsw_reg_pude_oper_status status; 238962306a36Sopenharmony_ci u16 local_port; 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci local_port = mlxsw_reg_pude_local_port_get(pude_pl); 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci if (WARN_ON_ONCE(!mlxsw_sp_local_port_is_valid(mlxsw_sp, local_port))) 239462306a36Sopenharmony_ci return; 239562306a36Sopenharmony_ci mlxsw_sp_port = mlxsw_sp->ports[local_port]; 239662306a36Sopenharmony_ci if (!mlxsw_sp_port) 239762306a36Sopenharmony_ci return; 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci status = mlxsw_reg_pude_oper_status_get(pude_pl); 240062306a36Sopenharmony_ci if (status == MLXSW_PORT_OPER_STATUS_UP) { 240162306a36Sopenharmony_ci netdev_info(mlxsw_sp_port->dev, "link up\n"); 240262306a36Sopenharmony_ci netif_carrier_on(mlxsw_sp_port->dev); 240362306a36Sopenharmony_ci mlxsw_core_schedule_dw(&mlxsw_sp_port->ptp.shaper_dw, 0); 240462306a36Sopenharmony_ci } else { 240562306a36Sopenharmony_ci netdev_info(mlxsw_sp_port->dev, "link down\n"); 240662306a36Sopenharmony_ci netif_carrier_off(mlxsw_sp_port->dev); 240762306a36Sopenharmony_ci mlxsw_sp_port_down_wipe_counters(mlxsw_sp_port); 240862306a36Sopenharmony_ci } 240962306a36Sopenharmony_ci} 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_cistatic void mlxsw_sp1_ptp_fifo_event_func(struct mlxsw_sp *mlxsw_sp, 241262306a36Sopenharmony_ci char *mtpptr_pl, bool ingress) 241362306a36Sopenharmony_ci{ 241462306a36Sopenharmony_ci u16 local_port; 241562306a36Sopenharmony_ci u8 num_rec; 241662306a36Sopenharmony_ci int i; 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci local_port = mlxsw_reg_mtpptr_local_port_get(mtpptr_pl); 241962306a36Sopenharmony_ci num_rec = mlxsw_reg_mtpptr_num_rec_get(mtpptr_pl); 242062306a36Sopenharmony_ci for (i = 0; i < num_rec; i++) { 242162306a36Sopenharmony_ci u8 domain_number; 242262306a36Sopenharmony_ci u8 message_type; 242362306a36Sopenharmony_ci u16 sequence_id; 242462306a36Sopenharmony_ci u64 timestamp; 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci mlxsw_reg_mtpptr_unpack(mtpptr_pl, i, &message_type, 242762306a36Sopenharmony_ci &domain_number, &sequence_id, 242862306a36Sopenharmony_ci ×tamp); 242962306a36Sopenharmony_ci mlxsw_sp1_ptp_got_timestamp(mlxsw_sp, ingress, local_port, 243062306a36Sopenharmony_ci message_type, domain_number, 243162306a36Sopenharmony_ci sequence_id, timestamp); 243262306a36Sopenharmony_ci } 243362306a36Sopenharmony_ci} 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_cistatic void mlxsw_sp1_ptp_ing_fifo_event_func(const struct mlxsw_reg_info *reg, 243662306a36Sopenharmony_ci char *mtpptr_pl, void *priv) 243762306a36Sopenharmony_ci{ 243862306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci mlxsw_sp1_ptp_fifo_event_func(mlxsw_sp, mtpptr_pl, true); 244162306a36Sopenharmony_ci} 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_cistatic void mlxsw_sp1_ptp_egr_fifo_event_func(const struct mlxsw_reg_info *reg, 244462306a36Sopenharmony_ci char *mtpptr_pl, void *priv) 244562306a36Sopenharmony_ci{ 244662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci mlxsw_sp1_ptp_fifo_event_func(mlxsw_sp, mtpptr_pl, false); 244962306a36Sopenharmony_ci} 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_civoid mlxsw_sp_rx_listener_no_mark_func(struct sk_buff *skb, 245262306a36Sopenharmony_ci u16 local_port, void *priv) 245362306a36Sopenharmony_ci{ 245462306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = priv; 245562306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port]; 245662306a36Sopenharmony_ci struct mlxsw_sp_port_pcpu_stats *pcpu_stats; 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci if (unlikely(!mlxsw_sp_port)) { 245962306a36Sopenharmony_ci dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n", 246062306a36Sopenharmony_ci local_port); 246162306a36Sopenharmony_ci return; 246262306a36Sopenharmony_ci } 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci skb->dev = mlxsw_sp_port->dev; 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats); 246762306a36Sopenharmony_ci u64_stats_update_begin(&pcpu_stats->syncp); 246862306a36Sopenharmony_ci pcpu_stats->rx_packets++; 246962306a36Sopenharmony_ci pcpu_stats->rx_bytes += skb->len; 247062306a36Sopenharmony_ci u64_stats_update_end(&pcpu_stats->syncp); 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, skb->dev); 247362306a36Sopenharmony_ci netif_receive_skb(skb); 247462306a36Sopenharmony_ci} 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_cistatic void mlxsw_sp_rx_listener_mark_func(struct sk_buff *skb, u16 local_port, 247762306a36Sopenharmony_ci void *priv) 247862306a36Sopenharmony_ci{ 247962306a36Sopenharmony_ci skb->offload_fwd_mark = 1; 248062306a36Sopenharmony_ci return mlxsw_sp_rx_listener_no_mark_func(skb, local_port, priv); 248162306a36Sopenharmony_ci} 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_cistatic void mlxsw_sp_rx_listener_l3_mark_func(struct sk_buff *skb, 248462306a36Sopenharmony_ci u16 local_port, void *priv) 248562306a36Sopenharmony_ci{ 248662306a36Sopenharmony_ci skb->offload_l3_fwd_mark = 1; 248762306a36Sopenharmony_ci skb->offload_fwd_mark = 1; 248862306a36Sopenharmony_ci return mlxsw_sp_rx_listener_no_mark_func(skb, local_port, priv); 248962306a36Sopenharmony_ci} 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_civoid mlxsw_sp_ptp_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, 249262306a36Sopenharmony_ci u16 local_port) 249362306a36Sopenharmony_ci{ 249462306a36Sopenharmony_ci mlxsw_sp->ptp_ops->receive(mlxsw_sp, skb, local_port); 249562306a36Sopenharmony_ci} 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci#define MLXSW_SP_RXL_NO_MARK(_trap_id, _action, _trap_group, _is_ctrl) \ 249862306a36Sopenharmony_ci MLXSW_RXL(mlxsw_sp_rx_listener_no_mark_func, _trap_id, _action, \ 249962306a36Sopenharmony_ci _is_ctrl, SP_##_trap_group, DISCARD) 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci#define MLXSW_SP_RXL_MARK(_trap_id, _action, _trap_group, _is_ctrl) \ 250262306a36Sopenharmony_ci MLXSW_RXL(mlxsw_sp_rx_listener_mark_func, _trap_id, _action, \ 250362306a36Sopenharmony_ci _is_ctrl, SP_##_trap_group, DISCARD) 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci#define MLXSW_SP_RXL_L3_MARK(_trap_id, _action, _trap_group, _is_ctrl) \ 250662306a36Sopenharmony_ci MLXSW_RXL(mlxsw_sp_rx_listener_l3_mark_func, _trap_id, _action, \ 250762306a36Sopenharmony_ci _is_ctrl, SP_##_trap_group, DISCARD) 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci#define MLXSW_SP_EVENTL(_func, _trap_id) \ 251062306a36Sopenharmony_ci MLXSW_EVENTL(_func, _trap_id, SP_EVENT) 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_cistatic const struct mlxsw_listener mlxsw_sp_listener[] = { 251362306a36Sopenharmony_ci /* Events */ 251462306a36Sopenharmony_ci MLXSW_SP_EVENTL(mlxsw_sp_pude_event_func, PUDE), 251562306a36Sopenharmony_ci /* L2 traps */ 251662306a36Sopenharmony_ci MLXSW_SP_RXL_NO_MARK(FID_MISS, TRAP_TO_CPU, FID_MISS, false), 251762306a36Sopenharmony_ci /* L3 traps */ 251862306a36Sopenharmony_ci MLXSW_SP_RXL_MARK(IPV6_UNSPECIFIED_ADDRESS, TRAP_TO_CPU, ROUTER_EXP, 251962306a36Sopenharmony_ci false), 252062306a36Sopenharmony_ci MLXSW_SP_RXL_MARK(IPV6_LINK_LOCAL_SRC, TRAP_TO_CPU, ROUTER_EXP, false), 252162306a36Sopenharmony_ci MLXSW_SP_RXL_MARK(IPV6_MC_LINK_LOCAL_DEST, TRAP_TO_CPU, ROUTER_EXP, 252262306a36Sopenharmony_ci false), 252362306a36Sopenharmony_ci MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_SIP_CLASS_E, FORWARD, 252462306a36Sopenharmony_ci ROUTER_EXP, false), 252562306a36Sopenharmony_ci MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_MC_DMAC, FORWARD, 252662306a36Sopenharmony_ci ROUTER_EXP, false), 252762306a36Sopenharmony_ci MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_SIP_DIP, FORWARD, 252862306a36Sopenharmony_ci ROUTER_EXP, false), 252962306a36Sopenharmony_ci MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_DIP_LINK_LOCAL, FORWARD, 253062306a36Sopenharmony_ci ROUTER_EXP, false), 253162306a36Sopenharmony_ci /* Multicast Router Traps */ 253262306a36Sopenharmony_ci MLXSW_SP_RXL_MARK(ACL1, TRAP_TO_CPU, MULTICAST, false), 253362306a36Sopenharmony_ci MLXSW_SP_RXL_L3_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false), 253462306a36Sopenharmony_ci /* NVE traps */ 253562306a36Sopenharmony_ci MLXSW_SP_RXL_MARK(NVE_ENCAP_ARP, TRAP_TO_CPU, NEIGH_DISCOVERY, false), 253662306a36Sopenharmony_ci}; 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_cistatic const struct mlxsw_listener mlxsw_sp1_listener[] = { 253962306a36Sopenharmony_ci /* Events */ 254062306a36Sopenharmony_ci MLXSW_EVENTL(mlxsw_sp1_ptp_egr_fifo_event_func, PTP_EGR_FIFO, SP_PTP0), 254162306a36Sopenharmony_ci MLXSW_EVENTL(mlxsw_sp1_ptp_ing_fifo_event_func, PTP_ING_FIFO, SP_PTP0), 254262306a36Sopenharmony_ci}; 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_cistatic const struct mlxsw_listener mlxsw_sp2_listener[] = { 254562306a36Sopenharmony_ci /* Events */ 254662306a36Sopenharmony_ci MLXSW_SP_EVENTL(mlxsw_sp_port_mapping_listener_func, PMLPE), 254762306a36Sopenharmony_ci}; 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_cistatic int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core) 255062306a36Sopenharmony_ci{ 255162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 255262306a36Sopenharmony_ci char qpcr_pl[MLXSW_REG_QPCR_LEN]; 255362306a36Sopenharmony_ci enum mlxsw_reg_qpcr_ir_units ir_units; 255462306a36Sopenharmony_ci int max_cpu_policers; 255562306a36Sopenharmony_ci bool is_bytes; 255662306a36Sopenharmony_ci u8 burst_size; 255762306a36Sopenharmony_ci u32 rate; 255862306a36Sopenharmony_ci int i, err; 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_CPU_POLICERS)) 256162306a36Sopenharmony_ci return -EIO; 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci max_cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS); 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci ir_units = MLXSW_REG_QPCR_IR_UNITS_M; 256662306a36Sopenharmony_ci for (i = 0; i < max_cpu_policers; i++) { 256762306a36Sopenharmony_ci is_bytes = false; 256862306a36Sopenharmony_ci switch (i) { 256962306a36Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_ROUTER_EXP: 257062306a36Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_MULTICAST: 257162306a36Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_FID_MISS: 257262306a36Sopenharmony_ci rate = 1024; 257362306a36Sopenharmony_ci burst_size = 7; 257462306a36Sopenharmony_ci break; 257562306a36Sopenharmony_ci default: 257662306a36Sopenharmony_ci continue; 257762306a36Sopenharmony_ci } 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci __set_bit(i, mlxsw_sp->trap->policers_usage); 258062306a36Sopenharmony_ci mlxsw_reg_qpcr_pack(qpcr_pl, i, ir_units, is_bytes, rate, 258162306a36Sopenharmony_ci burst_size); 258262306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(qpcr), qpcr_pl); 258362306a36Sopenharmony_ci if (err) 258462306a36Sopenharmony_ci return err; 258562306a36Sopenharmony_ci } 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci return 0; 258862306a36Sopenharmony_ci} 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_cistatic int mlxsw_sp_trap_groups_set(struct mlxsw_core *mlxsw_core) 259162306a36Sopenharmony_ci{ 259262306a36Sopenharmony_ci char htgt_pl[MLXSW_REG_HTGT_LEN]; 259362306a36Sopenharmony_ci enum mlxsw_reg_htgt_trap_group i; 259462306a36Sopenharmony_ci int max_cpu_policers; 259562306a36Sopenharmony_ci int max_trap_groups; 259662306a36Sopenharmony_ci u8 priority, tc; 259762306a36Sopenharmony_ci u16 policer_id; 259862306a36Sopenharmony_ci int err; 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_TRAP_GROUPS)) 260162306a36Sopenharmony_ci return -EIO; 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci max_trap_groups = MLXSW_CORE_RES_GET(mlxsw_core, MAX_TRAP_GROUPS); 260462306a36Sopenharmony_ci max_cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS); 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci for (i = 0; i < max_trap_groups; i++) { 260762306a36Sopenharmony_ci policer_id = i; 260862306a36Sopenharmony_ci switch (i) { 260962306a36Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_ROUTER_EXP: 261062306a36Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_MULTICAST: 261162306a36Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_FID_MISS: 261262306a36Sopenharmony_ci priority = 1; 261362306a36Sopenharmony_ci tc = 1; 261462306a36Sopenharmony_ci break; 261562306a36Sopenharmony_ci case MLXSW_REG_HTGT_TRAP_GROUP_SP_EVENT: 261662306a36Sopenharmony_ci priority = MLXSW_REG_HTGT_DEFAULT_PRIORITY; 261762306a36Sopenharmony_ci tc = MLXSW_REG_HTGT_DEFAULT_TC; 261862306a36Sopenharmony_ci policer_id = MLXSW_REG_HTGT_INVALID_POLICER; 261962306a36Sopenharmony_ci break; 262062306a36Sopenharmony_ci default: 262162306a36Sopenharmony_ci continue; 262262306a36Sopenharmony_ci } 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci if (max_cpu_policers <= policer_id && 262562306a36Sopenharmony_ci policer_id != MLXSW_REG_HTGT_INVALID_POLICER) 262662306a36Sopenharmony_ci return -EIO; 262762306a36Sopenharmony_ci 262862306a36Sopenharmony_ci mlxsw_reg_htgt_pack(htgt_pl, i, policer_id, priority, tc); 262962306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); 263062306a36Sopenharmony_ci if (err) 263162306a36Sopenharmony_ci return err; 263262306a36Sopenharmony_ci } 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci return 0; 263562306a36Sopenharmony_ci} 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_cistatic int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp) 263862306a36Sopenharmony_ci{ 263962306a36Sopenharmony_ci struct mlxsw_sp_trap *trap; 264062306a36Sopenharmony_ci u64 max_policers; 264162306a36Sopenharmony_ci int err; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_CPU_POLICERS)) 264462306a36Sopenharmony_ci return -EIO; 264562306a36Sopenharmony_ci max_policers = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_CPU_POLICERS); 264662306a36Sopenharmony_ci trap = kzalloc(struct_size(trap, policers_usage, 264762306a36Sopenharmony_ci BITS_TO_LONGS(max_policers)), GFP_KERNEL); 264862306a36Sopenharmony_ci if (!trap) 264962306a36Sopenharmony_ci return -ENOMEM; 265062306a36Sopenharmony_ci trap->max_policers = max_policers; 265162306a36Sopenharmony_ci mlxsw_sp->trap = trap; 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci err = mlxsw_sp_cpu_policers_set(mlxsw_sp->core); 265462306a36Sopenharmony_ci if (err) 265562306a36Sopenharmony_ci goto err_cpu_policers_set; 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ci err = mlxsw_sp_trap_groups_set(mlxsw_sp->core); 265862306a36Sopenharmony_ci if (err) 265962306a36Sopenharmony_ci goto err_trap_groups_set; 266062306a36Sopenharmony_ci 266162306a36Sopenharmony_ci err = mlxsw_core_traps_register(mlxsw_sp->core, mlxsw_sp_listener, 266262306a36Sopenharmony_ci ARRAY_SIZE(mlxsw_sp_listener), 266362306a36Sopenharmony_ci mlxsw_sp); 266462306a36Sopenharmony_ci if (err) 266562306a36Sopenharmony_ci goto err_traps_register; 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci err = mlxsw_core_traps_register(mlxsw_sp->core, mlxsw_sp->listeners, 266862306a36Sopenharmony_ci mlxsw_sp->listeners_count, mlxsw_sp); 266962306a36Sopenharmony_ci if (err) 267062306a36Sopenharmony_ci goto err_extra_traps_init; 267162306a36Sopenharmony_ci 267262306a36Sopenharmony_ci return 0; 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_cierr_extra_traps_init: 267562306a36Sopenharmony_ci mlxsw_core_traps_unregister(mlxsw_sp->core, mlxsw_sp_listener, 267662306a36Sopenharmony_ci ARRAY_SIZE(mlxsw_sp_listener), 267762306a36Sopenharmony_ci mlxsw_sp); 267862306a36Sopenharmony_cierr_traps_register: 267962306a36Sopenharmony_cierr_trap_groups_set: 268062306a36Sopenharmony_cierr_cpu_policers_set: 268162306a36Sopenharmony_ci kfree(trap); 268262306a36Sopenharmony_ci return err; 268362306a36Sopenharmony_ci} 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_cistatic void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) 268662306a36Sopenharmony_ci{ 268762306a36Sopenharmony_ci mlxsw_core_traps_unregister(mlxsw_sp->core, mlxsw_sp->listeners, 268862306a36Sopenharmony_ci mlxsw_sp->listeners_count, 268962306a36Sopenharmony_ci mlxsw_sp); 269062306a36Sopenharmony_ci mlxsw_core_traps_unregister(mlxsw_sp->core, mlxsw_sp_listener, 269162306a36Sopenharmony_ci ARRAY_SIZE(mlxsw_sp_listener), mlxsw_sp); 269262306a36Sopenharmony_ci kfree(mlxsw_sp->trap); 269362306a36Sopenharmony_ci} 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci#define MLXSW_SP_LAG_SEED_INIT 0xcafecafe 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_cistatic int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) 269862306a36Sopenharmony_ci{ 269962306a36Sopenharmony_ci char slcr_pl[MLXSW_REG_SLCR_LEN]; 270062306a36Sopenharmony_ci u16 max_lag; 270162306a36Sopenharmony_ci u32 seed; 270262306a36Sopenharmony_ci int err; 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_ci seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 270562306a36Sopenharmony_ci MLXSW_SP_LAG_SEED_INIT); 270662306a36Sopenharmony_ci mlxsw_reg_slcr_pack(slcr_pl, MLXSW_REG_SLCR_LAG_HASH_SMAC | 270762306a36Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_DMAC | 270862306a36Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_ETHERTYPE | 270962306a36Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_VLANID | 271062306a36Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_SIP | 271162306a36Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_DIP | 271262306a36Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_SPORT | 271362306a36Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_DPORT | 271462306a36Sopenharmony_ci MLXSW_REG_SLCR_LAG_HASH_IPPROTO, seed); 271562306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcr), slcr_pl); 271662306a36Sopenharmony_ci if (err) 271762306a36Sopenharmony_ci return err; 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag); 272062306a36Sopenharmony_ci if (err) 272162306a36Sopenharmony_ci return err; 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LAG_MEMBERS)) 272462306a36Sopenharmony_ci return -EIO; 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci mlxsw_sp->lags = kcalloc(max_lag, sizeof(struct mlxsw_sp_upper), 272762306a36Sopenharmony_ci GFP_KERNEL); 272862306a36Sopenharmony_ci if (!mlxsw_sp->lags) 272962306a36Sopenharmony_ci return -ENOMEM; 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci return 0; 273262306a36Sopenharmony_ci} 273362306a36Sopenharmony_ci 273462306a36Sopenharmony_cistatic void mlxsw_sp_lag_fini(struct mlxsw_sp *mlxsw_sp) 273562306a36Sopenharmony_ci{ 273662306a36Sopenharmony_ci kfree(mlxsw_sp->lags); 273762306a36Sopenharmony_ci} 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_cistatic const struct mlxsw_sp_ptp_ops mlxsw_sp1_ptp_ops = { 274062306a36Sopenharmony_ci .clock_init = mlxsw_sp1_ptp_clock_init, 274162306a36Sopenharmony_ci .clock_fini = mlxsw_sp1_ptp_clock_fini, 274262306a36Sopenharmony_ci .init = mlxsw_sp1_ptp_init, 274362306a36Sopenharmony_ci .fini = mlxsw_sp1_ptp_fini, 274462306a36Sopenharmony_ci .receive = mlxsw_sp1_ptp_receive, 274562306a36Sopenharmony_ci .transmitted = mlxsw_sp1_ptp_transmitted, 274662306a36Sopenharmony_ci .hwtstamp_get = mlxsw_sp1_ptp_hwtstamp_get, 274762306a36Sopenharmony_ci .hwtstamp_set = mlxsw_sp1_ptp_hwtstamp_set, 274862306a36Sopenharmony_ci .shaper_work = mlxsw_sp1_ptp_shaper_work, 274962306a36Sopenharmony_ci .get_ts_info = mlxsw_sp1_ptp_get_ts_info, 275062306a36Sopenharmony_ci .get_stats_count = mlxsw_sp1_get_stats_count, 275162306a36Sopenharmony_ci .get_stats_strings = mlxsw_sp1_get_stats_strings, 275262306a36Sopenharmony_ci .get_stats = mlxsw_sp1_get_stats, 275362306a36Sopenharmony_ci .txhdr_construct = mlxsw_sp_ptp_txhdr_construct, 275462306a36Sopenharmony_ci}; 275562306a36Sopenharmony_ci 275662306a36Sopenharmony_cistatic const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = { 275762306a36Sopenharmony_ci .clock_init = mlxsw_sp2_ptp_clock_init, 275862306a36Sopenharmony_ci .clock_fini = mlxsw_sp2_ptp_clock_fini, 275962306a36Sopenharmony_ci .init = mlxsw_sp2_ptp_init, 276062306a36Sopenharmony_ci .fini = mlxsw_sp2_ptp_fini, 276162306a36Sopenharmony_ci .receive = mlxsw_sp2_ptp_receive, 276262306a36Sopenharmony_ci .transmitted = mlxsw_sp2_ptp_transmitted, 276362306a36Sopenharmony_ci .hwtstamp_get = mlxsw_sp2_ptp_hwtstamp_get, 276462306a36Sopenharmony_ci .hwtstamp_set = mlxsw_sp2_ptp_hwtstamp_set, 276562306a36Sopenharmony_ci .shaper_work = mlxsw_sp2_ptp_shaper_work, 276662306a36Sopenharmony_ci .get_ts_info = mlxsw_sp2_ptp_get_ts_info, 276762306a36Sopenharmony_ci .get_stats_count = mlxsw_sp2_get_stats_count, 276862306a36Sopenharmony_ci .get_stats_strings = mlxsw_sp2_get_stats_strings, 276962306a36Sopenharmony_ci .get_stats = mlxsw_sp2_get_stats, 277062306a36Sopenharmony_ci .txhdr_construct = mlxsw_sp2_ptp_txhdr_construct, 277162306a36Sopenharmony_ci}; 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_cistatic const struct mlxsw_sp_ptp_ops mlxsw_sp4_ptp_ops = { 277462306a36Sopenharmony_ci .clock_init = mlxsw_sp2_ptp_clock_init, 277562306a36Sopenharmony_ci .clock_fini = mlxsw_sp2_ptp_clock_fini, 277662306a36Sopenharmony_ci .init = mlxsw_sp2_ptp_init, 277762306a36Sopenharmony_ci .fini = mlxsw_sp2_ptp_fini, 277862306a36Sopenharmony_ci .receive = mlxsw_sp2_ptp_receive, 277962306a36Sopenharmony_ci .transmitted = mlxsw_sp2_ptp_transmitted, 278062306a36Sopenharmony_ci .hwtstamp_get = mlxsw_sp2_ptp_hwtstamp_get, 278162306a36Sopenharmony_ci .hwtstamp_set = mlxsw_sp2_ptp_hwtstamp_set, 278262306a36Sopenharmony_ci .shaper_work = mlxsw_sp2_ptp_shaper_work, 278362306a36Sopenharmony_ci .get_ts_info = mlxsw_sp2_ptp_get_ts_info, 278462306a36Sopenharmony_ci .get_stats_count = mlxsw_sp2_get_stats_count, 278562306a36Sopenharmony_ci .get_stats_strings = mlxsw_sp2_get_stats_strings, 278662306a36Sopenharmony_ci .get_stats = mlxsw_sp2_get_stats, 278762306a36Sopenharmony_ci .txhdr_construct = mlxsw_sp_ptp_txhdr_construct, 278862306a36Sopenharmony_ci}; 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_cistruct mlxsw_sp_sample_trigger_node { 279162306a36Sopenharmony_ci struct mlxsw_sp_sample_trigger trigger; 279262306a36Sopenharmony_ci struct mlxsw_sp_sample_params params; 279362306a36Sopenharmony_ci struct rhash_head ht_node; 279462306a36Sopenharmony_ci struct rcu_head rcu; 279562306a36Sopenharmony_ci refcount_t refcount; 279662306a36Sopenharmony_ci}; 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_cistatic const struct rhashtable_params mlxsw_sp_sample_trigger_ht_params = { 279962306a36Sopenharmony_ci .key_offset = offsetof(struct mlxsw_sp_sample_trigger_node, trigger), 280062306a36Sopenharmony_ci .head_offset = offsetof(struct mlxsw_sp_sample_trigger_node, ht_node), 280162306a36Sopenharmony_ci .key_len = sizeof(struct mlxsw_sp_sample_trigger), 280262306a36Sopenharmony_ci .automatic_shrinking = true, 280362306a36Sopenharmony_ci}; 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_cistatic void 280662306a36Sopenharmony_cimlxsw_sp_sample_trigger_key_init(struct mlxsw_sp_sample_trigger *key, 280762306a36Sopenharmony_ci const struct mlxsw_sp_sample_trigger *trigger) 280862306a36Sopenharmony_ci{ 280962306a36Sopenharmony_ci memset(key, 0, sizeof(*key)); 281062306a36Sopenharmony_ci key->type = trigger->type; 281162306a36Sopenharmony_ci key->local_port = trigger->local_port; 281262306a36Sopenharmony_ci} 281362306a36Sopenharmony_ci 281462306a36Sopenharmony_ci/* RCU read lock must be held */ 281562306a36Sopenharmony_cistruct mlxsw_sp_sample_params * 281662306a36Sopenharmony_cimlxsw_sp_sample_trigger_params_lookup(struct mlxsw_sp *mlxsw_sp, 281762306a36Sopenharmony_ci const struct mlxsw_sp_sample_trigger *trigger) 281862306a36Sopenharmony_ci{ 281962306a36Sopenharmony_ci struct mlxsw_sp_sample_trigger_node *trigger_node; 282062306a36Sopenharmony_ci struct mlxsw_sp_sample_trigger key; 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_ci mlxsw_sp_sample_trigger_key_init(&key, trigger); 282362306a36Sopenharmony_ci trigger_node = rhashtable_lookup(&mlxsw_sp->sample_trigger_ht, &key, 282462306a36Sopenharmony_ci mlxsw_sp_sample_trigger_ht_params); 282562306a36Sopenharmony_ci if (!trigger_node) 282662306a36Sopenharmony_ci return NULL; 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_ci return &trigger_node->params; 282962306a36Sopenharmony_ci} 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_cistatic int 283262306a36Sopenharmony_cimlxsw_sp_sample_trigger_node_init(struct mlxsw_sp *mlxsw_sp, 283362306a36Sopenharmony_ci const struct mlxsw_sp_sample_trigger *trigger, 283462306a36Sopenharmony_ci const struct mlxsw_sp_sample_params *params) 283562306a36Sopenharmony_ci{ 283662306a36Sopenharmony_ci struct mlxsw_sp_sample_trigger_node *trigger_node; 283762306a36Sopenharmony_ci int err; 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci trigger_node = kzalloc(sizeof(*trigger_node), GFP_KERNEL); 284062306a36Sopenharmony_ci if (!trigger_node) 284162306a36Sopenharmony_ci return -ENOMEM; 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_ci trigger_node->trigger = *trigger; 284462306a36Sopenharmony_ci trigger_node->params = *params; 284562306a36Sopenharmony_ci refcount_set(&trigger_node->refcount, 1); 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci err = rhashtable_insert_fast(&mlxsw_sp->sample_trigger_ht, 284862306a36Sopenharmony_ci &trigger_node->ht_node, 284962306a36Sopenharmony_ci mlxsw_sp_sample_trigger_ht_params); 285062306a36Sopenharmony_ci if (err) 285162306a36Sopenharmony_ci goto err_rhashtable_insert; 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci return 0; 285462306a36Sopenharmony_ci 285562306a36Sopenharmony_cierr_rhashtable_insert: 285662306a36Sopenharmony_ci kfree(trigger_node); 285762306a36Sopenharmony_ci return err; 285862306a36Sopenharmony_ci} 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_cistatic void 286162306a36Sopenharmony_cimlxsw_sp_sample_trigger_node_fini(struct mlxsw_sp *mlxsw_sp, 286262306a36Sopenharmony_ci struct mlxsw_sp_sample_trigger_node *trigger_node) 286362306a36Sopenharmony_ci{ 286462306a36Sopenharmony_ci rhashtable_remove_fast(&mlxsw_sp->sample_trigger_ht, 286562306a36Sopenharmony_ci &trigger_node->ht_node, 286662306a36Sopenharmony_ci mlxsw_sp_sample_trigger_ht_params); 286762306a36Sopenharmony_ci kfree_rcu(trigger_node, rcu); 286862306a36Sopenharmony_ci} 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ciint 287162306a36Sopenharmony_cimlxsw_sp_sample_trigger_params_set(struct mlxsw_sp *mlxsw_sp, 287262306a36Sopenharmony_ci const struct mlxsw_sp_sample_trigger *trigger, 287362306a36Sopenharmony_ci const struct mlxsw_sp_sample_params *params, 287462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 287562306a36Sopenharmony_ci{ 287662306a36Sopenharmony_ci struct mlxsw_sp_sample_trigger_node *trigger_node; 287762306a36Sopenharmony_ci struct mlxsw_sp_sample_trigger key; 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_ci ASSERT_RTNL(); 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci mlxsw_sp_sample_trigger_key_init(&key, trigger); 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci trigger_node = rhashtable_lookup_fast(&mlxsw_sp->sample_trigger_ht, 288462306a36Sopenharmony_ci &key, 288562306a36Sopenharmony_ci mlxsw_sp_sample_trigger_ht_params); 288662306a36Sopenharmony_ci if (!trigger_node) 288762306a36Sopenharmony_ci return mlxsw_sp_sample_trigger_node_init(mlxsw_sp, &key, 288862306a36Sopenharmony_ci params); 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci if (trigger_node->trigger.local_port) { 289162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Sampling already enabled on port"); 289262306a36Sopenharmony_ci return -EINVAL; 289362306a36Sopenharmony_ci } 289462306a36Sopenharmony_ci 289562306a36Sopenharmony_ci if (trigger_node->params.psample_group != params->psample_group || 289662306a36Sopenharmony_ci trigger_node->params.truncate != params->truncate || 289762306a36Sopenharmony_ci trigger_node->params.rate != params->rate || 289862306a36Sopenharmony_ci trigger_node->params.trunc_size != params->trunc_size) { 289962306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Sampling parameters do not match for an existing sampling trigger"); 290062306a36Sopenharmony_ci return -EINVAL; 290162306a36Sopenharmony_ci } 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci refcount_inc(&trigger_node->refcount); 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci return 0; 290662306a36Sopenharmony_ci} 290762306a36Sopenharmony_ci 290862306a36Sopenharmony_civoid 290962306a36Sopenharmony_cimlxsw_sp_sample_trigger_params_unset(struct mlxsw_sp *mlxsw_sp, 291062306a36Sopenharmony_ci const struct mlxsw_sp_sample_trigger *trigger) 291162306a36Sopenharmony_ci{ 291262306a36Sopenharmony_ci struct mlxsw_sp_sample_trigger_node *trigger_node; 291362306a36Sopenharmony_ci struct mlxsw_sp_sample_trigger key; 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci ASSERT_RTNL(); 291662306a36Sopenharmony_ci 291762306a36Sopenharmony_ci mlxsw_sp_sample_trigger_key_init(&key, trigger); 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci trigger_node = rhashtable_lookup_fast(&mlxsw_sp->sample_trigger_ht, 292062306a36Sopenharmony_ci &key, 292162306a36Sopenharmony_ci mlxsw_sp_sample_trigger_ht_params); 292262306a36Sopenharmony_ci if (!trigger_node) 292362306a36Sopenharmony_ci return; 292462306a36Sopenharmony_ci 292562306a36Sopenharmony_ci if (!refcount_dec_and_test(&trigger_node->refcount)) 292662306a36Sopenharmony_ci return; 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci mlxsw_sp_sample_trigger_node_fini(mlxsw_sp, trigger_node); 292962306a36Sopenharmony_ci} 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_event(struct notifier_block *unused, 293262306a36Sopenharmony_ci unsigned long event, void *ptr); 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci#define MLXSW_SP_DEFAULT_PARSING_DEPTH 96 293562306a36Sopenharmony_ci#define MLXSW_SP_INCREASED_PARSING_DEPTH 128 293662306a36Sopenharmony_ci#define MLXSW_SP_DEFAULT_VXLAN_UDP_DPORT 4789 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_cistatic void mlxsw_sp_parsing_init(struct mlxsw_sp *mlxsw_sp) 293962306a36Sopenharmony_ci{ 294062306a36Sopenharmony_ci refcount_set(&mlxsw_sp->parsing.parsing_depth_ref, 0); 294162306a36Sopenharmony_ci mlxsw_sp->parsing.parsing_depth = MLXSW_SP_DEFAULT_PARSING_DEPTH; 294262306a36Sopenharmony_ci mlxsw_sp->parsing.vxlan_udp_dport = MLXSW_SP_DEFAULT_VXLAN_UDP_DPORT; 294362306a36Sopenharmony_ci mutex_init(&mlxsw_sp->parsing.lock); 294462306a36Sopenharmony_ci} 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_cistatic void mlxsw_sp_parsing_fini(struct mlxsw_sp *mlxsw_sp) 294762306a36Sopenharmony_ci{ 294862306a36Sopenharmony_ci mutex_destroy(&mlxsw_sp->parsing.lock); 294962306a36Sopenharmony_ci WARN_ON_ONCE(refcount_read(&mlxsw_sp->parsing.parsing_depth_ref)); 295062306a36Sopenharmony_ci} 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_cistruct mlxsw_sp_ipv6_addr_node { 295362306a36Sopenharmony_ci struct in6_addr key; 295462306a36Sopenharmony_ci struct rhash_head ht_node; 295562306a36Sopenharmony_ci u32 kvdl_index; 295662306a36Sopenharmony_ci refcount_t refcount; 295762306a36Sopenharmony_ci}; 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_cistatic const struct rhashtable_params mlxsw_sp_ipv6_addr_ht_params = { 296062306a36Sopenharmony_ci .key_offset = offsetof(struct mlxsw_sp_ipv6_addr_node, key), 296162306a36Sopenharmony_ci .head_offset = offsetof(struct mlxsw_sp_ipv6_addr_node, ht_node), 296262306a36Sopenharmony_ci .key_len = sizeof(struct in6_addr), 296362306a36Sopenharmony_ci .automatic_shrinking = true, 296462306a36Sopenharmony_ci}; 296562306a36Sopenharmony_ci 296662306a36Sopenharmony_cistatic int 296762306a36Sopenharmony_cimlxsw_sp_ipv6_addr_init(struct mlxsw_sp *mlxsw_sp, const struct in6_addr *addr6, 296862306a36Sopenharmony_ci u32 *p_kvdl_index) 296962306a36Sopenharmony_ci{ 297062306a36Sopenharmony_ci struct mlxsw_sp_ipv6_addr_node *node; 297162306a36Sopenharmony_ci char rips_pl[MLXSW_REG_RIPS_LEN]; 297262306a36Sopenharmony_ci int err; 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci err = mlxsw_sp_kvdl_alloc(mlxsw_sp, 297562306a36Sopenharmony_ci MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1, 297662306a36Sopenharmony_ci p_kvdl_index); 297762306a36Sopenharmony_ci if (err) 297862306a36Sopenharmony_ci return err; 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_ci mlxsw_reg_rips_pack(rips_pl, *p_kvdl_index, addr6); 298162306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rips), rips_pl); 298262306a36Sopenharmony_ci if (err) 298362306a36Sopenharmony_ci goto err_rips_write; 298462306a36Sopenharmony_ci 298562306a36Sopenharmony_ci node = kzalloc(sizeof(*node), GFP_KERNEL); 298662306a36Sopenharmony_ci if (!node) { 298762306a36Sopenharmony_ci err = -ENOMEM; 298862306a36Sopenharmony_ci goto err_node_alloc; 298962306a36Sopenharmony_ci } 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_ci node->key = *addr6; 299262306a36Sopenharmony_ci node->kvdl_index = *p_kvdl_index; 299362306a36Sopenharmony_ci refcount_set(&node->refcount, 1); 299462306a36Sopenharmony_ci 299562306a36Sopenharmony_ci err = rhashtable_insert_fast(&mlxsw_sp->ipv6_addr_ht, 299662306a36Sopenharmony_ci &node->ht_node, 299762306a36Sopenharmony_ci mlxsw_sp_ipv6_addr_ht_params); 299862306a36Sopenharmony_ci if (err) 299962306a36Sopenharmony_ci goto err_rhashtable_insert; 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci return 0; 300262306a36Sopenharmony_ci 300362306a36Sopenharmony_cierr_rhashtable_insert: 300462306a36Sopenharmony_ci kfree(node); 300562306a36Sopenharmony_cierr_node_alloc: 300662306a36Sopenharmony_cierr_rips_write: 300762306a36Sopenharmony_ci mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1, 300862306a36Sopenharmony_ci *p_kvdl_index); 300962306a36Sopenharmony_ci return err; 301062306a36Sopenharmony_ci} 301162306a36Sopenharmony_ci 301262306a36Sopenharmony_cistatic void mlxsw_sp_ipv6_addr_fini(struct mlxsw_sp *mlxsw_sp, 301362306a36Sopenharmony_ci struct mlxsw_sp_ipv6_addr_node *node) 301462306a36Sopenharmony_ci{ 301562306a36Sopenharmony_ci u32 kvdl_index = node->kvdl_index; 301662306a36Sopenharmony_ci 301762306a36Sopenharmony_ci rhashtable_remove_fast(&mlxsw_sp->ipv6_addr_ht, &node->ht_node, 301862306a36Sopenharmony_ci mlxsw_sp_ipv6_addr_ht_params); 301962306a36Sopenharmony_ci kfree(node); 302062306a36Sopenharmony_ci mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1, 302162306a36Sopenharmony_ci kvdl_index); 302262306a36Sopenharmony_ci} 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_ciint mlxsw_sp_ipv6_addr_kvdl_index_get(struct mlxsw_sp *mlxsw_sp, 302562306a36Sopenharmony_ci const struct in6_addr *addr6, 302662306a36Sopenharmony_ci u32 *p_kvdl_index) 302762306a36Sopenharmony_ci{ 302862306a36Sopenharmony_ci struct mlxsw_sp_ipv6_addr_node *node; 302962306a36Sopenharmony_ci int err = 0; 303062306a36Sopenharmony_ci 303162306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->ipv6_addr_ht_lock); 303262306a36Sopenharmony_ci node = rhashtable_lookup_fast(&mlxsw_sp->ipv6_addr_ht, addr6, 303362306a36Sopenharmony_ci mlxsw_sp_ipv6_addr_ht_params); 303462306a36Sopenharmony_ci if (node) { 303562306a36Sopenharmony_ci refcount_inc(&node->refcount); 303662306a36Sopenharmony_ci *p_kvdl_index = node->kvdl_index; 303762306a36Sopenharmony_ci goto out_unlock; 303862306a36Sopenharmony_ci } 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci err = mlxsw_sp_ipv6_addr_init(mlxsw_sp, addr6, p_kvdl_index); 304162306a36Sopenharmony_ci 304262306a36Sopenharmony_ciout_unlock: 304362306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->ipv6_addr_ht_lock); 304462306a36Sopenharmony_ci return err; 304562306a36Sopenharmony_ci} 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_civoid 304862306a36Sopenharmony_cimlxsw_sp_ipv6_addr_put(struct mlxsw_sp *mlxsw_sp, const struct in6_addr *addr6) 304962306a36Sopenharmony_ci{ 305062306a36Sopenharmony_ci struct mlxsw_sp_ipv6_addr_node *node; 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->ipv6_addr_ht_lock); 305362306a36Sopenharmony_ci node = rhashtable_lookup_fast(&mlxsw_sp->ipv6_addr_ht, addr6, 305462306a36Sopenharmony_ci mlxsw_sp_ipv6_addr_ht_params); 305562306a36Sopenharmony_ci if (WARN_ON(!node)) 305662306a36Sopenharmony_ci goto out_unlock; 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci if (!refcount_dec_and_test(&node->refcount)) 305962306a36Sopenharmony_ci goto out_unlock; 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_ci mlxsw_sp_ipv6_addr_fini(mlxsw_sp, node); 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ciout_unlock: 306462306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->ipv6_addr_ht_lock); 306562306a36Sopenharmony_ci} 306662306a36Sopenharmony_ci 306762306a36Sopenharmony_cistatic int mlxsw_sp_ipv6_addr_ht_init(struct mlxsw_sp *mlxsw_sp) 306862306a36Sopenharmony_ci{ 306962306a36Sopenharmony_ci int err; 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci err = rhashtable_init(&mlxsw_sp->ipv6_addr_ht, 307262306a36Sopenharmony_ci &mlxsw_sp_ipv6_addr_ht_params); 307362306a36Sopenharmony_ci if (err) 307462306a36Sopenharmony_ci return err; 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci mutex_init(&mlxsw_sp->ipv6_addr_ht_lock); 307762306a36Sopenharmony_ci return 0; 307862306a36Sopenharmony_ci} 307962306a36Sopenharmony_ci 308062306a36Sopenharmony_cistatic void mlxsw_sp_ipv6_addr_ht_fini(struct mlxsw_sp *mlxsw_sp) 308162306a36Sopenharmony_ci{ 308262306a36Sopenharmony_ci mutex_destroy(&mlxsw_sp->ipv6_addr_ht_lock); 308362306a36Sopenharmony_ci rhashtable_destroy(&mlxsw_sp->ipv6_addr_ht); 308462306a36Sopenharmony_ci} 308562306a36Sopenharmony_ci 308662306a36Sopenharmony_cistatic int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, 308762306a36Sopenharmony_ci const struct mlxsw_bus_info *mlxsw_bus_info, 308862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 308962306a36Sopenharmony_ci{ 309062306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 309162306a36Sopenharmony_ci int err; 309262306a36Sopenharmony_ci 309362306a36Sopenharmony_ci mlxsw_sp->core = mlxsw_core; 309462306a36Sopenharmony_ci mlxsw_sp->bus_info = mlxsw_bus_info; 309562306a36Sopenharmony_ci 309662306a36Sopenharmony_ci mlxsw_sp_parsing_init(mlxsw_sp); 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_ci err = mlxsw_sp_base_mac_get(mlxsw_sp); 309962306a36Sopenharmony_ci if (err) { 310062306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to get base mac\n"); 310162306a36Sopenharmony_ci return err; 310262306a36Sopenharmony_ci } 310362306a36Sopenharmony_ci 310462306a36Sopenharmony_ci err = mlxsw_sp_kvdl_init(mlxsw_sp); 310562306a36Sopenharmony_ci if (err) { 310662306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize KVDL\n"); 310762306a36Sopenharmony_ci return err; 310862306a36Sopenharmony_ci } 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci err = mlxsw_sp_pgt_init(mlxsw_sp); 311162306a36Sopenharmony_ci if (err) { 311262306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize PGT\n"); 311362306a36Sopenharmony_ci goto err_pgt_init; 311462306a36Sopenharmony_ci } 311562306a36Sopenharmony_ci 311662306a36Sopenharmony_ci err = mlxsw_sp_fids_init(mlxsw_sp); 311762306a36Sopenharmony_ci if (err) { 311862306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n"); 311962306a36Sopenharmony_ci goto err_fids_init; 312062306a36Sopenharmony_ci } 312162306a36Sopenharmony_ci 312262306a36Sopenharmony_ci err = mlxsw_sp_policers_init(mlxsw_sp); 312362306a36Sopenharmony_ci if (err) { 312462306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize policers\n"); 312562306a36Sopenharmony_ci goto err_policers_init; 312662306a36Sopenharmony_ci } 312762306a36Sopenharmony_ci 312862306a36Sopenharmony_ci err = mlxsw_sp_traps_init(mlxsw_sp); 312962306a36Sopenharmony_ci if (err) { 313062306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n"); 313162306a36Sopenharmony_ci goto err_traps_init; 313262306a36Sopenharmony_ci } 313362306a36Sopenharmony_ci 313462306a36Sopenharmony_ci err = mlxsw_sp_devlink_traps_init(mlxsw_sp); 313562306a36Sopenharmony_ci if (err) { 313662306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize devlink traps\n"); 313762306a36Sopenharmony_ci goto err_devlink_traps_init; 313862306a36Sopenharmony_ci } 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_ci err = mlxsw_sp_buffers_init(mlxsw_sp); 314162306a36Sopenharmony_ci if (err) { 314262306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize buffers\n"); 314362306a36Sopenharmony_ci goto err_buffers_init; 314462306a36Sopenharmony_ci } 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_ci err = mlxsw_sp_lag_init(mlxsw_sp); 314762306a36Sopenharmony_ci if (err) { 314862306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize LAG\n"); 314962306a36Sopenharmony_ci goto err_lag_init; 315062306a36Sopenharmony_ci } 315162306a36Sopenharmony_ci 315262306a36Sopenharmony_ci /* Initialize SPAN before router and switchdev, so that those components 315362306a36Sopenharmony_ci * can call mlxsw_sp_span_respin(). 315462306a36Sopenharmony_ci */ 315562306a36Sopenharmony_ci err = mlxsw_sp_span_init(mlxsw_sp); 315662306a36Sopenharmony_ci if (err) { 315762306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to init span system\n"); 315862306a36Sopenharmony_ci goto err_span_init; 315962306a36Sopenharmony_ci } 316062306a36Sopenharmony_ci 316162306a36Sopenharmony_ci err = mlxsw_sp_switchdev_init(mlxsw_sp); 316262306a36Sopenharmony_ci if (err) { 316362306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize switchdev\n"); 316462306a36Sopenharmony_ci goto err_switchdev_init; 316562306a36Sopenharmony_ci } 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ci err = mlxsw_sp_counter_pool_init(mlxsw_sp); 316862306a36Sopenharmony_ci if (err) { 316962306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to init counter pool\n"); 317062306a36Sopenharmony_ci goto err_counter_pool_init; 317162306a36Sopenharmony_ci } 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci err = mlxsw_sp_afa_init(mlxsw_sp); 317462306a36Sopenharmony_ci if (err) { 317562306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL actions\n"); 317662306a36Sopenharmony_ci goto err_afa_init; 317762306a36Sopenharmony_ci } 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_ci err = mlxsw_sp_ipv6_addr_ht_init(mlxsw_sp); 318062306a36Sopenharmony_ci if (err) { 318162306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize hash table for IPv6 addresses\n"); 318262306a36Sopenharmony_ci goto err_ipv6_addr_ht_init; 318362306a36Sopenharmony_ci } 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci err = mlxsw_sp_nve_init(mlxsw_sp); 318662306a36Sopenharmony_ci if (err) { 318762306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize NVE\n"); 318862306a36Sopenharmony_ci goto err_nve_init; 318962306a36Sopenharmony_ci } 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci err = mlxsw_sp_port_range_init(mlxsw_sp); 319262306a36Sopenharmony_ci if (err) { 319362306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize port ranges\n"); 319462306a36Sopenharmony_ci goto err_port_range_init; 319562306a36Sopenharmony_ci } 319662306a36Sopenharmony_ci 319762306a36Sopenharmony_ci err = mlxsw_sp_acl_init(mlxsw_sp); 319862306a36Sopenharmony_ci if (err) { 319962306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL\n"); 320062306a36Sopenharmony_ci goto err_acl_init; 320162306a36Sopenharmony_ci } 320262306a36Sopenharmony_ci 320362306a36Sopenharmony_ci err = mlxsw_sp_router_init(mlxsw_sp, extack); 320462306a36Sopenharmony_ci if (err) { 320562306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n"); 320662306a36Sopenharmony_ci goto err_router_init; 320762306a36Sopenharmony_ci } 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_ci if (mlxsw_sp->bus_info->read_clock_capable) { 321062306a36Sopenharmony_ci /* NULL is a valid return value from clock_init */ 321162306a36Sopenharmony_ci mlxsw_sp->clock = 321262306a36Sopenharmony_ci mlxsw_sp->ptp_ops->clock_init(mlxsw_sp, 321362306a36Sopenharmony_ci mlxsw_sp->bus_info->dev); 321462306a36Sopenharmony_ci if (IS_ERR(mlxsw_sp->clock)) { 321562306a36Sopenharmony_ci err = PTR_ERR(mlxsw_sp->clock); 321662306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to init ptp clock\n"); 321762306a36Sopenharmony_ci goto err_ptp_clock_init; 321862306a36Sopenharmony_ci } 321962306a36Sopenharmony_ci } 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_ci if (mlxsw_sp->clock) { 322262306a36Sopenharmony_ci /* NULL is a valid return value from ptp_ops->init */ 322362306a36Sopenharmony_ci mlxsw_sp->ptp_state = mlxsw_sp->ptp_ops->init(mlxsw_sp); 322462306a36Sopenharmony_ci if (IS_ERR(mlxsw_sp->ptp_state)) { 322562306a36Sopenharmony_ci err = PTR_ERR(mlxsw_sp->ptp_state); 322662306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize PTP\n"); 322762306a36Sopenharmony_ci goto err_ptp_init; 322862306a36Sopenharmony_ci } 322962306a36Sopenharmony_ci } 323062306a36Sopenharmony_ci 323162306a36Sopenharmony_ci /* Initialize netdevice notifier after SPAN is initialized, so that the 323262306a36Sopenharmony_ci * event handler can call SPAN respin. 323362306a36Sopenharmony_ci */ 323462306a36Sopenharmony_ci mlxsw_sp->netdevice_nb.notifier_call = mlxsw_sp_netdevice_event; 323562306a36Sopenharmony_ci err = register_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), 323662306a36Sopenharmony_ci &mlxsw_sp->netdevice_nb); 323762306a36Sopenharmony_ci if (err) { 323862306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to register netdev notifier\n"); 323962306a36Sopenharmony_ci goto err_netdev_notifier; 324062306a36Sopenharmony_ci } 324162306a36Sopenharmony_ci 324262306a36Sopenharmony_ci err = mlxsw_sp_dpipe_init(mlxsw_sp); 324362306a36Sopenharmony_ci if (err) { 324462306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to init pipeline debug\n"); 324562306a36Sopenharmony_ci goto err_dpipe_init; 324662306a36Sopenharmony_ci } 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci err = mlxsw_sp_port_module_info_init(mlxsw_sp); 324962306a36Sopenharmony_ci if (err) { 325062306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to init port module info\n"); 325162306a36Sopenharmony_ci goto err_port_module_info_init; 325262306a36Sopenharmony_ci } 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci err = rhashtable_init(&mlxsw_sp->sample_trigger_ht, 325562306a36Sopenharmony_ci &mlxsw_sp_sample_trigger_ht_params); 325662306a36Sopenharmony_ci if (err) { 325762306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to init sampling trigger hashtable\n"); 325862306a36Sopenharmony_ci goto err_sample_trigger_init; 325962306a36Sopenharmony_ci } 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci err = mlxsw_sp_ports_create(mlxsw_sp); 326262306a36Sopenharmony_ci if (err) { 326362306a36Sopenharmony_ci dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n"); 326462306a36Sopenharmony_ci goto err_ports_create; 326562306a36Sopenharmony_ci } 326662306a36Sopenharmony_ci 326762306a36Sopenharmony_ci return 0; 326862306a36Sopenharmony_ci 326962306a36Sopenharmony_cierr_ports_create: 327062306a36Sopenharmony_ci rhashtable_destroy(&mlxsw_sp->sample_trigger_ht); 327162306a36Sopenharmony_cierr_sample_trigger_init: 327262306a36Sopenharmony_ci mlxsw_sp_port_module_info_fini(mlxsw_sp); 327362306a36Sopenharmony_cierr_port_module_info_init: 327462306a36Sopenharmony_ci mlxsw_sp_dpipe_fini(mlxsw_sp); 327562306a36Sopenharmony_cierr_dpipe_init: 327662306a36Sopenharmony_ci unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), 327762306a36Sopenharmony_ci &mlxsw_sp->netdevice_nb); 327862306a36Sopenharmony_cierr_netdev_notifier: 327962306a36Sopenharmony_ci if (mlxsw_sp->clock) 328062306a36Sopenharmony_ci mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state); 328162306a36Sopenharmony_cierr_ptp_init: 328262306a36Sopenharmony_ci if (mlxsw_sp->clock) 328362306a36Sopenharmony_ci mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock); 328462306a36Sopenharmony_cierr_ptp_clock_init: 328562306a36Sopenharmony_ci mlxsw_sp_router_fini(mlxsw_sp); 328662306a36Sopenharmony_cierr_router_init: 328762306a36Sopenharmony_ci mlxsw_sp_acl_fini(mlxsw_sp); 328862306a36Sopenharmony_cierr_acl_init: 328962306a36Sopenharmony_ci mlxsw_sp_port_range_fini(mlxsw_sp); 329062306a36Sopenharmony_cierr_port_range_init: 329162306a36Sopenharmony_ci mlxsw_sp_nve_fini(mlxsw_sp); 329262306a36Sopenharmony_cierr_nve_init: 329362306a36Sopenharmony_ci mlxsw_sp_ipv6_addr_ht_fini(mlxsw_sp); 329462306a36Sopenharmony_cierr_ipv6_addr_ht_init: 329562306a36Sopenharmony_ci mlxsw_sp_afa_fini(mlxsw_sp); 329662306a36Sopenharmony_cierr_afa_init: 329762306a36Sopenharmony_ci mlxsw_sp_counter_pool_fini(mlxsw_sp); 329862306a36Sopenharmony_cierr_counter_pool_init: 329962306a36Sopenharmony_ci mlxsw_sp_switchdev_fini(mlxsw_sp); 330062306a36Sopenharmony_cierr_switchdev_init: 330162306a36Sopenharmony_ci mlxsw_sp_span_fini(mlxsw_sp); 330262306a36Sopenharmony_cierr_span_init: 330362306a36Sopenharmony_ci mlxsw_sp_lag_fini(mlxsw_sp); 330462306a36Sopenharmony_cierr_lag_init: 330562306a36Sopenharmony_ci mlxsw_sp_buffers_fini(mlxsw_sp); 330662306a36Sopenharmony_cierr_buffers_init: 330762306a36Sopenharmony_ci mlxsw_sp_devlink_traps_fini(mlxsw_sp); 330862306a36Sopenharmony_cierr_devlink_traps_init: 330962306a36Sopenharmony_ci mlxsw_sp_traps_fini(mlxsw_sp); 331062306a36Sopenharmony_cierr_traps_init: 331162306a36Sopenharmony_ci mlxsw_sp_policers_fini(mlxsw_sp); 331262306a36Sopenharmony_cierr_policers_init: 331362306a36Sopenharmony_ci mlxsw_sp_fids_fini(mlxsw_sp); 331462306a36Sopenharmony_cierr_fids_init: 331562306a36Sopenharmony_ci mlxsw_sp_pgt_fini(mlxsw_sp); 331662306a36Sopenharmony_cierr_pgt_init: 331762306a36Sopenharmony_ci mlxsw_sp_kvdl_fini(mlxsw_sp); 331862306a36Sopenharmony_ci mlxsw_sp_parsing_fini(mlxsw_sp); 331962306a36Sopenharmony_ci return err; 332062306a36Sopenharmony_ci} 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_cistatic int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core, 332362306a36Sopenharmony_ci const struct mlxsw_bus_info *mlxsw_bus_info, 332462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 332562306a36Sopenharmony_ci{ 332662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 332762306a36Sopenharmony_ci 332862306a36Sopenharmony_ci mlxsw_sp->switchdev_ops = &mlxsw_sp1_switchdev_ops; 332962306a36Sopenharmony_ci mlxsw_sp->kvdl_ops = &mlxsw_sp1_kvdl_ops; 333062306a36Sopenharmony_ci mlxsw_sp->afa_ops = &mlxsw_sp1_act_afa_ops; 333162306a36Sopenharmony_ci mlxsw_sp->afk_ops = &mlxsw_sp1_afk_ops; 333262306a36Sopenharmony_ci mlxsw_sp->mr_tcam_ops = &mlxsw_sp1_mr_tcam_ops; 333362306a36Sopenharmony_ci mlxsw_sp->acl_rulei_ops = &mlxsw_sp1_acl_rulei_ops; 333462306a36Sopenharmony_ci mlxsw_sp->acl_tcam_ops = &mlxsw_sp1_acl_tcam_ops; 333562306a36Sopenharmony_ci mlxsw_sp->nve_ops_arr = mlxsw_sp1_nve_ops_arr; 333662306a36Sopenharmony_ci mlxsw_sp->mac_mask = mlxsw_sp1_mac_mask; 333762306a36Sopenharmony_ci mlxsw_sp->sb_vals = &mlxsw_sp1_sb_vals; 333862306a36Sopenharmony_ci mlxsw_sp->sb_ops = &mlxsw_sp1_sb_ops; 333962306a36Sopenharmony_ci mlxsw_sp->port_type_speed_ops = &mlxsw_sp1_port_type_speed_ops; 334062306a36Sopenharmony_ci mlxsw_sp->ptp_ops = &mlxsw_sp1_ptp_ops; 334162306a36Sopenharmony_ci mlxsw_sp->span_ops = &mlxsw_sp1_span_ops; 334262306a36Sopenharmony_ci mlxsw_sp->policer_core_ops = &mlxsw_sp1_policer_core_ops; 334362306a36Sopenharmony_ci mlxsw_sp->trap_ops = &mlxsw_sp1_trap_ops; 334462306a36Sopenharmony_ci mlxsw_sp->mall_ops = &mlxsw_sp1_mall_ops; 334562306a36Sopenharmony_ci mlxsw_sp->router_ops = &mlxsw_sp1_router_ops; 334662306a36Sopenharmony_ci mlxsw_sp->listeners = mlxsw_sp1_listener; 334762306a36Sopenharmony_ci mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener); 334862306a36Sopenharmony_ci mlxsw_sp->fid_family_arr = mlxsw_sp1_fid_family_arr; 334962306a36Sopenharmony_ci mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP1; 335062306a36Sopenharmony_ci mlxsw_sp->pgt_smpe_index_valid = true; 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_ci return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); 335362306a36Sopenharmony_ci} 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_cistatic int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core, 335662306a36Sopenharmony_ci const struct mlxsw_bus_info *mlxsw_bus_info, 335762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 335862306a36Sopenharmony_ci{ 335962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 336062306a36Sopenharmony_ci 336162306a36Sopenharmony_ci mlxsw_sp->switchdev_ops = &mlxsw_sp2_switchdev_ops; 336262306a36Sopenharmony_ci mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops; 336362306a36Sopenharmony_ci mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops; 336462306a36Sopenharmony_ci mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops; 336562306a36Sopenharmony_ci mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops; 336662306a36Sopenharmony_ci mlxsw_sp->acl_rulei_ops = &mlxsw_sp2_acl_rulei_ops; 336762306a36Sopenharmony_ci mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops; 336862306a36Sopenharmony_ci mlxsw_sp->acl_bf_ops = &mlxsw_sp2_acl_bf_ops; 336962306a36Sopenharmony_ci mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr; 337062306a36Sopenharmony_ci mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask; 337162306a36Sopenharmony_ci mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals; 337262306a36Sopenharmony_ci mlxsw_sp->sb_ops = &mlxsw_sp2_sb_ops; 337362306a36Sopenharmony_ci mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops; 337462306a36Sopenharmony_ci mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops; 337562306a36Sopenharmony_ci mlxsw_sp->span_ops = &mlxsw_sp2_span_ops; 337662306a36Sopenharmony_ci mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops; 337762306a36Sopenharmony_ci mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops; 337862306a36Sopenharmony_ci mlxsw_sp->mall_ops = &mlxsw_sp2_mall_ops; 337962306a36Sopenharmony_ci mlxsw_sp->router_ops = &mlxsw_sp2_router_ops; 338062306a36Sopenharmony_ci mlxsw_sp->listeners = mlxsw_sp2_listener; 338162306a36Sopenharmony_ci mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener); 338262306a36Sopenharmony_ci mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr; 338362306a36Sopenharmony_ci mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP2; 338462306a36Sopenharmony_ci mlxsw_sp->pgt_smpe_index_valid = false; 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_ci return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); 338762306a36Sopenharmony_ci} 338862306a36Sopenharmony_ci 338962306a36Sopenharmony_cistatic int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core, 339062306a36Sopenharmony_ci const struct mlxsw_bus_info *mlxsw_bus_info, 339162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 339262306a36Sopenharmony_ci{ 339362306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 339462306a36Sopenharmony_ci 339562306a36Sopenharmony_ci mlxsw_sp->switchdev_ops = &mlxsw_sp2_switchdev_ops; 339662306a36Sopenharmony_ci mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops; 339762306a36Sopenharmony_ci mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops; 339862306a36Sopenharmony_ci mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops; 339962306a36Sopenharmony_ci mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops; 340062306a36Sopenharmony_ci mlxsw_sp->acl_rulei_ops = &mlxsw_sp2_acl_rulei_ops; 340162306a36Sopenharmony_ci mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops; 340262306a36Sopenharmony_ci mlxsw_sp->acl_bf_ops = &mlxsw_sp2_acl_bf_ops; 340362306a36Sopenharmony_ci mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr; 340462306a36Sopenharmony_ci mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask; 340562306a36Sopenharmony_ci mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals; 340662306a36Sopenharmony_ci mlxsw_sp->sb_ops = &mlxsw_sp3_sb_ops; 340762306a36Sopenharmony_ci mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops; 340862306a36Sopenharmony_ci mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops; 340962306a36Sopenharmony_ci mlxsw_sp->span_ops = &mlxsw_sp3_span_ops; 341062306a36Sopenharmony_ci mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops; 341162306a36Sopenharmony_ci mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops; 341262306a36Sopenharmony_ci mlxsw_sp->mall_ops = &mlxsw_sp2_mall_ops; 341362306a36Sopenharmony_ci mlxsw_sp->router_ops = &mlxsw_sp2_router_ops; 341462306a36Sopenharmony_ci mlxsw_sp->listeners = mlxsw_sp2_listener; 341562306a36Sopenharmony_ci mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener); 341662306a36Sopenharmony_ci mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr; 341762306a36Sopenharmony_ci mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3; 341862306a36Sopenharmony_ci mlxsw_sp->pgt_smpe_index_valid = false; 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); 342162306a36Sopenharmony_ci} 342262306a36Sopenharmony_ci 342362306a36Sopenharmony_cistatic int mlxsw_sp4_init(struct mlxsw_core *mlxsw_core, 342462306a36Sopenharmony_ci const struct mlxsw_bus_info *mlxsw_bus_info, 342562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 342662306a36Sopenharmony_ci{ 342762306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ci mlxsw_sp->switchdev_ops = &mlxsw_sp2_switchdev_ops; 343062306a36Sopenharmony_ci mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops; 343162306a36Sopenharmony_ci mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops; 343262306a36Sopenharmony_ci mlxsw_sp->afk_ops = &mlxsw_sp4_afk_ops; 343362306a36Sopenharmony_ci mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops; 343462306a36Sopenharmony_ci mlxsw_sp->acl_rulei_ops = &mlxsw_sp2_acl_rulei_ops; 343562306a36Sopenharmony_ci mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops; 343662306a36Sopenharmony_ci mlxsw_sp->acl_bf_ops = &mlxsw_sp4_acl_bf_ops; 343762306a36Sopenharmony_ci mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr; 343862306a36Sopenharmony_ci mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask; 343962306a36Sopenharmony_ci mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals; 344062306a36Sopenharmony_ci mlxsw_sp->sb_ops = &mlxsw_sp3_sb_ops; 344162306a36Sopenharmony_ci mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops; 344262306a36Sopenharmony_ci mlxsw_sp->ptp_ops = &mlxsw_sp4_ptp_ops; 344362306a36Sopenharmony_ci mlxsw_sp->span_ops = &mlxsw_sp3_span_ops; 344462306a36Sopenharmony_ci mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops; 344562306a36Sopenharmony_ci mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops; 344662306a36Sopenharmony_ci mlxsw_sp->mall_ops = &mlxsw_sp2_mall_ops; 344762306a36Sopenharmony_ci mlxsw_sp->router_ops = &mlxsw_sp2_router_ops; 344862306a36Sopenharmony_ci mlxsw_sp->listeners = mlxsw_sp2_listener; 344962306a36Sopenharmony_ci mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener); 345062306a36Sopenharmony_ci mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr; 345162306a36Sopenharmony_ci mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP4; 345262306a36Sopenharmony_ci mlxsw_sp->pgt_smpe_index_valid = false; 345362306a36Sopenharmony_ci 345462306a36Sopenharmony_ci return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); 345562306a36Sopenharmony_ci} 345662306a36Sopenharmony_ci 345762306a36Sopenharmony_cistatic void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) 345862306a36Sopenharmony_ci{ 345962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 346062306a36Sopenharmony_ci 346162306a36Sopenharmony_ci mlxsw_sp_ports_remove(mlxsw_sp); 346262306a36Sopenharmony_ci rhashtable_destroy(&mlxsw_sp->sample_trigger_ht); 346362306a36Sopenharmony_ci mlxsw_sp_port_module_info_fini(mlxsw_sp); 346462306a36Sopenharmony_ci mlxsw_sp_dpipe_fini(mlxsw_sp); 346562306a36Sopenharmony_ci unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), 346662306a36Sopenharmony_ci &mlxsw_sp->netdevice_nb); 346762306a36Sopenharmony_ci if (mlxsw_sp->clock) { 346862306a36Sopenharmony_ci mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state); 346962306a36Sopenharmony_ci mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock); 347062306a36Sopenharmony_ci } 347162306a36Sopenharmony_ci mlxsw_sp_router_fini(mlxsw_sp); 347262306a36Sopenharmony_ci mlxsw_sp_acl_fini(mlxsw_sp); 347362306a36Sopenharmony_ci mlxsw_sp_port_range_fini(mlxsw_sp); 347462306a36Sopenharmony_ci mlxsw_sp_nve_fini(mlxsw_sp); 347562306a36Sopenharmony_ci mlxsw_sp_ipv6_addr_ht_fini(mlxsw_sp); 347662306a36Sopenharmony_ci mlxsw_sp_afa_fini(mlxsw_sp); 347762306a36Sopenharmony_ci mlxsw_sp_counter_pool_fini(mlxsw_sp); 347862306a36Sopenharmony_ci mlxsw_sp_switchdev_fini(mlxsw_sp); 347962306a36Sopenharmony_ci mlxsw_sp_span_fini(mlxsw_sp); 348062306a36Sopenharmony_ci mlxsw_sp_lag_fini(mlxsw_sp); 348162306a36Sopenharmony_ci mlxsw_sp_buffers_fini(mlxsw_sp); 348262306a36Sopenharmony_ci mlxsw_sp_devlink_traps_fini(mlxsw_sp); 348362306a36Sopenharmony_ci mlxsw_sp_traps_fini(mlxsw_sp); 348462306a36Sopenharmony_ci mlxsw_sp_policers_fini(mlxsw_sp); 348562306a36Sopenharmony_ci mlxsw_sp_fids_fini(mlxsw_sp); 348662306a36Sopenharmony_ci mlxsw_sp_pgt_fini(mlxsw_sp); 348762306a36Sopenharmony_ci mlxsw_sp_kvdl_fini(mlxsw_sp); 348862306a36Sopenharmony_ci mlxsw_sp_parsing_fini(mlxsw_sp); 348962306a36Sopenharmony_ci} 349062306a36Sopenharmony_ci 349162306a36Sopenharmony_cistatic const struct mlxsw_config_profile mlxsw_sp1_config_profile = { 349262306a36Sopenharmony_ci .used_flood_mode = 1, 349362306a36Sopenharmony_ci .flood_mode = MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED, 349462306a36Sopenharmony_ci .used_max_ib_mc = 1, 349562306a36Sopenharmony_ci .max_ib_mc = 0, 349662306a36Sopenharmony_ci .used_max_pkey = 1, 349762306a36Sopenharmony_ci .max_pkey = 0, 349862306a36Sopenharmony_ci .used_ubridge = 1, 349962306a36Sopenharmony_ci .ubridge = 1, 350062306a36Sopenharmony_ci .used_kvd_sizes = 1, 350162306a36Sopenharmony_ci .kvd_hash_single_parts = 59, 350262306a36Sopenharmony_ci .kvd_hash_double_parts = 41, 350362306a36Sopenharmony_ci .kvd_linear_size = MLXSW_SP_KVD_LINEAR_SIZE, 350462306a36Sopenharmony_ci .swid_config = { 350562306a36Sopenharmony_ci { 350662306a36Sopenharmony_ci .used_type = 1, 350762306a36Sopenharmony_ci .type = MLXSW_PORT_SWID_TYPE_ETH, 350862306a36Sopenharmony_ci } 350962306a36Sopenharmony_ci }, 351062306a36Sopenharmony_ci}; 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_cistatic const struct mlxsw_config_profile mlxsw_sp2_config_profile = { 351362306a36Sopenharmony_ci .used_flood_mode = 1, 351462306a36Sopenharmony_ci .flood_mode = MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED, 351562306a36Sopenharmony_ci .used_max_ib_mc = 1, 351662306a36Sopenharmony_ci .max_ib_mc = 0, 351762306a36Sopenharmony_ci .used_max_pkey = 1, 351862306a36Sopenharmony_ci .max_pkey = 0, 351962306a36Sopenharmony_ci .used_ubridge = 1, 352062306a36Sopenharmony_ci .ubridge = 1, 352162306a36Sopenharmony_ci .swid_config = { 352262306a36Sopenharmony_ci { 352362306a36Sopenharmony_ci .used_type = 1, 352462306a36Sopenharmony_ci .type = MLXSW_PORT_SWID_TYPE_ETH, 352562306a36Sopenharmony_ci } 352662306a36Sopenharmony_ci }, 352762306a36Sopenharmony_ci .used_cqe_time_stamp_type = 1, 352862306a36Sopenharmony_ci .cqe_time_stamp_type = MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC, 352962306a36Sopenharmony_ci}; 353062306a36Sopenharmony_ci 353162306a36Sopenharmony_ci/* Reduce number of LAGs from full capacity (256) to the maximum supported LAGs 353262306a36Sopenharmony_ci * in Spectrum-2/3, to avoid regression in number of free entries in the PGT 353362306a36Sopenharmony_ci * table. 353462306a36Sopenharmony_ci */ 353562306a36Sopenharmony_ci#define MLXSW_SP4_CONFIG_PROFILE_MAX_LAG 128 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_cistatic const struct mlxsw_config_profile mlxsw_sp4_config_profile = { 353862306a36Sopenharmony_ci .used_max_lag = 1, 353962306a36Sopenharmony_ci .max_lag = MLXSW_SP4_CONFIG_PROFILE_MAX_LAG, 354062306a36Sopenharmony_ci .used_flood_mode = 1, 354162306a36Sopenharmony_ci .flood_mode = MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED, 354262306a36Sopenharmony_ci .used_max_ib_mc = 1, 354362306a36Sopenharmony_ci .max_ib_mc = 0, 354462306a36Sopenharmony_ci .used_max_pkey = 1, 354562306a36Sopenharmony_ci .max_pkey = 0, 354662306a36Sopenharmony_ci .used_ubridge = 1, 354762306a36Sopenharmony_ci .ubridge = 1, 354862306a36Sopenharmony_ci .swid_config = { 354962306a36Sopenharmony_ci { 355062306a36Sopenharmony_ci .used_type = 1, 355162306a36Sopenharmony_ci .type = MLXSW_PORT_SWID_TYPE_ETH, 355262306a36Sopenharmony_ci } 355362306a36Sopenharmony_ci }, 355462306a36Sopenharmony_ci .used_cqe_time_stamp_type = 1, 355562306a36Sopenharmony_ci .cqe_time_stamp_type = MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC, 355662306a36Sopenharmony_ci}; 355762306a36Sopenharmony_ci 355862306a36Sopenharmony_cistatic void 355962306a36Sopenharmony_cimlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core, 356062306a36Sopenharmony_ci struct devlink_resource_size_params *kvd_size_params, 356162306a36Sopenharmony_ci struct devlink_resource_size_params *linear_size_params, 356262306a36Sopenharmony_ci struct devlink_resource_size_params *hash_double_size_params, 356362306a36Sopenharmony_ci struct devlink_resource_size_params *hash_single_size_params) 356462306a36Sopenharmony_ci{ 356562306a36Sopenharmony_ci u32 single_size_min = MLXSW_CORE_RES_GET(mlxsw_core, 356662306a36Sopenharmony_ci KVD_SINGLE_MIN_SIZE); 356762306a36Sopenharmony_ci u32 double_size_min = MLXSW_CORE_RES_GET(mlxsw_core, 356862306a36Sopenharmony_ci KVD_DOUBLE_MIN_SIZE); 356962306a36Sopenharmony_ci u32 kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE); 357062306a36Sopenharmony_ci u32 linear_size_min = 0; 357162306a36Sopenharmony_ci 357262306a36Sopenharmony_ci devlink_resource_size_params_init(kvd_size_params, kvd_size, kvd_size, 357362306a36Sopenharmony_ci MLXSW_SP_KVD_GRANULARITY, 357462306a36Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 357562306a36Sopenharmony_ci devlink_resource_size_params_init(linear_size_params, linear_size_min, 357662306a36Sopenharmony_ci kvd_size - single_size_min - 357762306a36Sopenharmony_ci double_size_min, 357862306a36Sopenharmony_ci MLXSW_SP_KVD_GRANULARITY, 357962306a36Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 358062306a36Sopenharmony_ci devlink_resource_size_params_init(hash_double_size_params, 358162306a36Sopenharmony_ci double_size_min, 358262306a36Sopenharmony_ci kvd_size - single_size_min - 358362306a36Sopenharmony_ci linear_size_min, 358462306a36Sopenharmony_ci MLXSW_SP_KVD_GRANULARITY, 358562306a36Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 358662306a36Sopenharmony_ci devlink_resource_size_params_init(hash_single_size_params, 358762306a36Sopenharmony_ci single_size_min, 358862306a36Sopenharmony_ci kvd_size - double_size_min - 358962306a36Sopenharmony_ci linear_size_min, 359062306a36Sopenharmony_ci MLXSW_SP_KVD_GRANULARITY, 359162306a36Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 359262306a36Sopenharmony_ci} 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_cistatic int mlxsw_sp1_resources_kvd_register(struct mlxsw_core *mlxsw_core) 359562306a36Sopenharmony_ci{ 359662306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_core); 359762306a36Sopenharmony_ci struct devlink_resource_size_params hash_single_size_params; 359862306a36Sopenharmony_ci struct devlink_resource_size_params hash_double_size_params; 359962306a36Sopenharmony_ci struct devlink_resource_size_params linear_size_params; 360062306a36Sopenharmony_ci struct devlink_resource_size_params kvd_size_params; 360162306a36Sopenharmony_ci u32 kvd_size, single_size, double_size, linear_size; 360262306a36Sopenharmony_ci const struct mlxsw_config_profile *profile; 360362306a36Sopenharmony_ci int err; 360462306a36Sopenharmony_ci 360562306a36Sopenharmony_ci profile = &mlxsw_sp1_config_profile; 360662306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE)) 360762306a36Sopenharmony_ci return -EIO; 360862306a36Sopenharmony_ci 360962306a36Sopenharmony_ci mlxsw_sp_resource_size_params_prepare(mlxsw_core, &kvd_size_params, 361062306a36Sopenharmony_ci &linear_size_params, 361162306a36Sopenharmony_ci &hash_double_size_params, 361262306a36Sopenharmony_ci &hash_single_size_params); 361362306a36Sopenharmony_ci 361462306a36Sopenharmony_ci kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE); 361562306a36Sopenharmony_ci err = devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD, 361662306a36Sopenharmony_ci kvd_size, MLXSW_SP_RESOURCE_KVD, 361762306a36Sopenharmony_ci DEVLINK_RESOURCE_ID_PARENT_TOP, 361862306a36Sopenharmony_ci &kvd_size_params); 361962306a36Sopenharmony_ci if (err) 362062306a36Sopenharmony_ci return err; 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_ci linear_size = profile->kvd_linear_size; 362362306a36Sopenharmony_ci err = devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR, 362462306a36Sopenharmony_ci linear_size, 362562306a36Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_LINEAR, 362662306a36Sopenharmony_ci MLXSW_SP_RESOURCE_KVD, 362762306a36Sopenharmony_ci &linear_size_params); 362862306a36Sopenharmony_ci if (err) 362962306a36Sopenharmony_ci return err; 363062306a36Sopenharmony_ci 363162306a36Sopenharmony_ci err = mlxsw_sp1_kvdl_resources_register(mlxsw_core); 363262306a36Sopenharmony_ci if (err) 363362306a36Sopenharmony_ci return err; 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_ci double_size = kvd_size - linear_size; 363662306a36Sopenharmony_ci double_size *= profile->kvd_hash_double_parts; 363762306a36Sopenharmony_ci double_size /= profile->kvd_hash_double_parts + 363862306a36Sopenharmony_ci profile->kvd_hash_single_parts; 363962306a36Sopenharmony_ci double_size = rounddown(double_size, MLXSW_SP_KVD_GRANULARITY); 364062306a36Sopenharmony_ci err = devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_HASH_DOUBLE, 364162306a36Sopenharmony_ci double_size, 364262306a36Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, 364362306a36Sopenharmony_ci MLXSW_SP_RESOURCE_KVD, 364462306a36Sopenharmony_ci &hash_double_size_params); 364562306a36Sopenharmony_ci if (err) 364662306a36Sopenharmony_ci return err; 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ci single_size = kvd_size - double_size - linear_size; 364962306a36Sopenharmony_ci err = devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_HASH_SINGLE, 365062306a36Sopenharmony_ci single_size, 365162306a36Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, 365262306a36Sopenharmony_ci MLXSW_SP_RESOURCE_KVD, 365362306a36Sopenharmony_ci &hash_single_size_params); 365462306a36Sopenharmony_ci if (err) 365562306a36Sopenharmony_ci return err; 365662306a36Sopenharmony_ci 365762306a36Sopenharmony_ci return 0; 365862306a36Sopenharmony_ci} 365962306a36Sopenharmony_ci 366062306a36Sopenharmony_cistatic int mlxsw_sp2_resources_kvd_register(struct mlxsw_core *mlxsw_core) 366162306a36Sopenharmony_ci{ 366262306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_core); 366362306a36Sopenharmony_ci struct devlink_resource_size_params kvd_size_params; 366462306a36Sopenharmony_ci u32 kvd_size; 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE)) 366762306a36Sopenharmony_ci return -EIO; 366862306a36Sopenharmony_ci 366962306a36Sopenharmony_ci kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE); 367062306a36Sopenharmony_ci devlink_resource_size_params_init(&kvd_size_params, kvd_size, kvd_size, 367162306a36Sopenharmony_ci MLXSW_SP_KVD_GRANULARITY, 367262306a36Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 367362306a36Sopenharmony_ci 367462306a36Sopenharmony_ci return devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD, 367562306a36Sopenharmony_ci kvd_size, MLXSW_SP_RESOURCE_KVD, 367662306a36Sopenharmony_ci DEVLINK_RESOURCE_ID_PARENT_TOP, 367762306a36Sopenharmony_ci &kvd_size_params); 367862306a36Sopenharmony_ci} 367962306a36Sopenharmony_ci 368062306a36Sopenharmony_cistatic int mlxsw_sp_resources_span_register(struct mlxsw_core *mlxsw_core) 368162306a36Sopenharmony_ci{ 368262306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_core); 368362306a36Sopenharmony_ci struct devlink_resource_size_params span_size_params; 368462306a36Sopenharmony_ci u32 max_span; 368562306a36Sopenharmony_ci 368662306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SPAN)) 368762306a36Sopenharmony_ci return -EIO; 368862306a36Sopenharmony_ci 368962306a36Sopenharmony_ci max_span = MLXSW_CORE_RES_GET(mlxsw_core, MAX_SPAN); 369062306a36Sopenharmony_ci devlink_resource_size_params_init(&span_size_params, max_span, max_span, 369162306a36Sopenharmony_ci 1, DEVLINK_RESOURCE_UNIT_ENTRY); 369262306a36Sopenharmony_ci 369362306a36Sopenharmony_ci return devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_SPAN, 369462306a36Sopenharmony_ci max_span, MLXSW_SP_RESOURCE_SPAN, 369562306a36Sopenharmony_ci DEVLINK_RESOURCE_ID_PARENT_TOP, 369662306a36Sopenharmony_ci &span_size_params); 369762306a36Sopenharmony_ci} 369862306a36Sopenharmony_ci 369962306a36Sopenharmony_cistatic int 370062306a36Sopenharmony_cimlxsw_sp_resources_rif_mac_profile_register(struct mlxsw_core *mlxsw_core) 370162306a36Sopenharmony_ci{ 370262306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_core); 370362306a36Sopenharmony_ci struct devlink_resource_size_params size_params; 370462306a36Sopenharmony_ci u8 max_rif_mac_profiles; 370562306a36Sopenharmony_ci 370662306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_RIF_MAC_PROFILES)) 370762306a36Sopenharmony_ci max_rif_mac_profiles = 1; 370862306a36Sopenharmony_ci else 370962306a36Sopenharmony_ci max_rif_mac_profiles = MLXSW_CORE_RES_GET(mlxsw_core, 371062306a36Sopenharmony_ci MAX_RIF_MAC_PROFILES); 371162306a36Sopenharmony_ci devlink_resource_size_params_init(&size_params, max_rif_mac_profiles, 371262306a36Sopenharmony_ci max_rif_mac_profiles, 1, 371362306a36Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 371462306a36Sopenharmony_ci 371562306a36Sopenharmony_ci return devl_resource_register(devlink, 371662306a36Sopenharmony_ci "rif_mac_profiles", 371762306a36Sopenharmony_ci max_rif_mac_profiles, 371862306a36Sopenharmony_ci MLXSW_SP_RESOURCE_RIF_MAC_PROFILES, 371962306a36Sopenharmony_ci DEVLINK_RESOURCE_ID_PARENT_TOP, 372062306a36Sopenharmony_ci &size_params); 372162306a36Sopenharmony_ci} 372262306a36Sopenharmony_ci 372362306a36Sopenharmony_cistatic int mlxsw_sp_resources_rifs_register(struct mlxsw_core *mlxsw_core) 372462306a36Sopenharmony_ci{ 372562306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_core); 372662306a36Sopenharmony_ci struct devlink_resource_size_params size_params; 372762306a36Sopenharmony_ci u64 max_rifs; 372862306a36Sopenharmony_ci 372962306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_RIFS)) 373062306a36Sopenharmony_ci return -EIO; 373162306a36Sopenharmony_ci 373262306a36Sopenharmony_ci max_rifs = MLXSW_CORE_RES_GET(mlxsw_core, MAX_RIFS); 373362306a36Sopenharmony_ci devlink_resource_size_params_init(&size_params, max_rifs, max_rifs, 373462306a36Sopenharmony_ci 1, DEVLINK_RESOURCE_UNIT_ENTRY); 373562306a36Sopenharmony_ci 373662306a36Sopenharmony_ci return devl_resource_register(devlink, "rifs", max_rifs, 373762306a36Sopenharmony_ci MLXSW_SP_RESOURCE_RIFS, 373862306a36Sopenharmony_ci DEVLINK_RESOURCE_ID_PARENT_TOP, 373962306a36Sopenharmony_ci &size_params); 374062306a36Sopenharmony_ci} 374162306a36Sopenharmony_ci 374262306a36Sopenharmony_cistatic int 374362306a36Sopenharmony_cimlxsw_sp_resources_port_range_register(struct mlxsw_core *mlxsw_core) 374462306a36Sopenharmony_ci{ 374562306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_core); 374662306a36Sopenharmony_ci struct devlink_resource_size_params size_params; 374762306a36Sopenharmony_ci u64 max; 374862306a36Sopenharmony_ci 374962306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, ACL_MAX_L4_PORT_RANGE)) 375062306a36Sopenharmony_ci return -EIO; 375162306a36Sopenharmony_ci 375262306a36Sopenharmony_ci max = MLXSW_CORE_RES_GET(mlxsw_core, ACL_MAX_L4_PORT_RANGE); 375362306a36Sopenharmony_ci devlink_resource_size_params_init(&size_params, max, max, 1, 375462306a36Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 375562306a36Sopenharmony_ci 375662306a36Sopenharmony_ci return devl_resource_register(devlink, "port_range_registers", max, 375762306a36Sopenharmony_ci MLXSW_SP_RESOURCE_PORT_RANGE_REGISTERS, 375862306a36Sopenharmony_ci DEVLINK_RESOURCE_ID_PARENT_TOP, 375962306a36Sopenharmony_ci &size_params); 376062306a36Sopenharmony_ci} 376162306a36Sopenharmony_ci 376262306a36Sopenharmony_cistatic int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core) 376362306a36Sopenharmony_ci{ 376462306a36Sopenharmony_ci int err; 376562306a36Sopenharmony_ci 376662306a36Sopenharmony_ci err = mlxsw_sp1_resources_kvd_register(mlxsw_core); 376762306a36Sopenharmony_ci if (err) 376862306a36Sopenharmony_ci return err; 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_ci err = mlxsw_sp_resources_span_register(mlxsw_core); 377162306a36Sopenharmony_ci if (err) 377262306a36Sopenharmony_ci goto err_resources_span_register; 377362306a36Sopenharmony_ci 377462306a36Sopenharmony_ci err = mlxsw_sp_counter_resources_register(mlxsw_core); 377562306a36Sopenharmony_ci if (err) 377662306a36Sopenharmony_ci goto err_resources_counter_register; 377762306a36Sopenharmony_ci 377862306a36Sopenharmony_ci err = mlxsw_sp_policer_resources_register(mlxsw_core); 377962306a36Sopenharmony_ci if (err) 378062306a36Sopenharmony_ci goto err_policer_resources_register; 378162306a36Sopenharmony_ci 378262306a36Sopenharmony_ci err = mlxsw_sp_resources_rif_mac_profile_register(mlxsw_core); 378362306a36Sopenharmony_ci if (err) 378462306a36Sopenharmony_ci goto err_resources_rif_mac_profile_register; 378562306a36Sopenharmony_ci 378662306a36Sopenharmony_ci err = mlxsw_sp_resources_rifs_register(mlxsw_core); 378762306a36Sopenharmony_ci if (err) 378862306a36Sopenharmony_ci goto err_resources_rifs_register; 378962306a36Sopenharmony_ci 379062306a36Sopenharmony_ci err = mlxsw_sp_resources_port_range_register(mlxsw_core); 379162306a36Sopenharmony_ci if (err) 379262306a36Sopenharmony_ci goto err_resources_port_range_register; 379362306a36Sopenharmony_ci 379462306a36Sopenharmony_ci return 0; 379562306a36Sopenharmony_ci 379662306a36Sopenharmony_cierr_resources_port_range_register: 379762306a36Sopenharmony_cierr_resources_rifs_register: 379862306a36Sopenharmony_cierr_resources_rif_mac_profile_register: 379962306a36Sopenharmony_cierr_policer_resources_register: 380062306a36Sopenharmony_cierr_resources_counter_register: 380162306a36Sopenharmony_cierr_resources_span_register: 380262306a36Sopenharmony_ci devl_resources_unregister(priv_to_devlink(mlxsw_core)); 380362306a36Sopenharmony_ci return err; 380462306a36Sopenharmony_ci} 380562306a36Sopenharmony_ci 380662306a36Sopenharmony_cistatic int mlxsw_sp2_resources_register(struct mlxsw_core *mlxsw_core) 380762306a36Sopenharmony_ci{ 380862306a36Sopenharmony_ci int err; 380962306a36Sopenharmony_ci 381062306a36Sopenharmony_ci err = mlxsw_sp2_resources_kvd_register(mlxsw_core); 381162306a36Sopenharmony_ci if (err) 381262306a36Sopenharmony_ci return err; 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci err = mlxsw_sp_resources_span_register(mlxsw_core); 381562306a36Sopenharmony_ci if (err) 381662306a36Sopenharmony_ci goto err_resources_span_register; 381762306a36Sopenharmony_ci 381862306a36Sopenharmony_ci err = mlxsw_sp_counter_resources_register(mlxsw_core); 381962306a36Sopenharmony_ci if (err) 382062306a36Sopenharmony_ci goto err_resources_counter_register; 382162306a36Sopenharmony_ci 382262306a36Sopenharmony_ci err = mlxsw_sp_policer_resources_register(mlxsw_core); 382362306a36Sopenharmony_ci if (err) 382462306a36Sopenharmony_ci goto err_policer_resources_register; 382562306a36Sopenharmony_ci 382662306a36Sopenharmony_ci err = mlxsw_sp_resources_rif_mac_profile_register(mlxsw_core); 382762306a36Sopenharmony_ci if (err) 382862306a36Sopenharmony_ci goto err_resources_rif_mac_profile_register; 382962306a36Sopenharmony_ci 383062306a36Sopenharmony_ci err = mlxsw_sp_resources_rifs_register(mlxsw_core); 383162306a36Sopenharmony_ci if (err) 383262306a36Sopenharmony_ci goto err_resources_rifs_register; 383362306a36Sopenharmony_ci 383462306a36Sopenharmony_ci err = mlxsw_sp_resources_port_range_register(mlxsw_core); 383562306a36Sopenharmony_ci if (err) 383662306a36Sopenharmony_ci goto err_resources_port_range_register; 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_ci return 0; 383962306a36Sopenharmony_ci 384062306a36Sopenharmony_cierr_resources_port_range_register: 384162306a36Sopenharmony_cierr_resources_rifs_register: 384262306a36Sopenharmony_cierr_resources_rif_mac_profile_register: 384362306a36Sopenharmony_cierr_policer_resources_register: 384462306a36Sopenharmony_cierr_resources_counter_register: 384562306a36Sopenharmony_cierr_resources_span_register: 384662306a36Sopenharmony_ci devl_resources_unregister(priv_to_devlink(mlxsw_core)); 384762306a36Sopenharmony_ci return err; 384862306a36Sopenharmony_ci} 384962306a36Sopenharmony_ci 385062306a36Sopenharmony_cistatic int mlxsw_sp_kvd_sizes_get(struct mlxsw_core *mlxsw_core, 385162306a36Sopenharmony_ci const struct mlxsw_config_profile *profile, 385262306a36Sopenharmony_ci u64 *p_single_size, u64 *p_double_size, 385362306a36Sopenharmony_ci u64 *p_linear_size) 385462306a36Sopenharmony_ci{ 385562306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_core); 385662306a36Sopenharmony_ci u32 double_size; 385762306a36Sopenharmony_ci int err; 385862306a36Sopenharmony_ci 385962306a36Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SINGLE_MIN_SIZE) || 386062306a36Sopenharmony_ci !MLXSW_CORE_RES_VALID(mlxsw_core, KVD_DOUBLE_MIN_SIZE)) 386162306a36Sopenharmony_ci return -EIO; 386262306a36Sopenharmony_ci 386362306a36Sopenharmony_ci /* The hash part is what left of the kvd without the 386462306a36Sopenharmony_ci * linear part. It is split to the single size and 386562306a36Sopenharmony_ci * double size by the parts ratio from the profile. 386662306a36Sopenharmony_ci * Both sizes must be a multiplications of the 386762306a36Sopenharmony_ci * granularity from the profile. In case the user 386862306a36Sopenharmony_ci * provided the sizes they are obtained via devlink. 386962306a36Sopenharmony_ci */ 387062306a36Sopenharmony_ci err = devl_resource_size_get(devlink, 387162306a36Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_LINEAR, 387262306a36Sopenharmony_ci p_linear_size); 387362306a36Sopenharmony_ci if (err) 387462306a36Sopenharmony_ci *p_linear_size = profile->kvd_linear_size; 387562306a36Sopenharmony_ci 387662306a36Sopenharmony_ci err = devl_resource_size_get(devlink, 387762306a36Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE, 387862306a36Sopenharmony_ci p_double_size); 387962306a36Sopenharmony_ci if (err) { 388062306a36Sopenharmony_ci double_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) - 388162306a36Sopenharmony_ci *p_linear_size; 388262306a36Sopenharmony_ci double_size *= profile->kvd_hash_double_parts; 388362306a36Sopenharmony_ci double_size /= profile->kvd_hash_double_parts + 388462306a36Sopenharmony_ci profile->kvd_hash_single_parts; 388562306a36Sopenharmony_ci *p_double_size = rounddown(double_size, 388662306a36Sopenharmony_ci MLXSW_SP_KVD_GRANULARITY); 388762306a36Sopenharmony_ci } 388862306a36Sopenharmony_ci 388962306a36Sopenharmony_ci err = devl_resource_size_get(devlink, 389062306a36Sopenharmony_ci MLXSW_SP_RESOURCE_KVD_HASH_SINGLE, 389162306a36Sopenharmony_ci p_single_size); 389262306a36Sopenharmony_ci if (err) 389362306a36Sopenharmony_ci *p_single_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) - 389462306a36Sopenharmony_ci *p_double_size - *p_linear_size; 389562306a36Sopenharmony_ci 389662306a36Sopenharmony_ci /* Check results are legal. */ 389762306a36Sopenharmony_ci if (*p_single_size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE) || 389862306a36Sopenharmony_ci *p_double_size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_DOUBLE_MIN_SIZE) || 389962306a36Sopenharmony_ci MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) < *p_linear_size) 390062306a36Sopenharmony_ci return -EIO; 390162306a36Sopenharmony_ci 390262306a36Sopenharmony_ci return 0; 390362306a36Sopenharmony_ci} 390462306a36Sopenharmony_ci 390562306a36Sopenharmony_cistatic void mlxsw_sp_ptp_transmitted(struct mlxsw_core *mlxsw_core, 390662306a36Sopenharmony_ci struct sk_buff *skb, u16 local_port) 390762306a36Sopenharmony_ci{ 390862306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); 390962306a36Sopenharmony_ci 391062306a36Sopenharmony_ci skb_pull(skb, MLXSW_TXHDR_LEN); 391162306a36Sopenharmony_ci mlxsw_sp->ptp_ops->transmitted(mlxsw_sp, skb, local_port); 391262306a36Sopenharmony_ci} 391362306a36Sopenharmony_ci 391462306a36Sopenharmony_cistatic struct mlxsw_driver mlxsw_sp1_driver = { 391562306a36Sopenharmony_ci .kind = mlxsw_sp1_driver_name, 391662306a36Sopenharmony_ci .priv_size = sizeof(struct mlxsw_sp), 391762306a36Sopenharmony_ci .fw_req_rev = &mlxsw_sp1_fw_rev, 391862306a36Sopenharmony_ci .fw_filename = MLXSW_SP1_FW_FILENAME, 391962306a36Sopenharmony_ci .init = mlxsw_sp1_init, 392062306a36Sopenharmony_ci .fini = mlxsw_sp_fini, 392162306a36Sopenharmony_ci .port_split = mlxsw_sp_port_split, 392262306a36Sopenharmony_ci .port_unsplit = mlxsw_sp_port_unsplit, 392362306a36Sopenharmony_ci .sb_pool_get = mlxsw_sp_sb_pool_get, 392462306a36Sopenharmony_ci .sb_pool_set = mlxsw_sp_sb_pool_set, 392562306a36Sopenharmony_ci .sb_port_pool_get = mlxsw_sp_sb_port_pool_get, 392662306a36Sopenharmony_ci .sb_port_pool_set = mlxsw_sp_sb_port_pool_set, 392762306a36Sopenharmony_ci .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get, 392862306a36Sopenharmony_ci .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set, 392962306a36Sopenharmony_ci .sb_occ_snapshot = mlxsw_sp_sb_occ_snapshot, 393062306a36Sopenharmony_ci .sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear, 393162306a36Sopenharmony_ci .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get, 393262306a36Sopenharmony_ci .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get, 393362306a36Sopenharmony_ci .trap_init = mlxsw_sp_trap_init, 393462306a36Sopenharmony_ci .trap_fini = mlxsw_sp_trap_fini, 393562306a36Sopenharmony_ci .trap_action_set = mlxsw_sp_trap_action_set, 393662306a36Sopenharmony_ci .trap_group_init = mlxsw_sp_trap_group_init, 393762306a36Sopenharmony_ci .trap_group_set = mlxsw_sp_trap_group_set, 393862306a36Sopenharmony_ci .trap_policer_init = mlxsw_sp_trap_policer_init, 393962306a36Sopenharmony_ci .trap_policer_fini = mlxsw_sp_trap_policer_fini, 394062306a36Sopenharmony_ci .trap_policer_set = mlxsw_sp_trap_policer_set, 394162306a36Sopenharmony_ci .trap_policer_counter_get = mlxsw_sp_trap_policer_counter_get, 394262306a36Sopenharmony_ci .txhdr_construct = mlxsw_sp_txhdr_construct, 394362306a36Sopenharmony_ci .resources_register = mlxsw_sp1_resources_register, 394462306a36Sopenharmony_ci .kvd_sizes_get = mlxsw_sp_kvd_sizes_get, 394562306a36Sopenharmony_ci .ptp_transmitted = mlxsw_sp_ptp_transmitted, 394662306a36Sopenharmony_ci .txhdr_len = MLXSW_TXHDR_LEN, 394762306a36Sopenharmony_ci .profile = &mlxsw_sp1_config_profile, 394862306a36Sopenharmony_ci .sdq_supports_cqe_v2 = false, 394962306a36Sopenharmony_ci}; 395062306a36Sopenharmony_ci 395162306a36Sopenharmony_cistatic struct mlxsw_driver mlxsw_sp2_driver = { 395262306a36Sopenharmony_ci .kind = mlxsw_sp2_driver_name, 395362306a36Sopenharmony_ci .priv_size = sizeof(struct mlxsw_sp), 395462306a36Sopenharmony_ci .fw_req_rev = &mlxsw_sp2_fw_rev, 395562306a36Sopenharmony_ci .fw_filename = MLXSW_SP2_FW_FILENAME, 395662306a36Sopenharmony_ci .init = mlxsw_sp2_init, 395762306a36Sopenharmony_ci .fini = mlxsw_sp_fini, 395862306a36Sopenharmony_ci .port_split = mlxsw_sp_port_split, 395962306a36Sopenharmony_ci .port_unsplit = mlxsw_sp_port_unsplit, 396062306a36Sopenharmony_ci .ports_remove_selected = mlxsw_sp_ports_remove_selected, 396162306a36Sopenharmony_ci .sb_pool_get = mlxsw_sp_sb_pool_get, 396262306a36Sopenharmony_ci .sb_pool_set = mlxsw_sp_sb_pool_set, 396362306a36Sopenharmony_ci .sb_port_pool_get = mlxsw_sp_sb_port_pool_get, 396462306a36Sopenharmony_ci .sb_port_pool_set = mlxsw_sp_sb_port_pool_set, 396562306a36Sopenharmony_ci .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get, 396662306a36Sopenharmony_ci .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set, 396762306a36Sopenharmony_ci .sb_occ_snapshot = mlxsw_sp_sb_occ_snapshot, 396862306a36Sopenharmony_ci .sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear, 396962306a36Sopenharmony_ci .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get, 397062306a36Sopenharmony_ci .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get, 397162306a36Sopenharmony_ci .trap_init = mlxsw_sp_trap_init, 397262306a36Sopenharmony_ci .trap_fini = mlxsw_sp_trap_fini, 397362306a36Sopenharmony_ci .trap_action_set = mlxsw_sp_trap_action_set, 397462306a36Sopenharmony_ci .trap_group_init = mlxsw_sp_trap_group_init, 397562306a36Sopenharmony_ci .trap_group_set = mlxsw_sp_trap_group_set, 397662306a36Sopenharmony_ci .trap_policer_init = mlxsw_sp_trap_policer_init, 397762306a36Sopenharmony_ci .trap_policer_fini = mlxsw_sp_trap_policer_fini, 397862306a36Sopenharmony_ci .trap_policer_set = mlxsw_sp_trap_policer_set, 397962306a36Sopenharmony_ci .trap_policer_counter_get = mlxsw_sp_trap_policer_counter_get, 398062306a36Sopenharmony_ci .txhdr_construct = mlxsw_sp_txhdr_construct, 398162306a36Sopenharmony_ci .resources_register = mlxsw_sp2_resources_register, 398262306a36Sopenharmony_ci .ptp_transmitted = mlxsw_sp_ptp_transmitted, 398362306a36Sopenharmony_ci .txhdr_len = MLXSW_TXHDR_LEN, 398462306a36Sopenharmony_ci .profile = &mlxsw_sp2_config_profile, 398562306a36Sopenharmony_ci .sdq_supports_cqe_v2 = true, 398662306a36Sopenharmony_ci}; 398762306a36Sopenharmony_ci 398862306a36Sopenharmony_cistatic struct mlxsw_driver mlxsw_sp3_driver = { 398962306a36Sopenharmony_ci .kind = mlxsw_sp3_driver_name, 399062306a36Sopenharmony_ci .priv_size = sizeof(struct mlxsw_sp), 399162306a36Sopenharmony_ci .fw_req_rev = &mlxsw_sp3_fw_rev, 399262306a36Sopenharmony_ci .fw_filename = MLXSW_SP3_FW_FILENAME, 399362306a36Sopenharmony_ci .init = mlxsw_sp3_init, 399462306a36Sopenharmony_ci .fini = mlxsw_sp_fini, 399562306a36Sopenharmony_ci .port_split = mlxsw_sp_port_split, 399662306a36Sopenharmony_ci .port_unsplit = mlxsw_sp_port_unsplit, 399762306a36Sopenharmony_ci .ports_remove_selected = mlxsw_sp_ports_remove_selected, 399862306a36Sopenharmony_ci .sb_pool_get = mlxsw_sp_sb_pool_get, 399962306a36Sopenharmony_ci .sb_pool_set = mlxsw_sp_sb_pool_set, 400062306a36Sopenharmony_ci .sb_port_pool_get = mlxsw_sp_sb_port_pool_get, 400162306a36Sopenharmony_ci .sb_port_pool_set = mlxsw_sp_sb_port_pool_set, 400262306a36Sopenharmony_ci .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get, 400362306a36Sopenharmony_ci .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set, 400462306a36Sopenharmony_ci .sb_occ_snapshot = mlxsw_sp_sb_occ_snapshot, 400562306a36Sopenharmony_ci .sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear, 400662306a36Sopenharmony_ci .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get, 400762306a36Sopenharmony_ci .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get, 400862306a36Sopenharmony_ci .trap_init = mlxsw_sp_trap_init, 400962306a36Sopenharmony_ci .trap_fini = mlxsw_sp_trap_fini, 401062306a36Sopenharmony_ci .trap_action_set = mlxsw_sp_trap_action_set, 401162306a36Sopenharmony_ci .trap_group_init = mlxsw_sp_trap_group_init, 401262306a36Sopenharmony_ci .trap_group_set = mlxsw_sp_trap_group_set, 401362306a36Sopenharmony_ci .trap_policer_init = mlxsw_sp_trap_policer_init, 401462306a36Sopenharmony_ci .trap_policer_fini = mlxsw_sp_trap_policer_fini, 401562306a36Sopenharmony_ci .trap_policer_set = mlxsw_sp_trap_policer_set, 401662306a36Sopenharmony_ci .trap_policer_counter_get = mlxsw_sp_trap_policer_counter_get, 401762306a36Sopenharmony_ci .txhdr_construct = mlxsw_sp_txhdr_construct, 401862306a36Sopenharmony_ci .resources_register = mlxsw_sp2_resources_register, 401962306a36Sopenharmony_ci .ptp_transmitted = mlxsw_sp_ptp_transmitted, 402062306a36Sopenharmony_ci .txhdr_len = MLXSW_TXHDR_LEN, 402162306a36Sopenharmony_ci .profile = &mlxsw_sp2_config_profile, 402262306a36Sopenharmony_ci .sdq_supports_cqe_v2 = true, 402362306a36Sopenharmony_ci}; 402462306a36Sopenharmony_ci 402562306a36Sopenharmony_cistatic struct mlxsw_driver mlxsw_sp4_driver = { 402662306a36Sopenharmony_ci .kind = mlxsw_sp4_driver_name, 402762306a36Sopenharmony_ci .priv_size = sizeof(struct mlxsw_sp), 402862306a36Sopenharmony_ci .init = mlxsw_sp4_init, 402962306a36Sopenharmony_ci .fini = mlxsw_sp_fini, 403062306a36Sopenharmony_ci .port_split = mlxsw_sp_port_split, 403162306a36Sopenharmony_ci .port_unsplit = mlxsw_sp_port_unsplit, 403262306a36Sopenharmony_ci .ports_remove_selected = mlxsw_sp_ports_remove_selected, 403362306a36Sopenharmony_ci .sb_pool_get = mlxsw_sp_sb_pool_get, 403462306a36Sopenharmony_ci .sb_pool_set = mlxsw_sp_sb_pool_set, 403562306a36Sopenharmony_ci .sb_port_pool_get = mlxsw_sp_sb_port_pool_get, 403662306a36Sopenharmony_ci .sb_port_pool_set = mlxsw_sp_sb_port_pool_set, 403762306a36Sopenharmony_ci .sb_tc_pool_bind_get = mlxsw_sp_sb_tc_pool_bind_get, 403862306a36Sopenharmony_ci .sb_tc_pool_bind_set = mlxsw_sp_sb_tc_pool_bind_set, 403962306a36Sopenharmony_ci .sb_occ_snapshot = mlxsw_sp_sb_occ_snapshot, 404062306a36Sopenharmony_ci .sb_occ_max_clear = mlxsw_sp_sb_occ_max_clear, 404162306a36Sopenharmony_ci .sb_occ_port_pool_get = mlxsw_sp_sb_occ_port_pool_get, 404262306a36Sopenharmony_ci .sb_occ_tc_port_bind_get = mlxsw_sp_sb_occ_tc_port_bind_get, 404362306a36Sopenharmony_ci .trap_init = mlxsw_sp_trap_init, 404462306a36Sopenharmony_ci .trap_fini = mlxsw_sp_trap_fini, 404562306a36Sopenharmony_ci .trap_action_set = mlxsw_sp_trap_action_set, 404662306a36Sopenharmony_ci .trap_group_init = mlxsw_sp_trap_group_init, 404762306a36Sopenharmony_ci .trap_group_set = mlxsw_sp_trap_group_set, 404862306a36Sopenharmony_ci .trap_policer_init = mlxsw_sp_trap_policer_init, 404962306a36Sopenharmony_ci .trap_policer_fini = mlxsw_sp_trap_policer_fini, 405062306a36Sopenharmony_ci .trap_policer_set = mlxsw_sp_trap_policer_set, 405162306a36Sopenharmony_ci .trap_policer_counter_get = mlxsw_sp_trap_policer_counter_get, 405262306a36Sopenharmony_ci .txhdr_construct = mlxsw_sp_txhdr_construct, 405362306a36Sopenharmony_ci .resources_register = mlxsw_sp2_resources_register, 405462306a36Sopenharmony_ci .ptp_transmitted = mlxsw_sp_ptp_transmitted, 405562306a36Sopenharmony_ci .txhdr_len = MLXSW_TXHDR_LEN, 405662306a36Sopenharmony_ci .profile = &mlxsw_sp4_config_profile, 405762306a36Sopenharmony_ci .sdq_supports_cqe_v2 = true, 405862306a36Sopenharmony_ci}; 405962306a36Sopenharmony_ci 406062306a36Sopenharmony_cibool mlxsw_sp_port_dev_check(const struct net_device *dev) 406162306a36Sopenharmony_ci{ 406262306a36Sopenharmony_ci return dev->netdev_ops == &mlxsw_sp_port_netdev_ops; 406362306a36Sopenharmony_ci} 406462306a36Sopenharmony_ci 406562306a36Sopenharmony_cistatic int mlxsw_sp_lower_dev_walk(struct net_device *lower_dev, 406662306a36Sopenharmony_ci struct netdev_nested_priv *priv) 406762306a36Sopenharmony_ci{ 406862306a36Sopenharmony_ci int ret = 0; 406962306a36Sopenharmony_ci 407062306a36Sopenharmony_ci if (mlxsw_sp_port_dev_check(lower_dev)) { 407162306a36Sopenharmony_ci priv->data = (void *)netdev_priv(lower_dev); 407262306a36Sopenharmony_ci ret = 1; 407362306a36Sopenharmony_ci } 407462306a36Sopenharmony_ci 407562306a36Sopenharmony_ci return ret; 407662306a36Sopenharmony_ci} 407762306a36Sopenharmony_ci 407862306a36Sopenharmony_cistruct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev) 407962306a36Sopenharmony_ci{ 408062306a36Sopenharmony_ci struct netdev_nested_priv priv = { 408162306a36Sopenharmony_ci .data = NULL, 408262306a36Sopenharmony_ci }; 408362306a36Sopenharmony_ci 408462306a36Sopenharmony_ci if (mlxsw_sp_port_dev_check(dev)) 408562306a36Sopenharmony_ci return netdev_priv(dev); 408662306a36Sopenharmony_ci 408762306a36Sopenharmony_ci netdev_walk_all_lower_dev(dev, mlxsw_sp_lower_dev_walk, &priv); 408862306a36Sopenharmony_ci 408962306a36Sopenharmony_ci return (struct mlxsw_sp_port *)priv.data; 409062306a36Sopenharmony_ci} 409162306a36Sopenharmony_ci 409262306a36Sopenharmony_cistruct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev) 409362306a36Sopenharmony_ci{ 409462306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 409562306a36Sopenharmony_ci 409662306a36Sopenharmony_ci mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev); 409762306a36Sopenharmony_ci return mlxsw_sp_port ? mlxsw_sp_port->mlxsw_sp : NULL; 409862306a36Sopenharmony_ci} 409962306a36Sopenharmony_ci 410062306a36Sopenharmony_cistruct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev) 410162306a36Sopenharmony_ci{ 410262306a36Sopenharmony_ci struct netdev_nested_priv priv = { 410362306a36Sopenharmony_ci .data = NULL, 410462306a36Sopenharmony_ci }; 410562306a36Sopenharmony_ci 410662306a36Sopenharmony_ci if (mlxsw_sp_port_dev_check(dev)) 410762306a36Sopenharmony_ci return netdev_priv(dev); 410862306a36Sopenharmony_ci 410962306a36Sopenharmony_ci netdev_walk_all_lower_dev_rcu(dev, mlxsw_sp_lower_dev_walk, 411062306a36Sopenharmony_ci &priv); 411162306a36Sopenharmony_ci 411262306a36Sopenharmony_ci return (struct mlxsw_sp_port *)priv.data; 411362306a36Sopenharmony_ci} 411462306a36Sopenharmony_ci 411562306a36Sopenharmony_ciint mlxsw_sp_parsing_depth_inc(struct mlxsw_sp *mlxsw_sp) 411662306a36Sopenharmony_ci{ 411762306a36Sopenharmony_ci char mprs_pl[MLXSW_REG_MPRS_LEN]; 411862306a36Sopenharmony_ci int err = 0; 411962306a36Sopenharmony_ci 412062306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->parsing.lock); 412162306a36Sopenharmony_ci 412262306a36Sopenharmony_ci if (refcount_inc_not_zero(&mlxsw_sp->parsing.parsing_depth_ref)) 412362306a36Sopenharmony_ci goto out_unlock; 412462306a36Sopenharmony_ci 412562306a36Sopenharmony_ci mlxsw_reg_mprs_pack(mprs_pl, MLXSW_SP_INCREASED_PARSING_DEPTH, 412662306a36Sopenharmony_ci mlxsw_sp->parsing.vxlan_udp_dport); 412762306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl); 412862306a36Sopenharmony_ci if (err) 412962306a36Sopenharmony_ci goto out_unlock; 413062306a36Sopenharmony_ci 413162306a36Sopenharmony_ci mlxsw_sp->parsing.parsing_depth = MLXSW_SP_INCREASED_PARSING_DEPTH; 413262306a36Sopenharmony_ci refcount_set(&mlxsw_sp->parsing.parsing_depth_ref, 1); 413362306a36Sopenharmony_ci 413462306a36Sopenharmony_ciout_unlock: 413562306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->parsing.lock); 413662306a36Sopenharmony_ci return err; 413762306a36Sopenharmony_ci} 413862306a36Sopenharmony_ci 413962306a36Sopenharmony_civoid mlxsw_sp_parsing_depth_dec(struct mlxsw_sp *mlxsw_sp) 414062306a36Sopenharmony_ci{ 414162306a36Sopenharmony_ci char mprs_pl[MLXSW_REG_MPRS_LEN]; 414262306a36Sopenharmony_ci 414362306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->parsing.lock); 414462306a36Sopenharmony_ci 414562306a36Sopenharmony_ci if (!refcount_dec_and_test(&mlxsw_sp->parsing.parsing_depth_ref)) 414662306a36Sopenharmony_ci goto out_unlock; 414762306a36Sopenharmony_ci 414862306a36Sopenharmony_ci mlxsw_reg_mprs_pack(mprs_pl, MLXSW_SP_DEFAULT_PARSING_DEPTH, 414962306a36Sopenharmony_ci mlxsw_sp->parsing.vxlan_udp_dport); 415062306a36Sopenharmony_ci mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl); 415162306a36Sopenharmony_ci mlxsw_sp->parsing.parsing_depth = MLXSW_SP_DEFAULT_PARSING_DEPTH; 415262306a36Sopenharmony_ci 415362306a36Sopenharmony_ciout_unlock: 415462306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->parsing.lock); 415562306a36Sopenharmony_ci} 415662306a36Sopenharmony_ci 415762306a36Sopenharmony_ciint mlxsw_sp_parsing_vxlan_udp_dport_set(struct mlxsw_sp *mlxsw_sp, 415862306a36Sopenharmony_ci __be16 udp_dport) 415962306a36Sopenharmony_ci{ 416062306a36Sopenharmony_ci char mprs_pl[MLXSW_REG_MPRS_LEN]; 416162306a36Sopenharmony_ci int err; 416262306a36Sopenharmony_ci 416362306a36Sopenharmony_ci mutex_lock(&mlxsw_sp->parsing.lock); 416462306a36Sopenharmony_ci 416562306a36Sopenharmony_ci mlxsw_reg_mprs_pack(mprs_pl, mlxsw_sp->parsing.parsing_depth, 416662306a36Sopenharmony_ci be16_to_cpu(udp_dport)); 416762306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl); 416862306a36Sopenharmony_ci if (err) 416962306a36Sopenharmony_ci goto out_unlock; 417062306a36Sopenharmony_ci 417162306a36Sopenharmony_ci mlxsw_sp->parsing.vxlan_udp_dport = be16_to_cpu(udp_dport); 417262306a36Sopenharmony_ci 417362306a36Sopenharmony_ciout_unlock: 417462306a36Sopenharmony_ci mutex_unlock(&mlxsw_sp->parsing.lock); 417562306a36Sopenharmony_ci return err; 417662306a36Sopenharmony_ci} 417762306a36Sopenharmony_ci 417862306a36Sopenharmony_cistatic void 417962306a36Sopenharmony_cimlxsw_sp_port_lag_uppers_cleanup(struct mlxsw_sp_port *mlxsw_sp_port, 418062306a36Sopenharmony_ci struct net_device *lag_dev) 418162306a36Sopenharmony_ci{ 418262306a36Sopenharmony_ci struct net_device *br_dev = netdev_master_upper_dev_get(lag_dev); 418362306a36Sopenharmony_ci struct net_device *upper_dev; 418462306a36Sopenharmony_ci struct list_head *iter; 418562306a36Sopenharmony_ci 418662306a36Sopenharmony_ci if (netif_is_bridge_port(lag_dev)) 418762306a36Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, br_dev); 418862306a36Sopenharmony_ci 418962306a36Sopenharmony_ci netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) { 419062306a36Sopenharmony_ci if (!netif_is_bridge_port(upper_dev)) 419162306a36Sopenharmony_ci continue; 419262306a36Sopenharmony_ci br_dev = netdev_master_upper_dev_get(upper_dev); 419362306a36Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, br_dev); 419462306a36Sopenharmony_ci } 419562306a36Sopenharmony_ci} 419662306a36Sopenharmony_ci 419762306a36Sopenharmony_cistatic int mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, u16 lag_id) 419862306a36Sopenharmony_ci{ 419962306a36Sopenharmony_ci char sldr_pl[MLXSW_REG_SLDR_LEN]; 420062306a36Sopenharmony_ci 420162306a36Sopenharmony_ci mlxsw_reg_sldr_lag_create_pack(sldr_pl, lag_id); 420262306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); 420362306a36Sopenharmony_ci} 420462306a36Sopenharmony_ci 420562306a36Sopenharmony_cistatic int mlxsw_sp_lag_destroy(struct mlxsw_sp *mlxsw_sp, u16 lag_id) 420662306a36Sopenharmony_ci{ 420762306a36Sopenharmony_ci char sldr_pl[MLXSW_REG_SLDR_LEN]; 420862306a36Sopenharmony_ci 420962306a36Sopenharmony_ci mlxsw_reg_sldr_lag_destroy_pack(sldr_pl, lag_id); 421062306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); 421162306a36Sopenharmony_ci} 421262306a36Sopenharmony_ci 421362306a36Sopenharmony_cistatic int mlxsw_sp_lag_col_port_add(struct mlxsw_sp_port *mlxsw_sp_port, 421462306a36Sopenharmony_ci u16 lag_id, u8 port_index) 421562306a36Sopenharmony_ci{ 421662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 421762306a36Sopenharmony_ci char slcor_pl[MLXSW_REG_SLCOR_LEN]; 421862306a36Sopenharmony_ci 421962306a36Sopenharmony_ci mlxsw_reg_slcor_port_add_pack(slcor_pl, mlxsw_sp_port->local_port, 422062306a36Sopenharmony_ci lag_id, port_index); 422162306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl); 422262306a36Sopenharmony_ci} 422362306a36Sopenharmony_ci 422462306a36Sopenharmony_cistatic int mlxsw_sp_lag_col_port_remove(struct mlxsw_sp_port *mlxsw_sp_port, 422562306a36Sopenharmony_ci u16 lag_id) 422662306a36Sopenharmony_ci{ 422762306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 422862306a36Sopenharmony_ci char slcor_pl[MLXSW_REG_SLCOR_LEN]; 422962306a36Sopenharmony_ci 423062306a36Sopenharmony_ci mlxsw_reg_slcor_port_remove_pack(slcor_pl, mlxsw_sp_port->local_port, 423162306a36Sopenharmony_ci lag_id); 423262306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl); 423362306a36Sopenharmony_ci} 423462306a36Sopenharmony_ci 423562306a36Sopenharmony_cistatic int mlxsw_sp_lag_col_port_enable(struct mlxsw_sp_port *mlxsw_sp_port, 423662306a36Sopenharmony_ci u16 lag_id) 423762306a36Sopenharmony_ci{ 423862306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 423962306a36Sopenharmony_ci char slcor_pl[MLXSW_REG_SLCOR_LEN]; 424062306a36Sopenharmony_ci 424162306a36Sopenharmony_ci mlxsw_reg_slcor_col_enable_pack(slcor_pl, mlxsw_sp_port->local_port, 424262306a36Sopenharmony_ci lag_id); 424362306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl); 424462306a36Sopenharmony_ci} 424562306a36Sopenharmony_ci 424662306a36Sopenharmony_cistatic int mlxsw_sp_lag_col_port_disable(struct mlxsw_sp_port *mlxsw_sp_port, 424762306a36Sopenharmony_ci u16 lag_id) 424862306a36Sopenharmony_ci{ 424962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 425062306a36Sopenharmony_ci char slcor_pl[MLXSW_REG_SLCOR_LEN]; 425162306a36Sopenharmony_ci 425262306a36Sopenharmony_ci mlxsw_reg_slcor_col_disable_pack(slcor_pl, mlxsw_sp_port->local_port, 425362306a36Sopenharmony_ci lag_id); 425462306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl); 425562306a36Sopenharmony_ci} 425662306a36Sopenharmony_ci 425762306a36Sopenharmony_cistatic int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp, 425862306a36Sopenharmony_ci struct net_device *lag_dev, 425962306a36Sopenharmony_ci u16 *p_lag_id) 426062306a36Sopenharmony_ci{ 426162306a36Sopenharmony_ci struct mlxsw_sp_upper *lag; 426262306a36Sopenharmony_ci int free_lag_id = -1; 426362306a36Sopenharmony_ci u16 max_lag; 426462306a36Sopenharmony_ci int err, i; 426562306a36Sopenharmony_ci 426662306a36Sopenharmony_ci err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag); 426762306a36Sopenharmony_ci if (err) 426862306a36Sopenharmony_ci return err; 426962306a36Sopenharmony_ci 427062306a36Sopenharmony_ci for (i = 0; i < max_lag; i++) { 427162306a36Sopenharmony_ci lag = mlxsw_sp_lag_get(mlxsw_sp, i); 427262306a36Sopenharmony_ci if (lag->ref_count) { 427362306a36Sopenharmony_ci if (lag->dev == lag_dev) { 427462306a36Sopenharmony_ci *p_lag_id = i; 427562306a36Sopenharmony_ci return 0; 427662306a36Sopenharmony_ci } 427762306a36Sopenharmony_ci } else if (free_lag_id < 0) { 427862306a36Sopenharmony_ci free_lag_id = i; 427962306a36Sopenharmony_ci } 428062306a36Sopenharmony_ci } 428162306a36Sopenharmony_ci if (free_lag_id < 0) 428262306a36Sopenharmony_ci return -EBUSY; 428362306a36Sopenharmony_ci *p_lag_id = free_lag_id; 428462306a36Sopenharmony_ci return 0; 428562306a36Sopenharmony_ci} 428662306a36Sopenharmony_ci 428762306a36Sopenharmony_cistatic bool 428862306a36Sopenharmony_cimlxsw_sp_master_lag_check(struct mlxsw_sp *mlxsw_sp, 428962306a36Sopenharmony_ci struct net_device *lag_dev, 429062306a36Sopenharmony_ci struct netdev_lag_upper_info *lag_upper_info, 429162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 429262306a36Sopenharmony_ci{ 429362306a36Sopenharmony_ci u16 lag_id; 429462306a36Sopenharmony_ci 429562306a36Sopenharmony_ci if (mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id) != 0) { 429662306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported LAG devices"); 429762306a36Sopenharmony_ci return false; 429862306a36Sopenharmony_ci } 429962306a36Sopenharmony_ci if (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) { 430062306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "LAG device using unsupported Tx type"); 430162306a36Sopenharmony_ci return false; 430262306a36Sopenharmony_ci } 430362306a36Sopenharmony_ci return true; 430462306a36Sopenharmony_ci} 430562306a36Sopenharmony_ci 430662306a36Sopenharmony_cistatic int mlxsw_sp_port_lag_index_get(struct mlxsw_sp *mlxsw_sp, 430762306a36Sopenharmony_ci u16 lag_id, u8 *p_port_index) 430862306a36Sopenharmony_ci{ 430962306a36Sopenharmony_ci u64 max_lag_members; 431062306a36Sopenharmony_ci int i; 431162306a36Sopenharmony_ci 431262306a36Sopenharmony_ci max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core, 431362306a36Sopenharmony_ci MAX_LAG_MEMBERS); 431462306a36Sopenharmony_ci for (i = 0; i < max_lag_members; i++) { 431562306a36Sopenharmony_ci if (!mlxsw_sp_port_lagged_get(mlxsw_sp, lag_id, i)) { 431662306a36Sopenharmony_ci *p_port_index = i; 431762306a36Sopenharmony_ci return 0; 431862306a36Sopenharmony_ci } 431962306a36Sopenharmony_ci } 432062306a36Sopenharmony_ci return -EBUSY; 432162306a36Sopenharmony_ci} 432262306a36Sopenharmony_ci 432362306a36Sopenharmony_cistatic int mlxsw_sp_lag_uppers_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, 432462306a36Sopenharmony_ci struct net_device *lag_dev, 432562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 432662306a36Sopenharmony_ci{ 432762306a36Sopenharmony_ci struct net_device *upper_dev; 432862306a36Sopenharmony_ci struct net_device *master; 432962306a36Sopenharmony_ci struct list_head *iter; 433062306a36Sopenharmony_ci int done = 0; 433162306a36Sopenharmony_ci int err; 433262306a36Sopenharmony_ci 433362306a36Sopenharmony_ci master = netdev_master_upper_dev_get(lag_dev); 433462306a36Sopenharmony_ci if (master && netif_is_bridge_master(master)) { 433562306a36Sopenharmony_ci err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, lag_dev, master, 433662306a36Sopenharmony_ci extack); 433762306a36Sopenharmony_ci if (err) 433862306a36Sopenharmony_ci return err; 433962306a36Sopenharmony_ci } 434062306a36Sopenharmony_ci 434162306a36Sopenharmony_ci netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) { 434262306a36Sopenharmony_ci if (!is_vlan_dev(upper_dev)) 434362306a36Sopenharmony_ci continue; 434462306a36Sopenharmony_ci 434562306a36Sopenharmony_ci master = netdev_master_upper_dev_get(upper_dev); 434662306a36Sopenharmony_ci if (master && netif_is_bridge_master(master)) { 434762306a36Sopenharmony_ci err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, 434862306a36Sopenharmony_ci upper_dev, master, 434962306a36Sopenharmony_ci extack); 435062306a36Sopenharmony_ci if (err) 435162306a36Sopenharmony_ci goto err_port_bridge_join; 435262306a36Sopenharmony_ci } 435362306a36Sopenharmony_ci 435462306a36Sopenharmony_ci ++done; 435562306a36Sopenharmony_ci } 435662306a36Sopenharmony_ci 435762306a36Sopenharmony_ci return 0; 435862306a36Sopenharmony_ci 435962306a36Sopenharmony_cierr_port_bridge_join: 436062306a36Sopenharmony_ci netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) { 436162306a36Sopenharmony_ci if (!is_vlan_dev(upper_dev)) 436262306a36Sopenharmony_ci continue; 436362306a36Sopenharmony_ci 436462306a36Sopenharmony_ci master = netdev_master_upper_dev_get(upper_dev); 436562306a36Sopenharmony_ci if (!master || !netif_is_bridge_master(master)) 436662306a36Sopenharmony_ci continue; 436762306a36Sopenharmony_ci 436862306a36Sopenharmony_ci if (!done--) 436962306a36Sopenharmony_ci break; 437062306a36Sopenharmony_ci 437162306a36Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, master); 437262306a36Sopenharmony_ci } 437362306a36Sopenharmony_ci 437462306a36Sopenharmony_ci master = netdev_master_upper_dev_get(lag_dev); 437562306a36Sopenharmony_ci if (master && netif_is_bridge_master(master)) 437662306a36Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, master); 437762306a36Sopenharmony_ci 437862306a36Sopenharmony_ci return err; 437962306a36Sopenharmony_ci} 438062306a36Sopenharmony_ci 438162306a36Sopenharmony_cistatic void 438262306a36Sopenharmony_cimlxsw_sp_lag_uppers_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, 438362306a36Sopenharmony_ci struct net_device *lag_dev) 438462306a36Sopenharmony_ci{ 438562306a36Sopenharmony_ci struct net_device *upper_dev; 438662306a36Sopenharmony_ci struct net_device *master; 438762306a36Sopenharmony_ci struct list_head *iter; 438862306a36Sopenharmony_ci 438962306a36Sopenharmony_ci netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) { 439062306a36Sopenharmony_ci if (!is_vlan_dev(upper_dev)) 439162306a36Sopenharmony_ci continue; 439262306a36Sopenharmony_ci 439362306a36Sopenharmony_ci master = netdev_master_upper_dev_get(upper_dev); 439462306a36Sopenharmony_ci if (!master) 439562306a36Sopenharmony_ci continue; 439662306a36Sopenharmony_ci 439762306a36Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, master); 439862306a36Sopenharmony_ci } 439962306a36Sopenharmony_ci 440062306a36Sopenharmony_ci master = netdev_master_upper_dev_get(lag_dev); 440162306a36Sopenharmony_ci if (master) 440262306a36Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, master); 440362306a36Sopenharmony_ci} 440462306a36Sopenharmony_ci 440562306a36Sopenharmony_cistatic int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, 440662306a36Sopenharmony_ci struct net_device *lag_dev, 440762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 440862306a36Sopenharmony_ci{ 440962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 441062306a36Sopenharmony_ci struct mlxsw_sp_upper *lag; 441162306a36Sopenharmony_ci u16 lag_id; 441262306a36Sopenharmony_ci u8 port_index; 441362306a36Sopenharmony_ci int err; 441462306a36Sopenharmony_ci 441562306a36Sopenharmony_ci err = mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id); 441662306a36Sopenharmony_ci if (err) 441762306a36Sopenharmony_ci return err; 441862306a36Sopenharmony_ci lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id); 441962306a36Sopenharmony_ci if (!lag->ref_count) { 442062306a36Sopenharmony_ci err = mlxsw_sp_lag_create(mlxsw_sp, lag_id); 442162306a36Sopenharmony_ci if (err) 442262306a36Sopenharmony_ci return err; 442362306a36Sopenharmony_ci lag->dev = lag_dev; 442462306a36Sopenharmony_ci } 442562306a36Sopenharmony_ci 442662306a36Sopenharmony_ci err = mlxsw_sp_port_lag_index_get(mlxsw_sp, lag_id, &port_index); 442762306a36Sopenharmony_ci if (err) 442862306a36Sopenharmony_ci return err; 442962306a36Sopenharmony_ci 443062306a36Sopenharmony_ci err = mlxsw_sp_lag_uppers_bridge_join(mlxsw_sp_port, lag_dev, 443162306a36Sopenharmony_ci extack); 443262306a36Sopenharmony_ci if (err) 443362306a36Sopenharmony_ci goto err_lag_uppers_bridge_join; 443462306a36Sopenharmony_ci 443562306a36Sopenharmony_ci err = mlxsw_sp_lag_col_port_add(mlxsw_sp_port, lag_id, port_index); 443662306a36Sopenharmony_ci if (err) 443762306a36Sopenharmony_ci goto err_col_port_add; 443862306a36Sopenharmony_ci 443962306a36Sopenharmony_ci mlxsw_core_lag_mapping_set(mlxsw_sp->core, lag_id, port_index, 444062306a36Sopenharmony_ci mlxsw_sp_port->local_port); 444162306a36Sopenharmony_ci mlxsw_sp_port->lag_id = lag_id; 444262306a36Sopenharmony_ci mlxsw_sp_port->lagged = 1; 444362306a36Sopenharmony_ci lag->ref_count++; 444462306a36Sopenharmony_ci 444562306a36Sopenharmony_ci /* Port is no longer usable as a router interface */ 444662306a36Sopenharmony_ci if (mlxsw_sp_port->default_vlan->fid) 444762306a36Sopenharmony_ci mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port->default_vlan); 444862306a36Sopenharmony_ci 444962306a36Sopenharmony_ci /* Join a router interface configured on the LAG, if exists */ 445062306a36Sopenharmony_ci err = mlxsw_sp_router_port_join_lag(mlxsw_sp_port, lag_dev, 445162306a36Sopenharmony_ci extack); 445262306a36Sopenharmony_ci if (err) 445362306a36Sopenharmony_ci goto err_router_join; 445462306a36Sopenharmony_ci 445562306a36Sopenharmony_ci err = mlxsw_sp_netdevice_enslavement_replay(mlxsw_sp, lag_dev, extack); 445662306a36Sopenharmony_ci if (err) 445762306a36Sopenharmony_ci goto err_replay; 445862306a36Sopenharmony_ci 445962306a36Sopenharmony_ci return 0; 446062306a36Sopenharmony_ci 446162306a36Sopenharmony_cierr_replay: 446262306a36Sopenharmony_ci mlxsw_sp_router_port_leave_lag(mlxsw_sp_port, lag_dev); 446362306a36Sopenharmony_cierr_router_join: 446462306a36Sopenharmony_ci lag->ref_count--; 446562306a36Sopenharmony_ci mlxsw_sp_port->lagged = 0; 446662306a36Sopenharmony_ci mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id, 446762306a36Sopenharmony_ci mlxsw_sp_port->local_port); 446862306a36Sopenharmony_ci mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id); 446962306a36Sopenharmony_cierr_col_port_add: 447062306a36Sopenharmony_ci mlxsw_sp_lag_uppers_bridge_leave(mlxsw_sp_port, lag_dev); 447162306a36Sopenharmony_cierr_lag_uppers_bridge_join: 447262306a36Sopenharmony_ci if (!lag->ref_count) 447362306a36Sopenharmony_ci mlxsw_sp_lag_destroy(mlxsw_sp, lag_id); 447462306a36Sopenharmony_ci return err; 447562306a36Sopenharmony_ci} 447662306a36Sopenharmony_ci 447762306a36Sopenharmony_cistatic void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, 447862306a36Sopenharmony_ci struct net_device *lag_dev) 447962306a36Sopenharmony_ci{ 448062306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 448162306a36Sopenharmony_ci u16 lag_id = mlxsw_sp_port->lag_id; 448262306a36Sopenharmony_ci struct mlxsw_sp_upper *lag; 448362306a36Sopenharmony_ci 448462306a36Sopenharmony_ci if (!mlxsw_sp_port->lagged) 448562306a36Sopenharmony_ci return; 448662306a36Sopenharmony_ci lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id); 448762306a36Sopenharmony_ci WARN_ON(lag->ref_count == 0); 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_ci mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id); 449062306a36Sopenharmony_ci 449162306a36Sopenharmony_ci /* Any VLANs configured on the port are no longer valid */ 449262306a36Sopenharmony_ci mlxsw_sp_port_vlan_flush(mlxsw_sp_port, false); 449362306a36Sopenharmony_ci mlxsw_sp_port_vlan_cleanup(mlxsw_sp_port->default_vlan); 449462306a36Sopenharmony_ci /* Make the LAG and its directly linked uppers leave bridges they 449562306a36Sopenharmony_ci * are memeber in 449662306a36Sopenharmony_ci */ 449762306a36Sopenharmony_ci mlxsw_sp_port_lag_uppers_cleanup(mlxsw_sp_port, lag_dev); 449862306a36Sopenharmony_ci 449962306a36Sopenharmony_ci if (lag->ref_count == 1) 450062306a36Sopenharmony_ci mlxsw_sp_lag_destroy(mlxsw_sp, lag_id); 450162306a36Sopenharmony_ci 450262306a36Sopenharmony_ci mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id, 450362306a36Sopenharmony_ci mlxsw_sp_port->local_port); 450462306a36Sopenharmony_ci mlxsw_sp_port->lagged = 0; 450562306a36Sopenharmony_ci lag->ref_count--; 450662306a36Sopenharmony_ci 450762306a36Sopenharmony_ci /* Make sure untagged frames are allowed to ingress */ 450862306a36Sopenharmony_ci mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID, 450962306a36Sopenharmony_ci ETH_P_8021Q); 451062306a36Sopenharmony_ci} 451162306a36Sopenharmony_ci 451262306a36Sopenharmony_cistatic int mlxsw_sp_lag_dist_port_add(struct mlxsw_sp_port *mlxsw_sp_port, 451362306a36Sopenharmony_ci u16 lag_id) 451462306a36Sopenharmony_ci{ 451562306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 451662306a36Sopenharmony_ci char sldr_pl[MLXSW_REG_SLDR_LEN]; 451762306a36Sopenharmony_ci 451862306a36Sopenharmony_ci mlxsw_reg_sldr_lag_add_port_pack(sldr_pl, lag_id, 451962306a36Sopenharmony_ci mlxsw_sp_port->local_port); 452062306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); 452162306a36Sopenharmony_ci} 452262306a36Sopenharmony_ci 452362306a36Sopenharmony_cistatic int mlxsw_sp_lag_dist_port_remove(struct mlxsw_sp_port *mlxsw_sp_port, 452462306a36Sopenharmony_ci u16 lag_id) 452562306a36Sopenharmony_ci{ 452662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 452762306a36Sopenharmony_ci char sldr_pl[MLXSW_REG_SLDR_LEN]; 452862306a36Sopenharmony_ci 452962306a36Sopenharmony_ci mlxsw_reg_sldr_lag_remove_port_pack(sldr_pl, lag_id, 453062306a36Sopenharmony_ci mlxsw_sp_port->local_port); 453162306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); 453262306a36Sopenharmony_ci} 453362306a36Sopenharmony_ci 453462306a36Sopenharmony_cistatic int 453562306a36Sopenharmony_cimlxsw_sp_port_lag_col_dist_enable(struct mlxsw_sp_port *mlxsw_sp_port) 453662306a36Sopenharmony_ci{ 453762306a36Sopenharmony_ci int err; 453862306a36Sopenharmony_ci 453962306a36Sopenharmony_ci err = mlxsw_sp_lag_col_port_enable(mlxsw_sp_port, 454062306a36Sopenharmony_ci mlxsw_sp_port->lag_id); 454162306a36Sopenharmony_ci if (err) 454262306a36Sopenharmony_ci return err; 454362306a36Sopenharmony_ci 454462306a36Sopenharmony_ci err = mlxsw_sp_lag_dist_port_add(mlxsw_sp_port, mlxsw_sp_port->lag_id); 454562306a36Sopenharmony_ci if (err) 454662306a36Sopenharmony_ci goto err_dist_port_add; 454762306a36Sopenharmony_ci 454862306a36Sopenharmony_ci return 0; 454962306a36Sopenharmony_ci 455062306a36Sopenharmony_cierr_dist_port_add: 455162306a36Sopenharmony_ci mlxsw_sp_lag_col_port_disable(mlxsw_sp_port, mlxsw_sp_port->lag_id); 455262306a36Sopenharmony_ci return err; 455362306a36Sopenharmony_ci} 455462306a36Sopenharmony_ci 455562306a36Sopenharmony_cistatic int 455662306a36Sopenharmony_cimlxsw_sp_port_lag_col_dist_disable(struct mlxsw_sp_port *mlxsw_sp_port) 455762306a36Sopenharmony_ci{ 455862306a36Sopenharmony_ci int err; 455962306a36Sopenharmony_ci 456062306a36Sopenharmony_ci err = mlxsw_sp_lag_dist_port_remove(mlxsw_sp_port, 456162306a36Sopenharmony_ci mlxsw_sp_port->lag_id); 456262306a36Sopenharmony_ci if (err) 456362306a36Sopenharmony_ci return err; 456462306a36Sopenharmony_ci 456562306a36Sopenharmony_ci err = mlxsw_sp_lag_col_port_disable(mlxsw_sp_port, 456662306a36Sopenharmony_ci mlxsw_sp_port->lag_id); 456762306a36Sopenharmony_ci if (err) 456862306a36Sopenharmony_ci goto err_col_port_disable; 456962306a36Sopenharmony_ci 457062306a36Sopenharmony_ci return 0; 457162306a36Sopenharmony_ci 457262306a36Sopenharmony_cierr_col_port_disable: 457362306a36Sopenharmony_ci mlxsw_sp_lag_dist_port_add(mlxsw_sp_port, mlxsw_sp_port->lag_id); 457462306a36Sopenharmony_ci return err; 457562306a36Sopenharmony_ci} 457662306a36Sopenharmony_ci 457762306a36Sopenharmony_cistatic int mlxsw_sp_port_lag_changed(struct mlxsw_sp_port *mlxsw_sp_port, 457862306a36Sopenharmony_ci struct netdev_lag_lower_state_info *info) 457962306a36Sopenharmony_ci{ 458062306a36Sopenharmony_ci if (info->tx_enabled) 458162306a36Sopenharmony_ci return mlxsw_sp_port_lag_col_dist_enable(mlxsw_sp_port); 458262306a36Sopenharmony_ci else 458362306a36Sopenharmony_ci return mlxsw_sp_port_lag_col_dist_disable(mlxsw_sp_port); 458462306a36Sopenharmony_ci} 458562306a36Sopenharmony_ci 458662306a36Sopenharmony_cistatic int mlxsw_sp_port_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, 458762306a36Sopenharmony_ci bool enable) 458862306a36Sopenharmony_ci{ 458962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 459062306a36Sopenharmony_ci enum mlxsw_reg_spms_state spms_state; 459162306a36Sopenharmony_ci char *spms_pl; 459262306a36Sopenharmony_ci u16 vid; 459362306a36Sopenharmony_ci int err; 459462306a36Sopenharmony_ci 459562306a36Sopenharmony_ci spms_state = enable ? MLXSW_REG_SPMS_STATE_FORWARDING : 459662306a36Sopenharmony_ci MLXSW_REG_SPMS_STATE_DISCARDING; 459762306a36Sopenharmony_ci 459862306a36Sopenharmony_ci spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL); 459962306a36Sopenharmony_ci if (!spms_pl) 460062306a36Sopenharmony_ci return -ENOMEM; 460162306a36Sopenharmony_ci mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port); 460262306a36Sopenharmony_ci 460362306a36Sopenharmony_ci for (vid = 0; vid < VLAN_N_VID; vid++) 460462306a36Sopenharmony_ci mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state); 460562306a36Sopenharmony_ci 460662306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl); 460762306a36Sopenharmony_ci kfree(spms_pl); 460862306a36Sopenharmony_ci return err; 460962306a36Sopenharmony_ci} 461062306a36Sopenharmony_ci 461162306a36Sopenharmony_cistatic int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port) 461262306a36Sopenharmony_ci{ 461362306a36Sopenharmony_ci u16 vid = 1; 461462306a36Sopenharmony_ci int err; 461562306a36Sopenharmony_ci 461662306a36Sopenharmony_ci err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); 461762306a36Sopenharmony_ci if (err) 461862306a36Sopenharmony_ci return err; 461962306a36Sopenharmony_ci err = mlxsw_sp_port_stp_set(mlxsw_sp_port, true); 462062306a36Sopenharmony_ci if (err) 462162306a36Sopenharmony_ci goto err_port_stp_set; 462262306a36Sopenharmony_ci err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 1, VLAN_N_VID - 2, 462362306a36Sopenharmony_ci true, false); 462462306a36Sopenharmony_ci if (err) 462562306a36Sopenharmony_ci goto err_port_vlan_set; 462662306a36Sopenharmony_ci 462762306a36Sopenharmony_ci for (; vid <= VLAN_N_VID - 1; vid++) { 462862306a36Sopenharmony_ci err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, 462962306a36Sopenharmony_ci vid, false); 463062306a36Sopenharmony_ci if (err) 463162306a36Sopenharmony_ci goto err_vid_learning_set; 463262306a36Sopenharmony_ci } 463362306a36Sopenharmony_ci 463462306a36Sopenharmony_ci return 0; 463562306a36Sopenharmony_ci 463662306a36Sopenharmony_cierr_vid_learning_set: 463762306a36Sopenharmony_ci for (vid--; vid >= 1; vid--) 463862306a36Sopenharmony_ci mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); 463962306a36Sopenharmony_cierr_port_vlan_set: 464062306a36Sopenharmony_ci mlxsw_sp_port_stp_set(mlxsw_sp_port, false); 464162306a36Sopenharmony_cierr_port_stp_set: 464262306a36Sopenharmony_ci mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); 464362306a36Sopenharmony_ci return err; 464462306a36Sopenharmony_ci} 464562306a36Sopenharmony_ci 464662306a36Sopenharmony_cistatic void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port) 464762306a36Sopenharmony_ci{ 464862306a36Sopenharmony_ci u16 vid; 464962306a36Sopenharmony_ci 465062306a36Sopenharmony_ci for (vid = VLAN_N_VID - 1; vid >= 1; vid--) 465162306a36Sopenharmony_ci mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, 465262306a36Sopenharmony_ci vid, true); 465362306a36Sopenharmony_ci 465462306a36Sopenharmony_ci mlxsw_sp_port_vlan_set(mlxsw_sp_port, 1, VLAN_N_VID - 2, 465562306a36Sopenharmony_ci false, false); 465662306a36Sopenharmony_ci mlxsw_sp_port_stp_set(mlxsw_sp_port, false); 465762306a36Sopenharmony_ci mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); 465862306a36Sopenharmony_ci} 465962306a36Sopenharmony_ci 466062306a36Sopenharmony_cistatic bool mlxsw_sp_bridge_has_multiple_vxlans(struct net_device *br_dev) 466162306a36Sopenharmony_ci{ 466262306a36Sopenharmony_ci unsigned int num_vxlans = 0; 466362306a36Sopenharmony_ci struct net_device *dev; 466462306a36Sopenharmony_ci struct list_head *iter; 466562306a36Sopenharmony_ci 466662306a36Sopenharmony_ci netdev_for_each_lower_dev(br_dev, dev, iter) { 466762306a36Sopenharmony_ci if (netif_is_vxlan(dev)) 466862306a36Sopenharmony_ci num_vxlans++; 466962306a36Sopenharmony_ci } 467062306a36Sopenharmony_ci 467162306a36Sopenharmony_ci return num_vxlans > 1; 467262306a36Sopenharmony_ci} 467362306a36Sopenharmony_ci 467462306a36Sopenharmony_cistatic bool mlxsw_sp_bridge_vxlan_vlan_is_valid(struct net_device *br_dev) 467562306a36Sopenharmony_ci{ 467662306a36Sopenharmony_ci DECLARE_BITMAP(vlans, VLAN_N_VID) = {0}; 467762306a36Sopenharmony_ci struct net_device *dev; 467862306a36Sopenharmony_ci struct list_head *iter; 467962306a36Sopenharmony_ci 468062306a36Sopenharmony_ci netdev_for_each_lower_dev(br_dev, dev, iter) { 468162306a36Sopenharmony_ci u16 pvid; 468262306a36Sopenharmony_ci int err; 468362306a36Sopenharmony_ci 468462306a36Sopenharmony_ci if (!netif_is_vxlan(dev)) 468562306a36Sopenharmony_ci continue; 468662306a36Sopenharmony_ci 468762306a36Sopenharmony_ci err = mlxsw_sp_vxlan_mapped_vid(dev, &pvid); 468862306a36Sopenharmony_ci if (err || !pvid) 468962306a36Sopenharmony_ci continue; 469062306a36Sopenharmony_ci 469162306a36Sopenharmony_ci if (test_and_set_bit(pvid, vlans)) 469262306a36Sopenharmony_ci return false; 469362306a36Sopenharmony_ci } 469462306a36Sopenharmony_ci 469562306a36Sopenharmony_ci return true; 469662306a36Sopenharmony_ci} 469762306a36Sopenharmony_ci 469862306a36Sopenharmony_cistatic bool mlxsw_sp_bridge_vxlan_is_valid(struct net_device *br_dev, 469962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 470062306a36Sopenharmony_ci{ 470162306a36Sopenharmony_ci if (br_multicast_enabled(br_dev)) { 470262306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Multicast can not be enabled on a bridge with a VxLAN device"); 470362306a36Sopenharmony_ci return false; 470462306a36Sopenharmony_ci } 470562306a36Sopenharmony_ci 470662306a36Sopenharmony_ci if (!br_vlan_enabled(br_dev) && 470762306a36Sopenharmony_ci mlxsw_sp_bridge_has_multiple_vxlans(br_dev)) { 470862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices are not supported in a VLAN-unaware bridge"); 470962306a36Sopenharmony_ci return false; 471062306a36Sopenharmony_ci } 471162306a36Sopenharmony_ci 471262306a36Sopenharmony_ci if (br_vlan_enabled(br_dev) && 471362306a36Sopenharmony_ci !mlxsw_sp_bridge_vxlan_vlan_is_valid(br_dev)) { 471462306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices cannot have the same VLAN as PVID and egress untagged"); 471562306a36Sopenharmony_ci return false; 471662306a36Sopenharmony_ci } 471762306a36Sopenharmony_ci 471862306a36Sopenharmony_ci return true; 471962306a36Sopenharmony_ci} 472062306a36Sopenharmony_ci 472162306a36Sopenharmony_cistatic bool mlxsw_sp_netdev_is_master(struct net_device *upper_dev, 472262306a36Sopenharmony_ci struct net_device *dev) 472362306a36Sopenharmony_ci{ 472462306a36Sopenharmony_ci return upper_dev == netdev_master_upper_dev_get(dev); 472562306a36Sopenharmony_ci} 472662306a36Sopenharmony_ci 472762306a36Sopenharmony_cistatic int __mlxsw_sp_netdevice_event(struct mlxsw_sp *mlxsw_sp, 472862306a36Sopenharmony_ci unsigned long event, void *ptr, 472962306a36Sopenharmony_ci bool process_foreign); 473062306a36Sopenharmony_ci 473162306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_validate_uppers(struct mlxsw_sp *mlxsw_sp, 473262306a36Sopenharmony_ci struct net_device *dev, 473362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 473462306a36Sopenharmony_ci{ 473562306a36Sopenharmony_ci struct net_device *upper_dev; 473662306a36Sopenharmony_ci struct list_head *iter; 473762306a36Sopenharmony_ci int err; 473862306a36Sopenharmony_ci 473962306a36Sopenharmony_ci netdev_for_each_upper_dev_rcu(dev, upper_dev, iter) { 474062306a36Sopenharmony_ci struct netdev_notifier_changeupper_info info = { 474162306a36Sopenharmony_ci .info = { 474262306a36Sopenharmony_ci .dev = dev, 474362306a36Sopenharmony_ci .extack = extack, 474462306a36Sopenharmony_ci }, 474562306a36Sopenharmony_ci .master = mlxsw_sp_netdev_is_master(upper_dev, dev), 474662306a36Sopenharmony_ci .upper_dev = upper_dev, 474762306a36Sopenharmony_ci .linking = true, 474862306a36Sopenharmony_ci 474962306a36Sopenharmony_ci /* upper_info is relevant for LAG devices. But we would 475062306a36Sopenharmony_ci * only need this if LAG were a valid upper above 475162306a36Sopenharmony_ci * another upper (e.g. a bridge that is a member of a 475262306a36Sopenharmony_ci * LAG), and that is never a valid configuration. So we 475362306a36Sopenharmony_ci * can keep this as NULL. 475462306a36Sopenharmony_ci */ 475562306a36Sopenharmony_ci .upper_info = NULL, 475662306a36Sopenharmony_ci }; 475762306a36Sopenharmony_ci 475862306a36Sopenharmony_ci err = __mlxsw_sp_netdevice_event(mlxsw_sp, 475962306a36Sopenharmony_ci NETDEV_PRECHANGEUPPER, 476062306a36Sopenharmony_ci &info, true); 476162306a36Sopenharmony_ci if (err) 476262306a36Sopenharmony_ci return err; 476362306a36Sopenharmony_ci 476462306a36Sopenharmony_ci err = mlxsw_sp_netdevice_validate_uppers(mlxsw_sp, upper_dev, 476562306a36Sopenharmony_ci extack); 476662306a36Sopenharmony_ci if (err) 476762306a36Sopenharmony_ci return err; 476862306a36Sopenharmony_ci } 476962306a36Sopenharmony_ci 477062306a36Sopenharmony_ci return 0; 477162306a36Sopenharmony_ci} 477262306a36Sopenharmony_ci 477362306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, 477462306a36Sopenharmony_ci struct net_device *dev, 477562306a36Sopenharmony_ci unsigned long event, void *ptr, 477662306a36Sopenharmony_ci bool replay_deslavement) 477762306a36Sopenharmony_ci{ 477862306a36Sopenharmony_ci struct netdev_notifier_changeupper_info *info; 477962306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 478062306a36Sopenharmony_ci struct netlink_ext_ack *extack; 478162306a36Sopenharmony_ci struct net_device *upper_dev; 478262306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp; 478362306a36Sopenharmony_ci int err = 0; 478462306a36Sopenharmony_ci u16 proto; 478562306a36Sopenharmony_ci 478662306a36Sopenharmony_ci mlxsw_sp_port = netdev_priv(dev); 478762306a36Sopenharmony_ci mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 478862306a36Sopenharmony_ci info = ptr; 478962306a36Sopenharmony_ci extack = netdev_notifier_info_to_extack(&info->info); 479062306a36Sopenharmony_ci 479162306a36Sopenharmony_ci switch (event) { 479262306a36Sopenharmony_ci case NETDEV_PRECHANGEUPPER: 479362306a36Sopenharmony_ci upper_dev = info->upper_dev; 479462306a36Sopenharmony_ci if (!is_vlan_dev(upper_dev) && 479562306a36Sopenharmony_ci !netif_is_lag_master(upper_dev) && 479662306a36Sopenharmony_ci !netif_is_bridge_master(upper_dev) && 479762306a36Sopenharmony_ci !netif_is_ovs_master(upper_dev) && 479862306a36Sopenharmony_ci !netif_is_macvlan(upper_dev) && 479962306a36Sopenharmony_ci !netif_is_l3_master(upper_dev)) { 480062306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); 480162306a36Sopenharmony_ci return -EINVAL; 480262306a36Sopenharmony_ci } 480362306a36Sopenharmony_ci if (!info->linking) 480462306a36Sopenharmony_ci break; 480562306a36Sopenharmony_ci if (netif_is_bridge_master(upper_dev) && 480662306a36Sopenharmony_ci !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) && 480762306a36Sopenharmony_ci mlxsw_sp_bridge_has_vxlan(upper_dev) && 480862306a36Sopenharmony_ci !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack)) 480962306a36Sopenharmony_ci return -EOPNOTSUPP; 481062306a36Sopenharmony_ci if (netdev_has_any_upper_dev(upper_dev) && 481162306a36Sopenharmony_ci (!netif_is_bridge_master(upper_dev) || 481262306a36Sopenharmony_ci !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, 481362306a36Sopenharmony_ci upper_dev))) { 481462306a36Sopenharmony_ci err = mlxsw_sp_netdevice_validate_uppers(mlxsw_sp, 481562306a36Sopenharmony_ci upper_dev, 481662306a36Sopenharmony_ci extack); 481762306a36Sopenharmony_ci if (err) 481862306a36Sopenharmony_ci return err; 481962306a36Sopenharmony_ci } 482062306a36Sopenharmony_ci if (netif_is_lag_master(upper_dev) && 482162306a36Sopenharmony_ci !mlxsw_sp_master_lag_check(mlxsw_sp, upper_dev, 482262306a36Sopenharmony_ci info->upper_info, extack)) 482362306a36Sopenharmony_ci return -EINVAL; 482462306a36Sopenharmony_ci if (netif_is_lag_master(upper_dev) && vlan_uses_dev(dev)) { 482562306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Master device is a LAG master and this device has a VLAN"); 482662306a36Sopenharmony_ci return -EINVAL; 482762306a36Sopenharmony_ci } 482862306a36Sopenharmony_ci if (netif_is_lag_port(dev) && is_vlan_dev(upper_dev) && 482962306a36Sopenharmony_ci !netif_is_lag_master(vlan_dev_real_dev(upper_dev))) { 483062306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on a LAG port"); 483162306a36Sopenharmony_ci return -EINVAL; 483262306a36Sopenharmony_ci } 483362306a36Sopenharmony_ci if (netif_is_ovs_master(upper_dev) && vlan_uses_dev(dev)) { 483462306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Master device is an OVS master and this device has a VLAN"); 483562306a36Sopenharmony_ci return -EINVAL; 483662306a36Sopenharmony_ci } 483762306a36Sopenharmony_ci if (netif_is_ovs_port(dev) && is_vlan_dev(upper_dev)) { 483862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on an OVS port"); 483962306a36Sopenharmony_ci return -EINVAL; 484062306a36Sopenharmony_ci } 484162306a36Sopenharmony_ci if (netif_is_bridge_master(upper_dev)) { 484262306a36Sopenharmony_ci br_vlan_get_proto(upper_dev, &proto); 484362306a36Sopenharmony_ci if (br_vlan_enabled(upper_dev) && 484462306a36Sopenharmony_ci proto != ETH_P_8021Q && proto != ETH_P_8021AD) { 484562306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Enslaving a port to a bridge with unknown VLAN protocol is not supported"); 484662306a36Sopenharmony_ci return -EOPNOTSUPP; 484762306a36Sopenharmony_ci } 484862306a36Sopenharmony_ci if (vlan_uses_dev(lower_dev) && 484962306a36Sopenharmony_ci br_vlan_enabled(upper_dev) && 485062306a36Sopenharmony_ci proto == ETH_P_8021AD) { 485162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Enslaving a port that already has a VLAN upper to an 802.1ad bridge is not supported"); 485262306a36Sopenharmony_ci return -EOPNOTSUPP; 485362306a36Sopenharmony_ci } 485462306a36Sopenharmony_ci } 485562306a36Sopenharmony_ci if (netif_is_bridge_port(lower_dev) && is_vlan_dev(upper_dev)) { 485662306a36Sopenharmony_ci struct net_device *br_dev = netdev_master_upper_dev_get(lower_dev); 485762306a36Sopenharmony_ci 485862306a36Sopenharmony_ci if (br_vlan_enabled(br_dev)) { 485962306a36Sopenharmony_ci br_vlan_get_proto(br_dev, &proto); 486062306a36Sopenharmony_ci if (proto == ETH_P_8021AD) { 486162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are not supported on a port enslaved to an 802.1ad bridge"); 486262306a36Sopenharmony_ci return -EOPNOTSUPP; 486362306a36Sopenharmony_ci } 486462306a36Sopenharmony_ci } 486562306a36Sopenharmony_ci } 486662306a36Sopenharmony_ci if (is_vlan_dev(upper_dev) && 486762306a36Sopenharmony_ci ntohs(vlan_dev_vlan_proto(upper_dev)) != ETH_P_8021Q) { 486862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are only supported with 802.1q VLAN protocol"); 486962306a36Sopenharmony_ci return -EOPNOTSUPP; 487062306a36Sopenharmony_ci } 487162306a36Sopenharmony_ci if (is_vlan_dev(upper_dev) && mlxsw_sp_port->security) { 487262306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are not supported on a locked port"); 487362306a36Sopenharmony_ci return -EOPNOTSUPP; 487462306a36Sopenharmony_ci } 487562306a36Sopenharmony_ci break; 487662306a36Sopenharmony_ci case NETDEV_CHANGEUPPER: 487762306a36Sopenharmony_ci upper_dev = info->upper_dev; 487862306a36Sopenharmony_ci if (netif_is_bridge_master(upper_dev)) { 487962306a36Sopenharmony_ci if (info->linking) { 488062306a36Sopenharmony_ci err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, 488162306a36Sopenharmony_ci lower_dev, 488262306a36Sopenharmony_ci upper_dev, 488362306a36Sopenharmony_ci extack); 488462306a36Sopenharmony_ci } else { 488562306a36Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, 488662306a36Sopenharmony_ci lower_dev, 488762306a36Sopenharmony_ci upper_dev); 488862306a36Sopenharmony_ci if (!replay_deslavement) 488962306a36Sopenharmony_ci break; 489062306a36Sopenharmony_ci mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp, 489162306a36Sopenharmony_ci lower_dev); 489262306a36Sopenharmony_ci } 489362306a36Sopenharmony_ci } else if (netif_is_lag_master(upper_dev)) { 489462306a36Sopenharmony_ci if (info->linking) { 489562306a36Sopenharmony_ci err = mlxsw_sp_port_lag_join(mlxsw_sp_port, 489662306a36Sopenharmony_ci upper_dev, extack); 489762306a36Sopenharmony_ci } else { 489862306a36Sopenharmony_ci mlxsw_sp_port_lag_col_dist_disable(mlxsw_sp_port); 489962306a36Sopenharmony_ci mlxsw_sp_port_lag_leave(mlxsw_sp_port, 490062306a36Sopenharmony_ci upper_dev); 490162306a36Sopenharmony_ci mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp, 490262306a36Sopenharmony_ci dev); 490362306a36Sopenharmony_ci } 490462306a36Sopenharmony_ci } else if (netif_is_ovs_master(upper_dev)) { 490562306a36Sopenharmony_ci if (info->linking) 490662306a36Sopenharmony_ci err = mlxsw_sp_port_ovs_join(mlxsw_sp_port); 490762306a36Sopenharmony_ci else 490862306a36Sopenharmony_ci mlxsw_sp_port_ovs_leave(mlxsw_sp_port); 490962306a36Sopenharmony_ci } else if (netif_is_macvlan(upper_dev)) { 491062306a36Sopenharmony_ci if (!info->linking) 491162306a36Sopenharmony_ci mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev); 491262306a36Sopenharmony_ci } else if (is_vlan_dev(upper_dev)) { 491362306a36Sopenharmony_ci struct net_device *br_dev; 491462306a36Sopenharmony_ci 491562306a36Sopenharmony_ci if (!netif_is_bridge_port(upper_dev)) 491662306a36Sopenharmony_ci break; 491762306a36Sopenharmony_ci if (info->linking) 491862306a36Sopenharmony_ci break; 491962306a36Sopenharmony_ci br_dev = netdev_master_upper_dev_get(upper_dev); 492062306a36Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, 492162306a36Sopenharmony_ci br_dev); 492262306a36Sopenharmony_ci } 492362306a36Sopenharmony_ci break; 492462306a36Sopenharmony_ci } 492562306a36Sopenharmony_ci 492662306a36Sopenharmony_ci return err; 492762306a36Sopenharmony_ci} 492862306a36Sopenharmony_ci 492962306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_port_lower_event(struct net_device *dev, 493062306a36Sopenharmony_ci unsigned long event, void *ptr) 493162306a36Sopenharmony_ci{ 493262306a36Sopenharmony_ci struct netdev_notifier_changelowerstate_info *info; 493362306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port; 493462306a36Sopenharmony_ci int err; 493562306a36Sopenharmony_ci 493662306a36Sopenharmony_ci mlxsw_sp_port = netdev_priv(dev); 493762306a36Sopenharmony_ci info = ptr; 493862306a36Sopenharmony_ci 493962306a36Sopenharmony_ci switch (event) { 494062306a36Sopenharmony_ci case NETDEV_CHANGELOWERSTATE: 494162306a36Sopenharmony_ci if (netif_is_lag_port(dev) && mlxsw_sp_port->lagged) { 494262306a36Sopenharmony_ci err = mlxsw_sp_port_lag_changed(mlxsw_sp_port, 494362306a36Sopenharmony_ci info->lower_state_info); 494462306a36Sopenharmony_ci if (err) 494562306a36Sopenharmony_ci netdev_err(dev, "Failed to reflect link aggregation lower state change\n"); 494662306a36Sopenharmony_ci } 494762306a36Sopenharmony_ci break; 494862306a36Sopenharmony_ci } 494962306a36Sopenharmony_ci 495062306a36Sopenharmony_ci return 0; 495162306a36Sopenharmony_ci} 495262306a36Sopenharmony_ci 495362306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_port_event(struct net_device *lower_dev, 495462306a36Sopenharmony_ci struct net_device *port_dev, 495562306a36Sopenharmony_ci unsigned long event, void *ptr, 495662306a36Sopenharmony_ci bool replay_deslavement) 495762306a36Sopenharmony_ci{ 495862306a36Sopenharmony_ci switch (event) { 495962306a36Sopenharmony_ci case NETDEV_PRECHANGEUPPER: 496062306a36Sopenharmony_ci case NETDEV_CHANGEUPPER: 496162306a36Sopenharmony_ci return mlxsw_sp_netdevice_port_upper_event(lower_dev, port_dev, 496262306a36Sopenharmony_ci event, ptr, 496362306a36Sopenharmony_ci replay_deslavement); 496462306a36Sopenharmony_ci case NETDEV_CHANGELOWERSTATE: 496562306a36Sopenharmony_ci return mlxsw_sp_netdevice_port_lower_event(port_dev, event, 496662306a36Sopenharmony_ci ptr); 496762306a36Sopenharmony_ci } 496862306a36Sopenharmony_ci 496962306a36Sopenharmony_ci return 0; 497062306a36Sopenharmony_ci} 497162306a36Sopenharmony_ci 497262306a36Sopenharmony_ci/* Called for LAG or its upper VLAN after the per-LAG-lower processing was done, 497362306a36Sopenharmony_ci * to do any per-LAG / per-LAG-upper processing. 497462306a36Sopenharmony_ci */ 497562306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_post_lag_event(struct net_device *dev, 497662306a36Sopenharmony_ci unsigned long event, 497762306a36Sopenharmony_ci void *ptr) 497862306a36Sopenharmony_ci{ 497962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(dev); 498062306a36Sopenharmony_ci struct netdev_notifier_changeupper_info *info = ptr; 498162306a36Sopenharmony_ci 498262306a36Sopenharmony_ci if (!mlxsw_sp) 498362306a36Sopenharmony_ci return 0; 498462306a36Sopenharmony_ci 498562306a36Sopenharmony_ci switch (event) { 498662306a36Sopenharmony_ci case NETDEV_CHANGEUPPER: 498762306a36Sopenharmony_ci if (info->linking) 498862306a36Sopenharmony_ci break; 498962306a36Sopenharmony_ci if (netif_is_bridge_master(info->upper_dev)) 499062306a36Sopenharmony_ci mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp, dev); 499162306a36Sopenharmony_ci break; 499262306a36Sopenharmony_ci } 499362306a36Sopenharmony_ci return 0; 499462306a36Sopenharmony_ci} 499562306a36Sopenharmony_ci 499662306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev, 499762306a36Sopenharmony_ci unsigned long event, void *ptr) 499862306a36Sopenharmony_ci{ 499962306a36Sopenharmony_ci struct net_device *dev; 500062306a36Sopenharmony_ci struct list_head *iter; 500162306a36Sopenharmony_ci int ret; 500262306a36Sopenharmony_ci 500362306a36Sopenharmony_ci netdev_for_each_lower_dev(lag_dev, dev, iter) { 500462306a36Sopenharmony_ci if (mlxsw_sp_port_dev_check(dev)) { 500562306a36Sopenharmony_ci ret = mlxsw_sp_netdevice_port_event(lag_dev, dev, event, 500662306a36Sopenharmony_ci ptr, false); 500762306a36Sopenharmony_ci if (ret) 500862306a36Sopenharmony_ci return ret; 500962306a36Sopenharmony_ci } 501062306a36Sopenharmony_ci } 501162306a36Sopenharmony_ci 501262306a36Sopenharmony_ci return mlxsw_sp_netdevice_post_lag_event(lag_dev, event, ptr); 501362306a36Sopenharmony_ci} 501462306a36Sopenharmony_ci 501562306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev, 501662306a36Sopenharmony_ci struct net_device *dev, 501762306a36Sopenharmony_ci unsigned long event, void *ptr, 501862306a36Sopenharmony_ci u16 vid, bool replay_deslavement) 501962306a36Sopenharmony_ci{ 502062306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); 502162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 502262306a36Sopenharmony_ci struct netdev_notifier_changeupper_info *info = ptr; 502362306a36Sopenharmony_ci struct netlink_ext_ack *extack; 502462306a36Sopenharmony_ci struct net_device *upper_dev; 502562306a36Sopenharmony_ci int err = 0; 502662306a36Sopenharmony_ci 502762306a36Sopenharmony_ci extack = netdev_notifier_info_to_extack(&info->info); 502862306a36Sopenharmony_ci 502962306a36Sopenharmony_ci switch (event) { 503062306a36Sopenharmony_ci case NETDEV_PRECHANGEUPPER: 503162306a36Sopenharmony_ci upper_dev = info->upper_dev; 503262306a36Sopenharmony_ci if (!netif_is_bridge_master(upper_dev) && 503362306a36Sopenharmony_ci !netif_is_macvlan(upper_dev) && 503462306a36Sopenharmony_ci !netif_is_l3_master(upper_dev)) { 503562306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); 503662306a36Sopenharmony_ci return -EINVAL; 503762306a36Sopenharmony_ci } 503862306a36Sopenharmony_ci if (!info->linking) 503962306a36Sopenharmony_ci break; 504062306a36Sopenharmony_ci if (netif_is_bridge_master(upper_dev) && 504162306a36Sopenharmony_ci !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) && 504262306a36Sopenharmony_ci mlxsw_sp_bridge_has_vxlan(upper_dev) && 504362306a36Sopenharmony_ci !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack)) 504462306a36Sopenharmony_ci return -EOPNOTSUPP; 504562306a36Sopenharmony_ci if (netdev_has_any_upper_dev(upper_dev) && 504662306a36Sopenharmony_ci (!netif_is_bridge_master(upper_dev) || 504762306a36Sopenharmony_ci !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, 504862306a36Sopenharmony_ci upper_dev))) { 504962306a36Sopenharmony_ci err = mlxsw_sp_netdevice_validate_uppers(mlxsw_sp, 505062306a36Sopenharmony_ci upper_dev, 505162306a36Sopenharmony_ci extack); 505262306a36Sopenharmony_ci if (err) 505362306a36Sopenharmony_ci return err; 505462306a36Sopenharmony_ci } 505562306a36Sopenharmony_ci break; 505662306a36Sopenharmony_ci case NETDEV_CHANGEUPPER: 505762306a36Sopenharmony_ci upper_dev = info->upper_dev; 505862306a36Sopenharmony_ci if (netif_is_bridge_master(upper_dev)) { 505962306a36Sopenharmony_ci if (info->linking) { 506062306a36Sopenharmony_ci err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, 506162306a36Sopenharmony_ci vlan_dev, 506262306a36Sopenharmony_ci upper_dev, 506362306a36Sopenharmony_ci extack); 506462306a36Sopenharmony_ci } else { 506562306a36Sopenharmony_ci mlxsw_sp_port_bridge_leave(mlxsw_sp_port, 506662306a36Sopenharmony_ci vlan_dev, 506762306a36Sopenharmony_ci upper_dev); 506862306a36Sopenharmony_ci if (!replay_deslavement) 506962306a36Sopenharmony_ci break; 507062306a36Sopenharmony_ci mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp, 507162306a36Sopenharmony_ci vlan_dev); 507262306a36Sopenharmony_ci } 507362306a36Sopenharmony_ci } else if (netif_is_macvlan(upper_dev)) { 507462306a36Sopenharmony_ci if (!info->linking) 507562306a36Sopenharmony_ci mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev); 507662306a36Sopenharmony_ci } 507762306a36Sopenharmony_ci break; 507862306a36Sopenharmony_ci } 507962306a36Sopenharmony_ci 508062306a36Sopenharmony_ci return err; 508162306a36Sopenharmony_ci} 508262306a36Sopenharmony_ci 508362306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_lag_port_vlan_event(struct net_device *vlan_dev, 508462306a36Sopenharmony_ci struct net_device *lag_dev, 508562306a36Sopenharmony_ci unsigned long event, 508662306a36Sopenharmony_ci void *ptr, u16 vid) 508762306a36Sopenharmony_ci{ 508862306a36Sopenharmony_ci struct net_device *dev; 508962306a36Sopenharmony_ci struct list_head *iter; 509062306a36Sopenharmony_ci int ret; 509162306a36Sopenharmony_ci 509262306a36Sopenharmony_ci netdev_for_each_lower_dev(lag_dev, dev, iter) { 509362306a36Sopenharmony_ci if (mlxsw_sp_port_dev_check(dev)) { 509462306a36Sopenharmony_ci ret = mlxsw_sp_netdevice_port_vlan_event(vlan_dev, dev, 509562306a36Sopenharmony_ci event, ptr, 509662306a36Sopenharmony_ci vid, false); 509762306a36Sopenharmony_ci if (ret) 509862306a36Sopenharmony_ci return ret; 509962306a36Sopenharmony_ci } 510062306a36Sopenharmony_ci } 510162306a36Sopenharmony_ci 510262306a36Sopenharmony_ci return mlxsw_sp_netdevice_post_lag_event(vlan_dev, event, ptr); 510362306a36Sopenharmony_ci} 510462306a36Sopenharmony_ci 510562306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_bridge_vlan_event(struct mlxsw_sp *mlxsw_sp, 510662306a36Sopenharmony_ci struct net_device *vlan_dev, 510762306a36Sopenharmony_ci struct net_device *br_dev, 510862306a36Sopenharmony_ci unsigned long event, void *ptr, 510962306a36Sopenharmony_ci u16 vid, bool process_foreign) 511062306a36Sopenharmony_ci{ 511162306a36Sopenharmony_ci struct netdev_notifier_changeupper_info *info = ptr; 511262306a36Sopenharmony_ci struct netlink_ext_ack *extack; 511362306a36Sopenharmony_ci struct net_device *upper_dev; 511462306a36Sopenharmony_ci 511562306a36Sopenharmony_ci if (!process_foreign && !mlxsw_sp_lower_get(vlan_dev)) 511662306a36Sopenharmony_ci return 0; 511762306a36Sopenharmony_ci 511862306a36Sopenharmony_ci extack = netdev_notifier_info_to_extack(&info->info); 511962306a36Sopenharmony_ci 512062306a36Sopenharmony_ci switch (event) { 512162306a36Sopenharmony_ci case NETDEV_PRECHANGEUPPER: 512262306a36Sopenharmony_ci upper_dev = info->upper_dev; 512362306a36Sopenharmony_ci if (!netif_is_macvlan(upper_dev) && 512462306a36Sopenharmony_ci !netif_is_l3_master(upper_dev)) { 512562306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); 512662306a36Sopenharmony_ci return -EOPNOTSUPP; 512762306a36Sopenharmony_ci } 512862306a36Sopenharmony_ci break; 512962306a36Sopenharmony_ci case NETDEV_CHANGEUPPER: 513062306a36Sopenharmony_ci upper_dev = info->upper_dev; 513162306a36Sopenharmony_ci if (info->linking) 513262306a36Sopenharmony_ci break; 513362306a36Sopenharmony_ci if (netif_is_macvlan(upper_dev)) 513462306a36Sopenharmony_ci mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev); 513562306a36Sopenharmony_ci break; 513662306a36Sopenharmony_ci } 513762306a36Sopenharmony_ci 513862306a36Sopenharmony_ci return 0; 513962306a36Sopenharmony_ci} 514062306a36Sopenharmony_ci 514162306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_vlan_event(struct mlxsw_sp *mlxsw_sp, 514262306a36Sopenharmony_ci struct net_device *vlan_dev, 514362306a36Sopenharmony_ci unsigned long event, void *ptr, 514462306a36Sopenharmony_ci bool process_foreign) 514562306a36Sopenharmony_ci{ 514662306a36Sopenharmony_ci struct net_device *real_dev = vlan_dev_real_dev(vlan_dev); 514762306a36Sopenharmony_ci u16 vid = vlan_dev_vlan_id(vlan_dev); 514862306a36Sopenharmony_ci 514962306a36Sopenharmony_ci if (mlxsw_sp_port_dev_check(real_dev)) 515062306a36Sopenharmony_ci return mlxsw_sp_netdevice_port_vlan_event(vlan_dev, real_dev, 515162306a36Sopenharmony_ci event, ptr, vid, 515262306a36Sopenharmony_ci true); 515362306a36Sopenharmony_ci else if (netif_is_lag_master(real_dev)) 515462306a36Sopenharmony_ci return mlxsw_sp_netdevice_lag_port_vlan_event(vlan_dev, 515562306a36Sopenharmony_ci real_dev, event, 515662306a36Sopenharmony_ci ptr, vid); 515762306a36Sopenharmony_ci else if (netif_is_bridge_master(real_dev)) 515862306a36Sopenharmony_ci return mlxsw_sp_netdevice_bridge_vlan_event(mlxsw_sp, vlan_dev, 515962306a36Sopenharmony_ci real_dev, event, 516062306a36Sopenharmony_ci ptr, vid, 516162306a36Sopenharmony_ci process_foreign); 516262306a36Sopenharmony_ci 516362306a36Sopenharmony_ci return 0; 516462306a36Sopenharmony_ci} 516562306a36Sopenharmony_ci 516662306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_bridge_event(struct mlxsw_sp *mlxsw_sp, 516762306a36Sopenharmony_ci struct net_device *br_dev, 516862306a36Sopenharmony_ci unsigned long event, void *ptr, 516962306a36Sopenharmony_ci bool process_foreign) 517062306a36Sopenharmony_ci{ 517162306a36Sopenharmony_ci struct netdev_notifier_changeupper_info *info = ptr; 517262306a36Sopenharmony_ci struct netlink_ext_ack *extack; 517362306a36Sopenharmony_ci struct net_device *upper_dev; 517462306a36Sopenharmony_ci u16 proto; 517562306a36Sopenharmony_ci 517662306a36Sopenharmony_ci if (!process_foreign && !mlxsw_sp_lower_get(br_dev)) 517762306a36Sopenharmony_ci return 0; 517862306a36Sopenharmony_ci 517962306a36Sopenharmony_ci extack = netdev_notifier_info_to_extack(&info->info); 518062306a36Sopenharmony_ci 518162306a36Sopenharmony_ci switch (event) { 518262306a36Sopenharmony_ci case NETDEV_PRECHANGEUPPER: 518362306a36Sopenharmony_ci upper_dev = info->upper_dev; 518462306a36Sopenharmony_ci if (!is_vlan_dev(upper_dev) && 518562306a36Sopenharmony_ci !netif_is_macvlan(upper_dev) && 518662306a36Sopenharmony_ci !netif_is_l3_master(upper_dev)) { 518762306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); 518862306a36Sopenharmony_ci return -EOPNOTSUPP; 518962306a36Sopenharmony_ci } 519062306a36Sopenharmony_ci if (!info->linking) 519162306a36Sopenharmony_ci break; 519262306a36Sopenharmony_ci if (br_vlan_enabled(br_dev)) { 519362306a36Sopenharmony_ci br_vlan_get_proto(br_dev, &proto); 519462306a36Sopenharmony_ci if (proto == ETH_P_8021AD) { 519562306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Upper devices are not supported on top of an 802.1ad bridge"); 519662306a36Sopenharmony_ci return -EOPNOTSUPP; 519762306a36Sopenharmony_ci } 519862306a36Sopenharmony_ci } 519962306a36Sopenharmony_ci if (is_vlan_dev(upper_dev) && 520062306a36Sopenharmony_ci ntohs(vlan_dev_vlan_proto(upper_dev)) != ETH_P_8021Q) { 520162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are only supported with 802.1q VLAN protocol"); 520262306a36Sopenharmony_ci return -EOPNOTSUPP; 520362306a36Sopenharmony_ci } 520462306a36Sopenharmony_ci break; 520562306a36Sopenharmony_ci case NETDEV_CHANGEUPPER: 520662306a36Sopenharmony_ci upper_dev = info->upper_dev; 520762306a36Sopenharmony_ci if (info->linking) 520862306a36Sopenharmony_ci break; 520962306a36Sopenharmony_ci if (is_vlan_dev(upper_dev)) 521062306a36Sopenharmony_ci mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, upper_dev); 521162306a36Sopenharmony_ci if (netif_is_macvlan(upper_dev)) 521262306a36Sopenharmony_ci mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev); 521362306a36Sopenharmony_ci break; 521462306a36Sopenharmony_ci } 521562306a36Sopenharmony_ci 521662306a36Sopenharmony_ci return 0; 521762306a36Sopenharmony_ci} 521862306a36Sopenharmony_ci 521962306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_macvlan_event(struct net_device *macvlan_dev, 522062306a36Sopenharmony_ci unsigned long event, void *ptr) 522162306a36Sopenharmony_ci{ 522262306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(macvlan_dev); 522362306a36Sopenharmony_ci struct netdev_notifier_changeupper_info *info = ptr; 522462306a36Sopenharmony_ci struct netlink_ext_ack *extack; 522562306a36Sopenharmony_ci struct net_device *upper_dev; 522662306a36Sopenharmony_ci 522762306a36Sopenharmony_ci if (!mlxsw_sp || event != NETDEV_PRECHANGEUPPER) 522862306a36Sopenharmony_ci return 0; 522962306a36Sopenharmony_ci 523062306a36Sopenharmony_ci extack = netdev_notifier_info_to_extack(&info->info); 523162306a36Sopenharmony_ci upper_dev = info->upper_dev; 523262306a36Sopenharmony_ci 523362306a36Sopenharmony_ci if (!netif_is_l3_master(upper_dev)) { 523462306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type"); 523562306a36Sopenharmony_ci return -EOPNOTSUPP; 523662306a36Sopenharmony_ci } 523762306a36Sopenharmony_ci 523862306a36Sopenharmony_ci return 0; 523962306a36Sopenharmony_ci} 524062306a36Sopenharmony_ci 524162306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_vxlan_event(struct mlxsw_sp *mlxsw_sp, 524262306a36Sopenharmony_ci struct net_device *dev, 524362306a36Sopenharmony_ci unsigned long event, void *ptr) 524462306a36Sopenharmony_ci{ 524562306a36Sopenharmony_ci struct netdev_notifier_changeupper_info *cu_info; 524662306a36Sopenharmony_ci struct netdev_notifier_info *info = ptr; 524762306a36Sopenharmony_ci struct netlink_ext_ack *extack; 524862306a36Sopenharmony_ci struct net_device *upper_dev; 524962306a36Sopenharmony_ci 525062306a36Sopenharmony_ci extack = netdev_notifier_info_to_extack(info); 525162306a36Sopenharmony_ci 525262306a36Sopenharmony_ci switch (event) { 525362306a36Sopenharmony_ci case NETDEV_CHANGEUPPER: 525462306a36Sopenharmony_ci cu_info = container_of(info, 525562306a36Sopenharmony_ci struct netdev_notifier_changeupper_info, 525662306a36Sopenharmony_ci info); 525762306a36Sopenharmony_ci upper_dev = cu_info->upper_dev; 525862306a36Sopenharmony_ci if (!netif_is_bridge_master(upper_dev)) 525962306a36Sopenharmony_ci return 0; 526062306a36Sopenharmony_ci if (!mlxsw_sp_lower_get(upper_dev)) 526162306a36Sopenharmony_ci return 0; 526262306a36Sopenharmony_ci if (!mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack)) 526362306a36Sopenharmony_ci return -EOPNOTSUPP; 526462306a36Sopenharmony_ci if (cu_info->linking) { 526562306a36Sopenharmony_ci if (!netif_running(dev)) 526662306a36Sopenharmony_ci return 0; 526762306a36Sopenharmony_ci /* When the bridge is VLAN-aware, the VNI of the VxLAN 526862306a36Sopenharmony_ci * device needs to be mapped to a VLAN, but at this 526962306a36Sopenharmony_ci * point no VLANs are configured on the VxLAN device 527062306a36Sopenharmony_ci */ 527162306a36Sopenharmony_ci if (br_vlan_enabled(upper_dev)) 527262306a36Sopenharmony_ci return 0; 527362306a36Sopenharmony_ci return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, 527462306a36Sopenharmony_ci dev, 0, extack); 527562306a36Sopenharmony_ci } else { 527662306a36Sopenharmony_ci /* VLANs were already flushed, which triggered the 527762306a36Sopenharmony_ci * necessary cleanup 527862306a36Sopenharmony_ci */ 527962306a36Sopenharmony_ci if (br_vlan_enabled(upper_dev)) 528062306a36Sopenharmony_ci return 0; 528162306a36Sopenharmony_ci mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev); 528262306a36Sopenharmony_ci } 528362306a36Sopenharmony_ci break; 528462306a36Sopenharmony_ci case NETDEV_PRE_UP: 528562306a36Sopenharmony_ci upper_dev = netdev_master_upper_dev_get(dev); 528662306a36Sopenharmony_ci if (!upper_dev) 528762306a36Sopenharmony_ci return 0; 528862306a36Sopenharmony_ci if (!netif_is_bridge_master(upper_dev)) 528962306a36Sopenharmony_ci return 0; 529062306a36Sopenharmony_ci if (!mlxsw_sp_lower_get(upper_dev)) 529162306a36Sopenharmony_ci return 0; 529262306a36Sopenharmony_ci return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, dev, 0, 529362306a36Sopenharmony_ci extack); 529462306a36Sopenharmony_ci case NETDEV_DOWN: 529562306a36Sopenharmony_ci upper_dev = netdev_master_upper_dev_get(dev); 529662306a36Sopenharmony_ci if (!upper_dev) 529762306a36Sopenharmony_ci return 0; 529862306a36Sopenharmony_ci if (!netif_is_bridge_master(upper_dev)) 529962306a36Sopenharmony_ci return 0; 530062306a36Sopenharmony_ci if (!mlxsw_sp_lower_get(upper_dev)) 530162306a36Sopenharmony_ci return 0; 530262306a36Sopenharmony_ci mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev); 530362306a36Sopenharmony_ci break; 530462306a36Sopenharmony_ci } 530562306a36Sopenharmony_ci 530662306a36Sopenharmony_ci return 0; 530762306a36Sopenharmony_ci} 530862306a36Sopenharmony_ci 530962306a36Sopenharmony_cistatic int __mlxsw_sp_netdevice_event(struct mlxsw_sp *mlxsw_sp, 531062306a36Sopenharmony_ci unsigned long event, void *ptr, 531162306a36Sopenharmony_ci bool process_foreign) 531262306a36Sopenharmony_ci{ 531362306a36Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 531462306a36Sopenharmony_ci struct mlxsw_sp_span_entry *span_entry; 531562306a36Sopenharmony_ci int err = 0; 531662306a36Sopenharmony_ci 531762306a36Sopenharmony_ci if (event == NETDEV_UNREGISTER) { 531862306a36Sopenharmony_ci span_entry = mlxsw_sp_span_entry_find_by_port(mlxsw_sp, dev); 531962306a36Sopenharmony_ci if (span_entry) 532062306a36Sopenharmony_ci mlxsw_sp_span_entry_invalidate(mlxsw_sp, span_entry); 532162306a36Sopenharmony_ci } 532262306a36Sopenharmony_ci 532362306a36Sopenharmony_ci if (netif_is_vxlan(dev)) 532462306a36Sopenharmony_ci err = mlxsw_sp_netdevice_vxlan_event(mlxsw_sp, dev, event, ptr); 532562306a36Sopenharmony_ci else if (mlxsw_sp_port_dev_check(dev)) 532662306a36Sopenharmony_ci err = mlxsw_sp_netdevice_port_event(dev, dev, event, ptr, true); 532762306a36Sopenharmony_ci else if (netif_is_lag_master(dev)) 532862306a36Sopenharmony_ci err = mlxsw_sp_netdevice_lag_event(dev, event, ptr); 532962306a36Sopenharmony_ci else if (is_vlan_dev(dev)) 533062306a36Sopenharmony_ci err = mlxsw_sp_netdevice_vlan_event(mlxsw_sp, dev, event, ptr, 533162306a36Sopenharmony_ci process_foreign); 533262306a36Sopenharmony_ci else if (netif_is_bridge_master(dev)) 533362306a36Sopenharmony_ci err = mlxsw_sp_netdevice_bridge_event(mlxsw_sp, dev, event, ptr, 533462306a36Sopenharmony_ci process_foreign); 533562306a36Sopenharmony_ci else if (netif_is_macvlan(dev)) 533662306a36Sopenharmony_ci err = mlxsw_sp_netdevice_macvlan_event(dev, event, ptr); 533762306a36Sopenharmony_ci 533862306a36Sopenharmony_ci return err; 533962306a36Sopenharmony_ci} 534062306a36Sopenharmony_ci 534162306a36Sopenharmony_cistatic int mlxsw_sp_netdevice_event(struct notifier_block *nb, 534262306a36Sopenharmony_ci unsigned long event, void *ptr) 534362306a36Sopenharmony_ci{ 534462306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp; 534562306a36Sopenharmony_ci int err; 534662306a36Sopenharmony_ci 534762306a36Sopenharmony_ci mlxsw_sp = container_of(nb, struct mlxsw_sp, netdevice_nb); 534862306a36Sopenharmony_ci mlxsw_sp_span_respin(mlxsw_sp); 534962306a36Sopenharmony_ci err = __mlxsw_sp_netdevice_event(mlxsw_sp, event, ptr, false); 535062306a36Sopenharmony_ci 535162306a36Sopenharmony_ci return notifier_from_errno(err); 535262306a36Sopenharmony_ci} 535362306a36Sopenharmony_ci 535462306a36Sopenharmony_cistatic const struct pci_device_id mlxsw_sp1_pci_id_table[] = { 535562306a36Sopenharmony_ci {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM), 0}, 535662306a36Sopenharmony_ci {0, }, 535762306a36Sopenharmony_ci}; 535862306a36Sopenharmony_ci 535962306a36Sopenharmony_cistatic struct pci_driver mlxsw_sp1_pci_driver = { 536062306a36Sopenharmony_ci .name = mlxsw_sp1_driver_name, 536162306a36Sopenharmony_ci .id_table = mlxsw_sp1_pci_id_table, 536262306a36Sopenharmony_ci}; 536362306a36Sopenharmony_ci 536462306a36Sopenharmony_cistatic const struct pci_device_id mlxsw_sp2_pci_id_table[] = { 536562306a36Sopenharmony_ci {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM2), 0}, 536662306a36Sopenharmony_ci {0, }, 536762306a36Sopenharmony_ci}; 536862306a36Sopenharmony_ci 536962306a36Sopenharmony_cistatic struct pci_driver mlxsw_sp2_pci_driver = { 537062306a36Sopenharmony_ci .name = mlxsw_sp2_driver_name, 537162306a36Sopenharmony_ci .id_table = mlxsw_sp2_pci_id_table, 537262306a36Sopenharmony_ci}; 537362306a36Sopenharmony_ci 537462306a36Sopenharmony_cistatic const struct pci_device_id mlxsw_sp3_pci_id_table[] = { 537562306a36Sopenharmony_ci {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM3), 0}, 537662306a36Sopenharmony_ci {0, }, 537762306a36Sopenharmony_ci}; 537862306a36Sopenharmony_ci 537962306a36Sopenharmony_cistatic struct pci_driver mlxsw_sp3_pci_driver = { 538062306a36Sopenharmony_ci .name = mlxsw_sp3_driver_name, 538162306a36Sopenharmony_ci .id_table = mlxsw_sp3_pci_id_table, 538262306a36Sopenharmony_ci}; 538362306a36Sopenharmony_ci 538462306a36Sopenharmony_cistatic const struct pci_device_id mlxsw_sp4_pci_id_table[] = { 538562306a36Sopenharmony_ci {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM4), 0}, 538662306a36Sopenharmony_ci {0, }, 538762306a36Sopenharmony_ci}; 538862306a36Sopenharmony_ci 538962306a36Sopenharmony_cistatic struct pci_driver mlxsw_sp4_pci_driver = { 539062306a36Sopenharmony_ci .name = mlxsw_sp4_driver_name, 539162306a36Sopenharmony_ci .id_table = mlxsw_sp4_pci_id_table, 539262306a36Sopenharmony_ci}; 539362306a36Sopenharmony_ci 539462306a36Sopenharmony_cistatic int __init mlxsw_sp_module_init(void) 539562306a36Sopenharmony_ci{ 539662306a36Sopenharmony_ci int err; 539762306a36Sopenharmony_ci 539862306a36Sopenharmony_ci err = mlxsw_core_driver_register(&mlxsw_sp1_driver); 539962306a36Sopenharmony_ci if (err) 540062306a36Sopenharmony_ci return err; 540162306a36Sopenharmony_ci 540262306a36Sopenharmony_ci err = mlxsw_core_driver_register(&mlxsw_sp2_driver); 540362306a36Sopenharmony_ci if (err) 540462306a36Sopenharmony_ci goto err_sp2_core_driver_register; 540562306a36Sopenharmony_ci 540662306a36Sopenharmony_ci err = mlxsw_core_driver_register(&mlxsw_sp3_driver); 540762306a36Sopenharmony_ci if (err) 540862306a36Sopenharmony_ci goto err_sp3_core_driver_register; 540962306a36Sopenharmony_ci 541062306a36Sopenharmony_ci err = mlxsw_core_driver_register(&mlxsw_sp4_driver); 541162306a36Sopenharmony_ci if (err) 541262306a36Sopenharmony_ci goto err_sp4_core_driver_register; 541362306a36Sopenharmony_ci 541462306a36Sopenharmony_ci err = mlxsw_pci_driver_register(&mlxsw_sp1_pci_driver); 541562306a36Sopenharmony_ci if (err) 541662306a36Sopenharmony_ci goto err_sp1_pci_driver_register; 541762306a36Sopenharmony_ci 541862306a36Sopenharmony_ci err = mlxsw_pci_driver_register(&mlxsw_sp2_pci_driver); 541962306a36Sopenharmony_ci if (err) 542062306a36Sopenharmony_ci goto err_sp2_pci_driver_register; 542162306a36Sopenharmony_ci 542262306a36Sopenharmony_ci err = mlxsw_pci_driver_register(&mlxsw_sp3_pci_driver); 542362306a36Sopenharmony_ci if (err) 542462306a36Sopenharmony_ci goto err_sp3_pci_driver_register; 542562306a36Sopenharmony_ci 542662306a36Sopenharmony_ci err = mlxsw_pci_driver_register(&mlxsw_sp4_pci_driver); 542762306a36Sopenharmony_ci if (err) 542862306a36Sopenharmony_ci goto err_sp4_pci_driver_register; 542962306a36Sopenharmony_ci 543062306a36Sopenharmony_ci return 0; 543162306a36Sopenharmony_ci 543262306a36Sopenharmony_cierr_sp4_pci_driver_register: 543362306a36Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sp3_pci_driver); 543462306a36Sopenharmony_cierr_sp3_pci_driver_register: 543562306a36Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver); 543662306a36Sopenharmony_cierr_sp2_pci_driver_register: 543762306a36Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver); 543862306a36Sopenharmony_cierr_sp1_pci_driver_register: 543962306a36Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp4_driver); 544062306a36Sopenharmony_cierr_sp4_core_driver_register: 544162306a36Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp3_driver); 544262306a36Sopenharmony_cierr_sp3_core_driver_register: 544362306a36Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp2_driver); 544462306a36Sopenharmony_cierr_sp2_core_driver_register: 544562306a36Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp1_driver); 544662306a36Sopenharmony_ci return err; 544762306a36Sopenharmony_ci} 544862306a36Sopenharmony_ci 544962306a36Sopenharmony_cistatic void __exit mlxsw_sp_module_exit(void) 545062306a36Sopenharmony_ci{ 545162306a36Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sp4_pci_driver); 545262306a36Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sp3_pci_driver); 545362306a36Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver); 545462306a36Sopenharmony_ci mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver); 545562306a36Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp4_driver); 545662306a36Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp3_driver); 545762306a36Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp2_driver); 545862306a36Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_sp1_driver); 545962306a36Sopenharmony_ci} 546062306a36Sopenharmony_ci 546162306a36Sopenharmony_cimodule_init(mlxsw_sp_module_init); 546262306a36Sopenharmony_cimodule_exit(mlxsw_sp_module_exit); 546362306a36Sopenharmony_ci 546462306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 546562306a36Sopenharmony_ciMODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>"); 546662306a36Sopenharmony_ciMODULE_DESCRIPTION("Mellanox Spectrum driver"); 546762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mlxsw_sp1_pci_id_table); 546862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mlxsw_sp2_pci_id_table); 546962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mlxsw_sp3_pci_id_table); 547062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mlxsw_sp4_pci_id_table); 547162306a36Sopenharmony_ciMODULE_FIRMWARE(MLXSW_SP1_FW_FILENAME); 547262306a36Sopenharmony_ciMODULE_FIRMWARE(MLXSW_SP2_FW_FILENAME); 547362306a36Sopenharmony_ciMODULE_FIRMWARE(MLXSW_SP3_FW_FILENAME); 547462306a36Sopenharmony_ciMODULE_FIRMWARE(MLXSW_SP_LINECARDS_INI_BUNDLE_FILENAME); 5475