18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/kernel.h>
58c2ecf20Sopenharmony_ci#include <linux/module.h>
68c2ecf20Sopenharmony_ci#include <linux/types.h>
78c2ecf20Sopenharmony_ci#include <linux/pci.h>
88c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
98c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
108c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/device.h>
138c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
148c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
158c2ecf20Sopenharmony_ci#include <linux/if_bridge.h>
168c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
178c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
188c2ecf20Sopenharmony_ci#include <linux/bitops.h>
198c2ecf20Sopenharmony_ci#include <linux/list.h>
208c2ecf20Sopenharmony_ci#include <linux/notifier.h>
218c2ecf20Sopenharmony_ci#include <linux/dcbnl.h>
228c2ecf20Sopenharmony_ci#include <linux/inetdevice.h>
238c2ecf20Sopenharmony_ci#include <linux/netlink.h>
248c2ecf20Sopenharmony_ci#include <linux/jhash.h>
258c2ecf20Sopenharmony_ci#include <linux/log2.h>
268c2ecf20Sopenharmony_ci#include <net/switchdev.h>
278c2ecf20Sopenharmony_ci#include <net/pkt_cls.h>
288c2ecf20Sopenharmony_ci#include <net/netevent.h>
298c2ecf20Sopenharmony_ci#include <net/addrconf.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include "spectrum.h"
328c2ecf20Sopenharmony_ci#include "pci.h"
338c2ecf20Sopenharmony_ci#include "core.h"
348c2ecf20Sopenharmony_ci#include "core_env.h"
358c2ecf20Sopenharmony_ci#include "reg.h"
368c2ecf20Sopenharmony_ci#include "port.h"
378c2ecf20Sopenharmony_ci#include "trap.h"
388c2ecf20Sopenharmony_ci#include "txheader.h"
398c2ecf20Sopenharmony_ci#include "spectrum_cnt.h"
408c2ecf20Sopenharmony_ci#include "spectrum_dpipe.h"
418c2ecf20Sopenharmony_ci#include "spectrum_acl_flex_actions.h"
428c2ecf20Sopenharmony_ci#include "spectrum_span.h"
438c2ecf20Sopenharmony_ci#include "spectrum_ptp.h"
448c2ecf20Sopenharmony_ci#include "spectrum_trap.h"
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define MLXSW_SP1_FWREV_MAJOR 13
478c2ecf20Sopenharmony_ci#define MLXSW_SP1_FWREV_MINOR 2008
488c2ecf20Sopenharmony_ci#define MLXSW_SP1_FWREV_SUBMINOR 1310
498c2ecf20Sopenharmony_ci#define MLXSW_SP1_FWREV_CAN_RESET_MINOR 1702
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = {
528c2ecf20Sopenharmony_ci	.major = MLXSW_SP1_FWREV_MAJOR,
538c2ecf20Sopenharmony_ci	.minor = MLXSW_SP1_FWREV_MINOR,
548c2ecf20Sopenharmony_ci	.subminor = MLXSW_SP1_FWREV_SUBMINOR,
558c2ecf20Sopenharmony_ci	.can_reset_minor = MLXSW_SP1_FWREV_CAN_RESET_MINOR,
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define MLXSW_SP1_FW_FILENAME \
598c2ecf20Sopenharmony_ci	"mellanox/mlxsw_spectrum-" __stringify(MLXSW_SP1_FWREV_MAJOR) \
608c2ecf20Sopenharmony_ci	"." __stringify(MLXSW_SP1_FWREV_MINOR) \
618c2ecf20Sopenharmony_ci	"." __stringify(MLXSW_SP1_FWREV_SUBMINOR) ".mfa2"
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#define MLXSW_SP2_FWREV_MAJOR 29
648c2ecf20Sopenharmony_ci#define MLXSW_SP2_FWREV_MINOR 2008
658c2ecf20Sopenharmony_ci#define MLXSW_SP2_FWREV_SUBMINOR 1310
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic const struct mlxsw_fw_rev mlxsw_sp2_fw_rev = {
688c2ecf20Sopenharmony_ci	.major = MLXSW_SP2_FWREV_MAJOR,
698c2ecf20Sopenharmony_ci	.minor = MLXSW_SP2_FWREV_MINOR,
708c2ecf20Sopenharmony_ci	.subminor = MLXSW_SP2_FWREV_SUBMINOR,
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define MLXSW_SP2_FW_FILENAME \
748c2ecf20Sopenharmony_ci	"mellanox/mlxsw_spectrum2-" __stringify(MLXSW_SP2_FWREV_MAJOR) \
758c2ecf20Sopenharmony_ci	"." __stringify(MLXSW_SP2_FWREV_MINOR) \
768c2ecf20Sopenharmony_ci	"." __stringify(MLXSW_SP2_FWREV_SUBMINOR) ".mfa2"
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#define MLXSW_SP3_FWREV_MAJOR 30
798c2ecf20Sopenharmony_ci#define MLXSW_SP3_FWREV_MINOR 2008
808c2ecf20Sopenharmony_ci#define MLXSW_SP3_FWREV_SUBMINOR 1310
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic const struct mlxsw_fw_rev mlxsw_sp3_fw_rev = {
838c2ecf20Sopenharmony_ci	.major = MLXSW_SP3_FWREV_MAJOR,
848c2ecf20Sopenharmony_ci	.minor = MLXSW_SP3_FWREV_MINOR,
858c2ecf20Sopenharmony_ci	.subminor = MLXSW_SP3_FWREV_SUBMINOR,
868c2ecf20Sopenharmony_ci};
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#define MLXSW_SP3_FW_FILENAME \
898c2ecf20Sopenharmony_ci	"mellanox/mlxsw_spectrum3-" __stringify(MLXSW_SP3_FWREV_MAJOR) \
908c2ecf20Sopenharmony_ci	"." __stringify(MLXSW_SP3_FWREV_MINOR) \
918c2ecf20Sopenharmony_ci	"." __stringify(MLXSW_SP3_FWREV_SUBMINOR) ".mfa2"
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic const char mlxsw_sp1_driver_name[] = "mlxsw_spectrum";
948c2ecf20Sopenharmony_cistatic const char mlxsw_sp2_driver_name[] = "mlxsw_spectrum2";
958c2ecf20Sopenharmony_cistatic const char mlxsw_sp3_driver_name[] = "mlxsw_spectrum3";
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic const unsigned char mlxsw_sp1_mac_mask[ETH_ALEN] = {
988c2ecf20Sopenharmony_ci	0xff, 0xff, 0xff, 0xff, 0xfc, 0x00
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_cistatic const unsigned char mlxsw_sp2_mac_mask[ETH_ALEN] = {
1018c2ecf20Sopenharmony_ci	0xff, 0xff, 0xff, 0xff, 0xf0, 0x00
1028c2ecf20Sopenharmony_ci};
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/* tx_hdr_version
1058c2ecf20Sopenharmony_ci * Tx header version.
1068c2ecf20Sopenharmony_ci * Must be set to 1.
1078c2ecf20Sopenharmony_ci */
1088c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, version, 0x00, 28, 4);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci/* tx_hdr_ctl
1118c2ecf20Sopenharmony_ci * Packet control type.
1128c2ecf20Sopenharmony_ci * 0 - Ethernet control (e.g. EMADs, LACP)
1138c2ecf20Sopenharmony_ci * 1 - Ethernet data
1148c2ecf20Sopenharmony_ci */
1158c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, ctl, 0x00, 26, 2);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/* tx_hdr_proto
1188c2ecf20Sopenharmony_ci * Packet protocol type. Must be set to 1 (Ethernet).
1198c2ecf20Sopenharmony_ci */
1208c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, proto, 0x00, 21, 3);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/* tx_hdr_rx_is_router
1238c2ecf20Sopenharmony_ci * Packet is sent from the router. Valid for data packets only.
1248c2ecf20Sopenharmony_ci */
1258c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, rx_is_router, 0x00, 19, 1);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/* tx_hdr_fid_valid
1288c2ecf20Sopenharmony_ci * Indicates if the 'fid' field is valid and should be used for
1298c2ecf20Sopenharmony_ci * forwarding lookup. Valid for data packets only.
1308c2ecf20Sopenharmony_ci */
1318c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, fid_valid, 0x00, 16, 1);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/* tx_hdr_swid
1348c2ecf20Sopenharmony_ci * Switch partition ID. Must be set to 0.
1358c2ecf20Sopenharmony_ci */
1368c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, swid, 0x00, 12, 3);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/* tx_hdr_control_tclass
1398c2ecf20Sopenharmony_ci * Indicates if the packet should use the control TClass and not one
1408c2ecf20Sopenharmony_ci * of the data TClasses.
1418c2ecf20Sopenharmony_ci */
1428c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, control_tclass, 0x00, 6, 1);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/* tx_hdr_etclass
1458c2ecf20Sopenharmony_ci * Egress TClass to be used on the egress device on the egress port.
1468c2ecf20Sopenharmony_ci */
1478c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, etclass, 0x00, 0, 4);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci/* tx_hdr_port_mid
1508c2ecf20Sopenharmony_ci * Destination local port for unicast packets.
1518c2ecf20Sopenharmony_ci * Destination multicast ID for multicast packets.
1528c2ecf20Sopenharmony_ci *
1538c2ecf20Sopenharmony_ci * Control packets are directed to a specific egress port, while data
1548c2ecf20Sopenharmony_ci * packets are transmitted through the CPU port (0) into the switch partition,
1558c2ecf20Sopenharmony_ci * where forwarding rules are applied.
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, port_mid, 0x04, 16, 16);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci/* tx_hdr_fid
1608c2ecf20Sopenharmony_ci * Forwarding ID used for L2 forwarding lookup. Valid only if 'fid_valid' is
1618c2ecf20Sopenharmony_ci * set, otherwise calculated based on the packet's VID using VID to FID mapping.
1628c2ecf20Sopenharmony_ci * Valid for data packets only.
1638c2ecf20Sopenharmony_ci */
1648c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, fid, 0x08, 0, 16);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci/* tx_hdr_type
1678c2ecf20Sopenharmony_ci * 0 - Data packets
1688c2ecf20Sopenharmony_ci * 6 - Control packets
1698c2ecf20Sopenharmony_ci */
1708c2ecf20Sopenharmony_ciMLXSW_ITEM32(tx, hdr, type, 0x0C, 0, 4);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ciint mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp,
1738c2ecf20Sopenharmony_ci			      unsigned int counter_index, u64 *packets,
1748c2ecf20Sopenharmony_ci			      u64 *bytes)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	char mgpc_pl[MLXSW_REG_MGPC_LEN];
1778c2ecf20Sopenharmony_ci	int err;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_NOP,
1808c2ecf20Sopenharmony_ci			    MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES);
1818c2ecf20Sopenharmony_ci	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl);
1828c2ecf20Sopenharmony_ci	if (err)
1838c2ecf20Sopenharmony_ci		return err;
1848c2ecf20Sopenharmony_ci	if (packets)
1858c2ecf20Sopenharmony_ci		*packets = mlxsw_reg_mgpc_packet_counter_get(mgpc_pl);
1868c2ecf20Sopenharmony_ci	if (bytes)
1878c2ecf20Sopenharmony_ci		*bytes = mlxsw_reg_mgpc_byte_counter_get(mgpc_pl);
1888c2ecf20Sopenharmony_ci	return 0;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic int mlxsw_sp_flow_counter_clear(struct mlxsw_sp *mlxsw_sp,
1928c2ecf20Sopenharmony_ci				       unsigned int counter_index)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	char mgpc_pl[MLXSW_REG_MGPC_LEN];
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_CLEAR,
1978c2ecf20Sopenharmony_ci			    MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES);
1988c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ciint mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp,
2028c2ecf20Sopenharmony_ci				unsigned int *p_counter_index)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	int err;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	err = mlxsw_sp_counter_alloc(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW,
2078c2ecf20Sopenharmony_ci				     p_counter_index);
2088c2ecf20Sopenharmony_ci	if (err)
2098c2ecf20Sopenharmony_ci		return err;
2108c2ecf20Sopenharmony_ci	err = mlxsw_sp_flow_counter_clear(mlxsw_sp, *p_counter_index);
2118c2ecf20Sopenharmony_ci	if (err)
2128c2ecf20Sopenharmony_ci		goto err_counter_clear;
2138c2ecf20Sopenharmony_ci	return 0;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cierr_counter_clear:
2168c2ecf20Sopenharmony_ci	mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW,
2178c2ecf20Sopenharmony_ci			      *p_counter_index);
2188c2ecf20Sopenharmony_ci	return err;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_civoid mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp,
2228c2ecf20Sopenharmony_ci				unsigned int counter_index)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	 mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW,
2258c2ecf20Sopenharmony_ci			       counter_index);
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic void mlxsw_sp_txhdr_construct(struct sk_buff *skb,
2298c2ecf20Sopenharmony_ci				     const struct mlxsw_tx_info *tx_info)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	memset(txhdr, 0, MLXSW_TXHDR_LEN);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	mlxsw_tx_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1);
2368c2ecf20Sopenharmony_ci	mlxsw_tx_hdr_ctl_set(txhdr, MLXSW_TXHDR_ETH_CTL);
2378c2ecf20Sopenharmony_ci	mlxsw_tx_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH);
2388c2ecf20Sopenharmony_ci	mlxsw_tx_hdr_swid_set(txhdr, 0);
2398c2ecf20Sopenharmony_ci	mlxsw_tx_hdr_control_tclass_set(txhdr, 1);
2408c2ecf20Sopenharmony_ci	mlxsw_tx_hdr_port_mid_set(txhdr, tx_info->local_port);
2418c2ecf20Sopenharmony_ci	mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cienum mlxsw_reg_spms_state mlxsw_sp_stp_spms_state(u8 state)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	switch (state) {
2478c2ecf20Sopenharmony_ci	case BR_STATE_FORWARDING:
2488c2ecf20Sopenharmony_ci		return MLXSW_REG_SPMS_STATE_FORWARDING;
2498c2ecf20Sopenharmony_ci	case BR_STATE_LEARNING:
2508c2ecf20Sopenharmony_ci		return MLXSW_REG_SPMS_STATE_LEARNING;
2518c2ecf20Sopenharmony_ci	case BR_STATE_LISTENING:
2528c2ecf20Sopenharmony_ci	case BR_STATE_DISABLED:
2538c2ecf20Sopenharmony_ci	case BR_STATE_BLOCKING:
2548c2ecf20Sopenharmony_ci		return MLXSW_REG_SPMS_STATE_DISCARDING;
2558c2ecf20Sopenharmony_ci	default:
2568c2ecf20Sopenharmony_ci		BUG();
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ciint mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
2618c2ecf20Sopenharmony_ci			      u8 state)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	enum mlxsw_reg_spms_state spms_state = mlxsw_sp_stp_spms_state(state);
2648c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
2658c2ecf20Sopenharmony_ci	char *spms_pl;
2668c2ecf20Sopenharmony_ci	int err;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL);
2698c2ecf20Sopenharmony_ci	if (!spms_pl)
2708c2ecf20Sopenharmony_ci		return -ENOMEM;
2718c2ecf20Sopenharmony_ci	mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port);
2728c2ecf20Sopenharmony_ci	mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl);
2758c2ecf20Sopenharmony_ci	kfree(spms_pl);
2768c2ecf20Sopenharmony_ci	return err;
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic int mlxsw_sp_base_mac_get(struct mlxsw_sp *mlxsw_sp)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	char spad_pl[MLXSW_REG_SPAD_LEN] = {0};
2828c2ecf20Sopenharmony_ci	int err;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(spad), spad_pl);
2858c2ecf20Sopenharmony_ci	if (err)
2868c2ecf20Sopenharmony_ci		return err;
2878c2ecf20Sopenharmony_ci	mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_sp->base_mac);
2888c2ecf20Sopenharmony_ci	return 0;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ciint mlxsw_sp_port_admin_status_set(struct mlxsw_sp_port *mlxsw_sp_port,
2928c2ecf20Sopenharmony_ci				   bool is_up)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
2958c2ecf20Sopenharmony_ci	char paos_pl[MLXSW_REG_PAOS_LEN];
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	mlxsw_reg_paos_pack(paos_pl, mlxsw_sp_port->local_port,
2988c2ecf20Sopenharmony_ci			    is_up ? MLXSW_PORT_ADMIN_STATUS_UP :
2998c2ecf20Sopenharmony_ci			    MLXSW_PORT_ADMIN_STATUS_DOWN);
3008c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(paos), paos_pl);
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_dev_addr_set(struct mlxsw_sp_port *mlxsw_sp_port,
3048c2ecf20Sopenharmony_ci				      unsigned char *addr)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
3078c2ecf20Sopenharmony_ci	char ppad_pl[MLXSW_REG_PPAD_LEN];
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	mlxsw_reg_ppad_pack(ppad_pl, true, mlxsw_sp_port->local_port);
3108c2ecf20Sopenharmony_ci	mlxsw_reg_ppad_mac_memcpy_to(ppad_pl, addr);
3118c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ppad), ppad_pl);
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_dev_addr_init(struct mlxsw_sp_port *mlxsw_sp_port)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
3178c2ecf20Sopenharmony_ci	unsigned char *addr = mlxsw_sp_port->dev->dev_addr;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	ether_addr_copy(addr, mlxsw_sp->base_mac);
3208c2ecf20Sopenharmony_ci	addr[ETH_ALEN - 1] += mlxsw_sp_port->local_port;
3218c2ecf20Sopenharmony_ci	return mlxsw_sp_port_dev_addr_set(mlxsw_sp_port, addr);
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_max_mtu_get(struct mlxsw_sp_port *mlxsw_sp_port, int *p_max_mtu)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
3278c2ecf20Sopenharmony_ci	char pmtu_pl[MLXSW_REG_PMTU_LEN];
3288c2ecf20Sopenharmony_ci	int err;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sp_port->local_port, 0);
3318c2ecf20Sopenharmony_ci	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl);
3328c2ecf20Sopenharmony_ci	if (err)
3338c2ecf20Sopenharmony_ci		return err;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	*p_max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl);
3368c2ecf20Sopenharmony_ci	return 0;
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_mtu_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
3428c2ecf20Sopenharmony_ci	char pmtu_pl[MLXSW_REG_PMTU_LEN];
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	mtu += MLXSW_TXHDR_LEN + ETH_HLEN;
3458c2ecf20Sopenharmony_ci	if (mtu > mlxsw_sp_port->max_mtu)
3468c2ecf20Sopenharmony_ci		return -EINVAL;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sp_port->local_port, mtu);
3498c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl);
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_swid_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 swid)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
3558c2ecf20Sopenharmony_ci	char pspa_pl[MLXSW_REG_PSPA_LEN];
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sp_port->local_port);
3588c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pspa), pspa_pl);
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ciint mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
3648c2ecf20Sopenharmony_ci	char svpe_pl[MLXSW_REG_SVPE_LEN];
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	mlxsw_reg_svpe_pack(svpe_pl, mlxsw_sp_port->local_port, enable);
3678c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svpe), svpe_pl);
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ciint mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,
3718c2ecf20Sopenharmony_ci				   bool learn_enable)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
3748c2ecf20Sopenharmony_ci	char *spvmlr_pl;
3758c2ecf20Sopenharmony_ci	int err;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	spvmlr_pl = kmalloc(MLXSW_REG_SPVMLR_LEN, GFP_KERNEL);
3788c2ecf20Sopenharmony_ci	if (!spvmlr_pl)
3798c2ecf20Sopenharmony_ci		return -ENOMEM;
3808c2ecf20Sopenharmony_ci	mlxsw_reg_spvmlr_pack(spvmlr_pl, mlxsw_sp_port->local_port, vid, vid,
3818c2ecf20Sopenharmony_ci			      learn_enable);
3828c2ecf20Sopenharmony_ci	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvmlr), spvmlr_pl);
3838c2ecf20Sopenharmony_ci	kfree(spvmlr_pl);
3848c2ecf20Sopenharmony_ci	return err;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port,
3888c2ecf20Sopenharmony_ci				    u16 vid)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
3918c2ecf20Sopenharmony_ci	char spvid_pl[MLXSW_REG_SPVID_LEN];
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	mlxsw_reg_spvid_pack(spvid_pl, mlxsw_sp_port->local_port, vid);
3948c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl);
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port *mlxsw_sp_port,
3988c2ecf20Sopenharmony_ci					    bool allow)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
4018c2ecf20Sopenharmony_ci	char spaft_pl[MLXSW_REG_SPAFT_LEN];
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	mlxsw_reg_spaft_pack(spaft_pl, mlxsw_sp_port->local_port, allow);
4048c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spaft), spaft_pl);
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ciint mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	int err;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	if (!vid) {
4128c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, false);
4138c2ecf20Sopenharmony_ci		if (err)
4148c2ecf20Sopenharmony_ci			return err;
4158c2ecf20Sopenharmony_ci	} else {
4168c2ecf20Sopenharmony_ci		err = __mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid);
4178c2ecf20Sopenharmony_ci		if (err)
4188c2ecf20Sopenharmony_ci			return err;
4198c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, true);
4208c2ecf20Sopenharmony_ci		if (err)
4218c2ecf20Sopenharmony_ci			goto err_port_allow_untagged_set;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	mlxsw_sp_port->pvid = vid;
4258c2ecf20Sopenharmony_ci	return 0;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cierr_port_allow_untagged_set:
4288c2ecf20Sopenharmony_ci	__mlxsw_sp_port_pvid_set(mlxsw_sp_port, mlxsw_sp_port->pvid);
4298c2ecf20Sopenharmony_ci	return err;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int
4338c2ecf20Sopenharmony_cimlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
4368c2ecf20Sopenharmony_ci	char sspr_pl[MLXSW_REG_SSPR_LEN];
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	mlxsw_reg_sspr_pack(sspr_pl, mlxsw_sp_port->local_port);
4398c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sspr), sspr_pl);
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic int
4438c2ecf20Sopenharmony_cimlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, u8 local_port,
4448c2ecf20Sopenharmony_ci			      struct mlxsw_sp_port_mapping *port_mapping)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	char pmlp_pl[MLXSW_REG_PMLP_LEN];
4478c2ecf20Sopenharmony_ci	bool separate_rxtx;
4488c2ecf20Sopenharmony_ci	u8 module;
4498c2ecf20Sopenharmony_ci	u8 width;
4508c2ecf20Sopenharmony_ci	int err;
4518c2ecf20Sopenharmony_ci	int i;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
4548c2ecf20Sopenharmony_ci	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
4558c2ecf20Sopenharmony_ci	if (err)
4568c2ecf20Sopenharmony_ci		return err;
4578c2ecf20Sopenharmony_ci	module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
4588c2ecf20Sopenharmony_ci	width = mlxsw_reg_pmlp_width_get(pmlp_pl);
4598c2ecf20Sopenharmony_ci	separate_rxtx = mlxsw_reg_pmlp_rxtx_get(pmlp_pl);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	if (width && !is_power_of_2(width)) {
4628c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: width value is not power of 2\n",
4638c2ecf20Sopenharmony_ci			local_port);
4648c2ecf20Sopenharmony_ci		return -EINVAL;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	for (i = 0; i < width; i++) {
4688c2ecf20Sopenharmony_ci		if (mlxsw_reg_pmlp_module_get(pmlp_pl, i) != module) {
4698c2ecf20Sopenharmony_ci			dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: contains multiple modules\n",
4708c2ecf20Sopenharmony_ci				local_port);
4718c2ecf20Sopenharmony_ci			return -EINVAL;
4728c2ecf20Sopenharmony_ci		}
4738c2ecf20Sopenharmony_ci		if (separate_rxtx &&
4748c2ecf20Sopenharmony_ci		    mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) !=
4758c2ecf20Sopenharmony_ci		    mlxsw_reg_pmlp_rx_lane_get(pmlp_pl, i)) {
4768c2ecf20Sopenharmony_ci			dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are different\n",
4778c2ecf20Sopenharmony_ci				local_port);
4788c2ecf20Sopenharmony_ci			return -EINVAL;
4798c2ecf20Sopenharmony_ci		}
4808c2ecf20Sopenharmony_ci		if (mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) != i) {
4818c2ecf20Sopenharmony_ci			dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are not sequential\n",
4828c2ecf20Sopenharmony_ci				local_port);
4838c2ecf20Sopenharmony_ci			return -EINVAL;
4848c2ecf20Sopenharmony_ci		}
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	port_mapping->module = module;
4888c2ecf20Sopenharmony_ci	port_mapping->width = width;
4898c2ecf20Sopenharmony_ci	port_mapping->lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0);
4908c2ecf20Sopenharmony_ci	return 0;
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_module_map(struct mlxsw_sp_port *mlxsw_sp_port)
4948c2ecf20Sopenharmony_ci{
4958c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_mapping *port_mapping = &mlxsw_sp_port->mapping;
4968c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
4978c2ecf20Sopenharmony_ci	char pmlp_pl[MLXSW_REG_PMLP_LEN];
4988c2ecf20Sopenharmony_ci	int i;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sp_port->local_port);
5018c2ecf20Sopenharmony_ci	mlxsw_reg_pmlp_width_set(pmlp_pl, port_mapping->width);
5028c2ecf20Sopenharmony_ci	for (i = 0; i < port_mapping->width; i++) {
5038c2ecf20Sopenharmony_ci		mlxsw_reg_pmlp_module_set(pmlp_pl, i, port_mapping->module);
5048c2ecf20Sopenharmony_ci		mlxsw_reg_pmlp_tx_lane_set(pmlp_pl, i, port_mapping->lane + i); /* Rx & Tx */
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_module_unmap(struct mlxsw_sp_port *mlxsw_sp_port)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
5138c2ecf20Sopenharmony_ci	char pmlp_pl[MLXSW_REG_PMLP_LEN];
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sp_port->local_port);
5168c2ecf20Sopenharmony_ci	mlxsw_reg_pmlp_width_set(pmlp_pl, 0);
5178c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_open(struct net_device *dev)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
5238c2ecf20Sopenharmony_ci	int err;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);
5268c2ecf20Sopenharmony_ci	if (err)
5278c2ecf20Sopenharmony_ci		return err;
5288c2ecf20Sopenharmony_ci	netif_start_queue(dev);
5298c2ecf20Sopenharmony_ci	return 0;
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_stop(struct net_device *dev)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	netif_stop_queue(dev);
5378c2ecf20Sopenharmony_ci	return mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb,
5418c2ecf20Sopenharmony_ci				      struct net_device *dev)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
5448c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
5458c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_pcpu_stats *pcpu_stats;
5468c2ecf20Sopenharmony_ci	const struct mlxsw_tx_info tx_info = {
5478c2ecf20Sopenharmony_ci		.local_port = mlxsw_sp_port->local_port,
5488c2ecf20Sopenharmony_ci		.is_emad = false,
5498c2ecf20Sopenharmony_ci	};
5508c2ecf20Sopenharmony_ci	u64 len;
5518c2ecf20Sopenharmony_ci	int err;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {
5548c2ecf20Sopenharmony_ci		this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
5558c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
5568c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	if (mlxsw_core_skb_transmit_busy(mlxsw_sp->core, &tx_info))
5628c2ecf20Sopenharmony_ci		return NETDEV_TX_BUSY;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	if (eth_skb_pad(skb)) {
5658c2ecf20Sopenharmony_ci		this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
5668c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	mlxsw_sp_txhdr_construct(skb, &tx_info);
5708c2ecf20Sopenharmony_ci	/* TX header is consumed by HW on the way so we shouldn't count its
5718c2ecf20Sopenharmony_ci	 * bytes as being sent.
5728c2ecf20Sopenharmony_ci	 */
5738c2ecf20Sopenharmony_ci	len = skb->len - MLXSW_TXHDR_LEN;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	/* Due to a race we might fail here because of a full queue. In that
5768c2ecf20Sopenharmony_ci	 * unlikely case we simply drop the packet.
5778c2ecf20Sopenharmony_ci	 */
5788c2ecf20Sopenharmony_ci	err = mlxsw_core_skb_transmit(mlxsw_sp->core, skb, &tx_info);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	if (!err) {
5818c2ecf20Sopenharmony_ci		pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats);
5828c2ecf20Sopenharmony_ci		u64_stats_update_begin(&pcpu_stats->syncp);
5838c2ecf20Sopenharmony_ci		pcpu_stats->tx_packets++;
5848c2ecf20Sopenharmony_ci		pcpu_stats->tx_bytes += len;
5858c2ecf20Sopenharmony_ci		u64_stats_update_end(&pcpu_stats->syncp);
5868c2ecf20Sopenharmony_ci	} else {
5878c2ecf20Sopenharmony_ci		this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);
5888c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic void mlxsw_sp_set_rx_mode(struct net_device *dev)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_set_mac_address(struct net_device *dev, void *p)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
6008c2ecf20Sopenharmony_ci	struct sockaddr *addr = p;
6018c2ecf20Sopenharmony_ci	int err;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	if (!is_valid_ether_addr(addr->sa_data))
6048c2ecf20Sopenharmony_ci		return -EADDRNOTAVAIL;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_dev_addr_set(mlxsw_sp_port, addr->sa_data);
6078c2ecf20Sopenharmony_ci	if (err)
6088c2ecf20Sopenharmony_ci		return err;
6098c2ecf20Sopenharmony_ci	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
6108c2ecf20Sopenharmony_ci	return 0;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_change_mtu(struct net_device *dev, int mtu)
6148c2ecf20Sopenharmony_ci{
6158c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
6168c2ecf20Sopenharmony_ci	struct mlxsw_sp_hdroom orig_hdroom;
6178c2ecf20Sopenharmony_ci	struct mlxsw_sp_hdroom hdroom;
6188c2ecf20Sopenharmony_ci	int err;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	orig_hdroom = *mlxsw_sp_port->hdroom;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	hdroom = orig_hdroom;
6238c2ecf20Sopenharmony_ci	hdroom.mtu = mtu;
6248c2ecf20Sopenharmony_ci	mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
6278c2ecf20Sopenharmony_ci	if (err) {
6288c2ecf20Sopenharmony_ci		netdev_err(dev, "Failed to configure port's headroom\n");
6298c2ecf20Sopenharmony_ci		return err;
6308c2ecf20Sopenharmony_ci	}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, mtu);
6338c2ecf20Sopenharmony_ci	if (err)
6348c2ecf20Sopenharmony_ci		goto err_port_mtu_set;
6358c2ecf20Sopenharmony_ci	dev->mtu = mtu;
6368c2ecf20Sopenharmony_ci	return 0;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cierr_port_mtu_set:
6398c2ecf20Sopenharmony_ci	mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);
6408c2ecf20Sopenharmony_ci	return err;
6418c2ecf20Sopenharmony_ci}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_cistatic int
6448c2ecf20Sopenharmony_cimlxsw_sp_port_get_sw_stats64(const struct net_device *dev,
6458c2ecf20Sopenharmony_ci			     struct rtnl_link_stats64 *stats)
6468c2ecf20Sopenharmony_ci{
6478c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
6488c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_pcpu_stats *p;
6498c2ecf20Sopenharmony_ci	u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
6508c2ecf20Sopenharmony_ci	u32 tx_dropped = 0;
6518c2ecf20Sopenharmony_ci	unsigned int start;
6528c2ecf20Sopenharmony_ci	int i;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	for_each_possible_cpu(i) {
6558c2ecf20Sopenharmony_ci		p = per_cpu_ptr(mlxsw_sp_port->pcpu_stats, i);
6568c2ecf20Sopenharmony_ci		do {
6578c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&p->syncp);
6588c2ecf20Sopenharmony_ci			rx_packets	= p->rx_packets;
6598c2ecf20Sopenharmony_ci			rx_bytes	= p->rx_bytes;
6608c2ecf20Sopenharmony_ci			tx_packets	= p->tx_packets;
6618c2ecf20Sopenharmony_ci			tx_bytes	= p->tx_bytes;
6628c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&p->syncp, start));
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci		stats->rx_packets	+= rx_packets;
6658c2ecf20Sopenharmony_ci		stats->rx_bytes		+= rx_bytes;
6668c2ecf20Sopenharmony_ci		stats->tx_packets	+= tx_packets;
6678c2ecf20Sopenharmony_ci		stats->tx_bytes		+= tx_bytes;
6688c2ecf20Sopenharmony_ci		/* tx_dropped is u32, updated without syncp protection. */
6698c2ecf20Sopenharmony_ci		tx_dropped	+= p->tx_dropped;
6708c2ecf20Sopenharmony_ci	}
6718c2ecf20Sopenharmony_ci	stats->tx_dropped	= tx_dropped;
6728c2ecf20Sopenharmony_ci	return 0;
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_cistatic bool mlxsw_sp_port_has_offload_stats(const struct net_device *dev, int attr_id)
6768c2ecf20Sopenharmony_ci{
6778c2ecf20Sopenharmony_ci	switch (attr_id) {
6788c2ecf20Sopenharmony_ci	case IFLA_OFFLOAD_XSTATS_CPU_HIT:
6798c2ecf20Sopenharmony_ci		return true;
6808c2ecf20Sopenharmony_ci	}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	return false;
6838c2ecf20Sopenharmony_ci}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_get_offload_stats(int attr_id, const struct net_device *dev,
6868c2ecf20Sopenharmony_ci					   void *sp)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	switch (attr_id) {
6898c2ecf20Sopenharmony_ci	case IFLA_OFFLOAD_XSTATS_CPU_HIT:
6908c2ecf20Sopenharmony_ci		return mlxsw_sp_port_get_sw_stats64(dev, sp);
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	return -EINVAL;
6948c2ecf20Sopenharmony_ci}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ciint mlxsw_sp_port_get_stats_raw(struct net_device *dev, int grp,
6978c2ecf20Sopenharmony_ci				int prio, char *ppcnt_pl)
6988c2ecf20Sopenharmony_ci{
6998c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
7008c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sp_port->local_port, grp, prio);
7038c2ecf20Sopenharmony_ci	return mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ppcnt), ppcnt_pl);
7048c2ecf20Sopenharmony_ci}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_get_hw_stats(struct net_device *dev,
7078c2ecf20Sopenharmony_ci				      struct rtnl_link_stats64 *stats)
7088c2ecf20Sopenharmony_ci{
7098c2ecf20Sopenharmony_ci	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
7108c2ecf20Sopenharmony_ci	int err;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,
7138c2ecf20Sopenharmony_ci					  0, ppcnt_pl);
7148c2ecf20Sopenharmony_ci	if (err)
7158c2ecf20Sopenharmony_ci		goto out;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	stats->tx_packets =
7188c2ecf20Sopenharmony_ci		mlxsw_reg_ppcnt_a_frames_transmitted_ok_get(ppcnt_pl);
7198c2ecf20Sopenharmony_ci	stats->rx_packets =
7208c2ecf20Sopenharmony_ci		mlxsw_reg_ppcnt_a_frames_received_ok_get(ppcnt_pl);
7218c2ecf20Sopenharmony_ci	stats->tx_bytes =
7228c2ecf20Sopenharmony_ci		mlxsw_reg_ppcnt_a_octets_transmitted_ok_get(ppcnt_pl);
7238c2ecf20Sopenharmony_ci	stats->rx_bytes =
7248c2ecf20Sopenharmony_ci		mlxsw_reg_ppcnt_a_octets_received_ok_get(ppcnt_pl);
7258c2ecf20Sopenharmony_ci	stats->multicast =
7268c2ecf20Sopenharmony_ci		mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get(ppcnt_pl);
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	stats->rx_crc_errors =
7298c2ecf20Sopenharmony_ci		mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get(ppcnt_pl);
7308c2ecf20Sopenharmony_ci	stats->rx_frame_errors =
7318c2ecf20Sopenharmony_ci		mlxsw_reg_ppcnt_a_alignment_errors_get(ppcnt_pl);
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	stats->rx_length_errors = (
7348c2ecf20Sopenharmony_ci		mlxsw_reg_ppcnt_a_in_range_length_errors_get(ppcnt_pl) +
7358c2ecf20Sopenharmony_ci		mlxsw_reg_ppcnt_a_out_of_range_length_field_get(ppcnt_pl) +
7368c2ecf20Sopenharmony_ci		mlxsw_reg_ppcnt_a_frame_too_long_errors_get(ppcnt_pl));
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	stats->rx_errors = (stats->rx_crc_errors +
7398c2ecf20Sopenharmony_ci		stats->rx_frame_errors + stats->rx_length_errors);
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ciout:
7428c2ecf20Sopenharmony_ci	return err;
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_cistatic void
7468c2ecf20Sopenharmony_cimlxsw_sp_port_get_hw_xstats(struct net_device *dev,
7478c2ecf20Sopenharmony_ci			    struct mlxsw_sp_port_xstats *xstats)
7488c2ecf20Sopenharmony_ci{
7498c2ecf20Sopenharmony_ci	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];
7508c2ecf20Sopenharmony_ci	int err, i;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_EXT_CNT, 0,
7538c2ecf20Sopenharmony_ci					  ppcnt_pl);
7548c2ecf20Sopenharmony_ci	if (!err)
7558c2ecf20Sopenharmony_ci		xstats->ecn = mlxsw_reg_ppcnt_ecn_marked_get(ppcnt_pl);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	for (i = 0; i < TC_MAX_QUEUE; i++) {
7588c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_get_stats_raw(dev,
7598c2ecf20Sopenharmony_ci						  MLXSW_REG_PPCNT_TC_CONG_TC,
7608c2ecf20Sopenharmony_ci						  i, ppcnt_pl);
7618c2ecf20Sopenharmony_ci		if (!err)
7628c2ecf20Sopenharmony_ci			xstats->wred_drop[i] =
7638c2ecf20Sopenharmony_ci				mlxsw_reg_ppcnt_wred_discard_get(ppcnt_pl);
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_TC_CNT,
7668c2ecf20Sopenharmony_ci						  i, ppcnt_pl);
7678c2ecf20Sopenharmony_ci		if (err)
7688c2ecf20Sopenharmony_ci			continue;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci		xstats->backlog[i] =
7718c2ecf20Sopenharmony_ci			mlxsw_reg_ppcnt_tc_transmit_queue_get(ppcnt_pl);
7728c2ecf20Sopenharmony_ci		xstats->tail_drop[i] =
7738c2ecf20Sopenharmony_ci			mlxsw_reg_ppcnt_tc_no_buffer_discard_uc_get(ppcnt_pl);
7748c2ecf20Sopenharmony_ci	}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
7778c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_PRIO_CNT,
7788c2ecf20Sopenharmony_ci						  i, ppcnt_pl);
7798c2ecf20Sopenharmony_ci		if (err)
7808c2ecf20Sopenharmony_ci			continue;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci		xstats->tx_packets[i] = mlxsw_reg_ppcnt_tx_frames_get(ppcnt_pl);
7838c2ecf20Sopenharmony_ci		xstats->tx_bytes[i] = mlxsw_reg_ppcnt_tx_octets_get(ppcnt_pl);
7848c2ecf20Sopenharmony_ci	}
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_cistatic void update_stats_cache(struct work_struct *work)
7888c2ecf20Sopenharmony_ci{
7898c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port =
7908c2ecf20Sopenharmony_ci		container_of(work, struct mlxsw_sp_port,
7918c2ecf20Sopenharmony_ci			     periodic_hw_stats.update_dw.work);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	if (!netif_carrier_ok(mlxsw_sp_port->dev))
7948c2ecf20Sopenharmony_ci		/* Note: mlxsw_sp_port_down_wipe_counters() clears the cache as
7958c2ecf20Sopenharmony_ci		 * necessary when port goes down.
7968c2ecf20Sopenharmony_ci		 */
7978c2ecf20Sopenharmony_ci		goto out;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	mlxsw_sp_port_get_hw_stats(mlxsw_sp_port->dev,
8008c2ecf20Sopenharmony_ci				   &mlxsw_sp_port->periodic_hw_stats.stats);
8018c2ecf20Sopenharmony_ci	mlxsw_sp_port_get_hw_xstats(mlxsw_sp_port->dev,
8028c2ecf20Sopenharmony_ci				    &mlxsw_sp_port->periodic_hw_stats.xstats);
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ciout:
8058c2ecf20Sopenharmony_ci	mlxsw_core_schedule_dw(&mlxsw_sp_port->periodic_hw_stats.update_dw,
8068c2ecf20Sopenharmony_ci			       MLXSW_HW_STATS_UPDATE_TIME);
8078c2ecf20Sopenharmony_ci}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci/* Return the stats from a cache that is updated periodically,
8108c2ecf20Sopenharmony_ci * as this function might get called in an atomic context.
8118c2ecf20Sopenharmony_ci */
8128c2ecf20Sopenharmony_cistatic void
8138c2ecf20Sopenharmony_cimlxsw_sp_port_get_stats64(struct net_device *dev,
8148c2ecf20Sopenharmony_ci			  struct rtnl_link_stats64 *stats)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	memcpy(stats, &mlxsw_sp_port->periodic_hw_stats.stats, sizeof(*stats));
8198c2ecf20Sopenharmony_ci}
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_cistatic int __mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,
8228c2ecf20Sopenharmony_ci				    u16 vid_begin, u16 vid_end,
8238c2ecf20Sopenharmony_ci				    bool is_member, bool untagged)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
8268c2ecf20Sopenharmony_ci	char *spvm_pl;
8278c2ecf20Sopenharmony_ci	int err;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	spvm_pl = kmalloc(MLXSW_REG_SPVM_LEN, GFP_KERNEL);
8308c2ecf20Sopenharmony_ci	if (!spvm_pl)
8318c2ecf20Sopenharmony_ci		return -ENOMEM;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	mlxsw_reg_spvm_pack(spvm_pl, mlxsw_sp_port->local_port,	vid_begin,
8348c2ecf20Sopenharmony_ci			    vid_end, is_member, untagged);
8358c2ecf20Sopenharmony_ci	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvm), spvm_pl);
8368c2ecf20Sopenharmony_ci	kfree(spvm_pl);
8378c2ecf20Sopenharmony_ci	return err;
8388c2ecf20Sopenharmony_ci}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ciint mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin,
8418c2ecf20Sopenharmony_ci			   u16 vid_end, bool is_member, bool untagged)
8428c2ecf20Sopenharmony_ci{
8438c2ecf20Sopenharmony_ci	u16 vid, vid_e;
8448c2ecf20Sopenharmony_ci	int err;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	for (vid = vid_begin; vid <= vid_end;
8478c2ecf20Sopenharmony_ci	     vid += MLXSW_REG_SPVM_REC_MAX_COUNT) {
8488c2ecf20Sopenharmony_ci		vid_e = min((u16) (vid + MLXSW_REG_SPVM_REC_MAX_COUNT - 1),
8498c2ecf20Sopenharmony_ci			    vid_end);
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci		err = __mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid_e,
8528c2ecf20Sopenharmony_ci					       is_member, untagged);
8538c2ecf20Sopenharmony_ci		if (err)
8548c2ecf20Sopenharmony_ci			return err;
8558c2ecf20Sopenharmony_ci	}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	return 0;
8588c2ecf20Sopenharmony_ci}
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_vlan_flush(struct mlxsw_sp_port *mlxsw_sp_port,
8618c2ecf20Sopenharmony_ci				     bool flush_default)
8628c2ecf20Sopenharmony_ci{
8638c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, *tmp;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	list_for_each_entry_safe(mlxsw_sp_port_vlan, tmp,
8668c2ecf20Sopenharmony_ci				 &mlxsw_sp_port->vlans_list, list) {
8678c2ecf20Sopenharmony_ci		if (!flush_default &&
8688c2ecf20Sopenharmony_ci		    mlxsw_sp_port_vlan->vid == MLXSW_SP_DEFAULT_VID)
8698c2ecf20Sopenharmony_ci			continue;
8708c2ecf20Sopenharmony_ci		mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
8718c2ecf20Sopenharmony_ci	}
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_cistatic void
8758c2ecf20Sopenharmony_cimlxsw_sp_port_vlan_cleanup(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	if (mlxsw_sp_port_vlan->bridge_port)
8788c2ecf20Sopenharmony_ci		mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
8798c2ecf20Sopenharmony_ci	else if (mlxsw_sp_port_vlan->fid)
8808c2ecf20Sopenharmony_ci		mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);
8818c2ecf20Sopenharmony_ci}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_cistruct mlxsw_sp_port_vlan *
8848c2ecf20Sopenharmony_cimlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
8878c2ecf20Sopenharmony_ci	bool untagged = vid == MLXSW_SP_DEFAULT_VID;
8888c2ecf20Sopenharmony_ci	int err;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
8918c2ecf20Sopenharmony_ci	if (mlxsw_sp_port_vlan)
8928c2ecf20Sopenharmony_ci		return ERR_PTR(-EEXIST);
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true, untagged);
8958c2ecf20Sopenharmony_ci	if (err)
8968c2ecf20Sopenharmony_ci		return ERR_PTR(err);
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan = kzalloc(sizeof(*mlxsw_sp_port_vlan), GFP_KERNEL);
8998c2ecf20Sopenharmony_ci	if (!mlxsw_sp_port_vlan) {
9008c2ecf20Sopenharmony_ci		err = -ENOMEM;
9018c2ecf20Sopenharmony_ci		goto err_port_vlan_alloc;
9028c2ecf20Sopenharmony_ci	}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port;
9058c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan->vid = vid;
9068c2ecf20Sopenharmony_ci	list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list);
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	return mlxsw_sp_port_vlan;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_cierr_port_vlan_alloc:
9118c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
9128c2ecf20Sopenharmony_ci	return ERR_PTR(err);
9138c2ecf20Sopenharmony_ci}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_civoid mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
9168c2ecf20Sopenharmony_ci{
9178c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;
9188c2ecf20Sopenharmony_ci	u16 vid = mlxsw_sp_port_vlan->vid;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan_cleanup(mlxsw_sp_port_vlan);
9218c2ecf20Sopenharmony_ci	list_del(&mlxsw_sp_port_vlan->list);
9228c2ecf20Sopenharmony_ci	kfree(mlxsw_sp_port_vlan);
9238c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);
9248c2ecf20Sopenharmony_ci}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_add_vid(struct net_device *dev,
9278c2ecf20Sopenharmony_ci				 __be16 __always_unused proto, u16 vid)
9288c2ecf20Sopenharmony_ci{
9298c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	/* VLAN 0 is added to HW filter when device goes up, but it is
9328c2ecf20Sopenharmony_ci	 * reserved in our case, so simply return.
9338c2ecf20Sopenharmony_ci	 */
9348c2ecf20Sopenharmony_ci	if (!vid)
9358c2ecf20Sopenharmony_ci		return 0;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid));
9388c2ecf20Sopenharmony_ci}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_kill_vid(struct net_device *dev,
9418c2ecf20Sopenharmony_ci				  __be16 __always_unused proto, u16 vid)
9428c2ecf20Sopenharmony_ci{
9438c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
9448c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	/* VLAN 0 is removed from HW filter when device goes down, but
9478c2ecf20Sopenharmony_ci	 * it is reserved in our case, so simply return.
9488c2ecf20Sopenharmony_ci	 */
9498c2ecf20Sopenharmony_ci	if (!vid)
9508c2ecf20Sopenharmony_ci		return 0;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
9538c2ecf20Sopenharmony_ci	if (!mlxsw_sp_port_vlan)
9548c2ecf20Sopenharmony_ci		return 0;
9558c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	return 0;
9588c2ecf20Sopenharmony_ci}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_cistatic int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
9618c2ecf20Sopenharmony_ci				   struct flow_block_offload *f)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	switch (f->binder_type) {
9648c2ecf20Sopenharmony_ci	case FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS:
9658c2ecf20Sopenharmony_ci		return mlxsw_sp_setup_tc_block_clsact(mlxsw_sp_port, f, true);
9668c2ecf20Sopenharmony_ci	case FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS:
9678c2ecf20Sopenharmony_ci		return mlxsw_sp_setup_tc_block_clsact(mlxsw_sp_port, f, false);
9688c2ecf20Sopenharmony_ci	case FLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP:
9698c2ecf20Sopenharmony_ci		return mlxsw_sp_setup_tc_block_qevent_early_drop(mlxsw_sp_port, f);
9708c2ecf20Sopenharmony_ci	default:
9718c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
9728c2ecf20Sopenharmony_ci	}
9738c2ecf20Sopenharmony_ci}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_cistatic int mlxsw_sp_setup_tc(struct net_device *dev, enum tc_setup_type type,
9768c2ecf20Sopenharmony_ci			     void *type_data)
9778c2ecf20Sopenharmony_ci{
9788c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	switch (type) {
9818c2ecf20Sopenharmony_ci	case TC_SETUP_BLOCK:
9828c2ecf20Sopenharmony_ci		return mlxsw_sp_setup_tc_block(mlxsw_sp_port, type_data);
9838c2ecf20Sopenharmony_ci	case TC_SETUP_QDISC_RED:
9848c2ecf20Sopenharmony_ci		return mlxsw_sp_setup_tc_red(mlxsw_sp_port, type_data);
9858c2ecf20Sopenharmony_ci	case TC_SETUP_QDISC_PRIO:
9868c2ecf20Sopenharmony_ci		return mlxsw_sp_setup_tc_prio(mlxsw_sp_port, type_data);
9878c2ecf20Sopenharmony_ci	case TC_SETUP_QDISC_ETS:
9888c2ecf20Sopenharmony_ci		return mlxsw_sp_setup_tc_ets(mlxsw_sp_port, type_data);
9898c2ecf20Sopenharmony_ci	case TC_SETUP_QDISC_TBF:
9908c2ecf20Sopenharmony_ci		return mlxsw_sp_setup_tc_tbf(mlxsw_sp_port, type_data);
9918c2ecf20Sopenharmony_ci	case TC_SETUP_QDISC_FIFO:
9928c2ecf20Sopenharmony_ci		return mlxsw_sp_setup_tc_fifo(mlxsw_sp_port, type_data);
9938c2ecf20Sopenharmony_ci	default:
9948c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
9958c2ecf20Sopenharmony_ci	}
9968c2ecf20Sopenharmony_ci}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic int mlxsw_sp_feature_hw_tc(struct net_device *dev, bool enable)
9998c2ecf20Sopenharmony_ci{
10008c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	if (!enable) {
10038c2ecf20Sopenharmony_ci		if (mlxsw_sp_flow_block_rule_count(mlxsw_sp_port->ing_flow_block) ||
10048c2ecf20Sopenharmony_ci		    mlxsw_sp_flow_block_rule_count(mlxsw_sp_port->eg_flow_block)) {
10058c2ecf20Sopenharmony_ci			netdev_err(dev, "Active offloaded tc filters, can't turn hw_tc_offload off\n");
10068c2ecf20Sopenharmony_ci			return -EINVAL;
10078c2ecf20Sopenharmony_ci		}
10088c2ecf20Sopenharmony_ci		mlxsw_sp_flow_block_disable_inc(mlxsw_sp_port->ing_flow_block);
10098c2ecf20Sopenharmony_ci		mlxsw_sp_flow_block_disable_inc(mlxsw_sp_port->eg_flow_block);
10108c2ecf20Sopenharmony_ci	} else {
10118c2ecf20Sopenharmony_ci		mlxsw_sp_flow_block_disable_dec(mlxsw_sp_port->ing_flow_block);
10128c2ecf20Sopenharmony_ci		mlxsw_sp_flow_block_disable_dec(mlxsw_sp_port->eg_flow_block);
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ci	return 0;
10158c2ecf20Sopenharmony_ci}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_cistatic int mlxsw_sp_feature_loopback(struct net_device *dev, bool enable)
10188c2ecf20Sopenharmony_ci{
10198c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
10208c2ecf20Sopenharmony_ci	char pplr_pl[MLXSW_REG_PPLR_LEN];
10218c2ecf20Sopenharmony_ci	int err;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	if (netif_running(dev))
10248c2ecf20Sopenharmony_ci		mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	mlxsw_reg_pplr_pack(pplr_pl, mlxsw_sp_port->local_port, enable);
10278c2ecf20Sopenharmony_ci	err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pplr),
10288c2ecf20Sopenharmony_ci			      pplr_pl);
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	if (netif_running(dev))
10318c2ecf20Sopenharmony_ci		mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	return err;
10348c2ecf20Sopenharmony_ci}
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_citypedef int (*mlxsw_sp_feature_handler)(struct net_device *dev, bool enable);
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_cistatic int mlxsw_sp_handle_feature(struct net_device *dev,
10398c2ecf20Sopenharmony_ci				   netdev_features_t wanted_features,
10408c2ecf20Sopenharmony_ci				   netdev_features_t feature,
10418c2ecf20Sopenharmony_ci				   mlxsw_sp_feature_handler feature_handler)
10428c2ecf20Sopenharmony_ci{
10438c2ecf20Sopenharmony_ci	netdev_features_t changes = wanted_features ^ dev->features;
10448c2ecf20Sopenharmony_ci	bool enable = !!(wanted_features & feature);
10458c2ecf20Sopenharmony_ci	int err;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	if (!(changes & feature))
10488c2ecf20Sopenharmony_ci		return 0;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	err = feature_handler(dev, enable);
10518c2ecf20Sopenharmony_ci	if (err) {
10528c2ecf20Sopenharmony_ci		netdev_err(dev, "%s feature %pNF failed, err %d\n",
10538c2ecf20Sopenharmony_ci			   enable ? "Enable" : "Disable", &feature, err);
10548c2ecf20Sopenharmony_ci		return err;
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	if (enable)
10588c2ecf20Sopenharmony_ci		dev->features |= feature;
10598c2ecf20Sopenharmony_ci	else
10608c2ecf20Sopenharmony_ci		dev->features &= ~feature;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	return 0;
10638c2ecf20Sopenharmony_ci}
10648c2ecf20Sopenharmony_cistatic int mlxsw_sp_set_features(struct net_device *dev,
10658c2ecf20Sopenharmony_ci				 netdev_features_t features)
10668c2ecf20Sopenharmony_ci{
10678c2ecf20Sopenharmony_ci	netdev_features_t oper_features = dev->features;
10688c2ecf20Sopenharmony_ci	int err = 0;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	err |= mlxsw_sp_handle_feature(dev, features, NETIF_F_HW_TC,
10718c2ecf20Sopenharmony_ci				       mlxsw_sp_feature_hw_tc);
10728c2ecf20Sopenharmony_ci	err |= mlxsw_sp_handle_feature(dev, features, NETIF_F_LOOPBACK,
10738c2ecf20Sopenharmony_ci				       mlxsw_sp_feature_loopback);
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	if (err) {
10768c2ecf20Sopenharmony_ci		dev->features = oper_features;
10778c2ecf20Sopenharmony_ci		return -EINVAL;
10788c2ecf20Sopenharmony_ci	}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	return 0;
10818c2ecf20Sopenharmony_ci}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_cistatic struct devlink_port *
10848c2ecf20Sopenharmony_cimlxsw_sp_port_get_devlink_port(struct net_device *dev)
10858c2ecf20Sopenharmony_ci{
10868c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
10878c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	return mlxsw_core_port_devlink_port_get(mlxsw_sp->core,
10908c2ecf20Sopenharmony_ci						mlxsw_sp_port->local_port);
10918c2ecf20Sopenharmony_ci}
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
10948c2ecf20Sopenharmony_ci				      struct ifreq *ifr)
10958c2ecf20Sopenharmony_ci{
10968c2ecf20Sopenharmony_ci	struct hwtstamp_config config;
10978c2ecf20Sopenharmony_ci	int err;
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
11008c2ecf20Sopenharmony_ci		return -EFAULT;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port,
11038c2ecf20Sopenharmony_ci							     &config);
11048c2ecf20Sopenharmony_ci	if (err)
11058c2ecf20Sopenharmony_ci		return err;
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
11088c2ecf20Sopenharmony_ci		return -EFAULT;
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	return 0;
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
11148c2ecf20Sopenharmony_ci				      struct ifreq *ifr)
11158c2ecf20Sopenharmony_ci{
11168c2ecf20Sopenharmony_ci	struct hwtstamp_config config;
11178c2ecf20Sopenharmony_ci	int err;
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_get(mlxsw_sp_port,
11208c2ecf20Sopenharmony_ci							     &config);
11218c2ecf20Sopenharmony_ci	if (err)
11228c2ecf20Sopenharmony_ci		return err;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
11258c2ecf20Sopenharmony_ci		return -EFAULT;
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	return 0;
11288c2ecf20Sopenharmony_ci}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_cistatic inline void mlxsw_sp_port_ptp_clear(struct mlxsw_sp_port *mlxsw_sp_port)
11318c2ecf20Sopenharmony_ci{
11328c2ecf20Sopenharmony_ci	struct hwtstamp_config config = {0};
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port, &config);
11358c2ecf20Sopenharmony_ci}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_cistatic int
11388c2ecf20Sopenharmony_cimlxsw_sp_port_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
11398c2ecf20Sopenharmony_ci{
11408c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	switch (cmd) {
11438c2ecf20Sopenharmony_ci	case SIOCSHWTSTAMP:
11448c2ecf20Sopenharmony_ci		return mlxsw_sp_port_hwtstamp_set(mlxsw_sp_port, ifr);
11458c2ecf20Sopenharmony_ci	case SIOCGHWTSTAMP:
11468c2ecf20Sopenharmony_ci		return mlxsw_sp_port_hwtstamp_get(mlxsw_sp_port, ifr);
11478c2ecf20Sopenharmony_ci	default:
11488c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
11498c2ecf20Sopenharmony_ci	}
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_cistatic const struct net_device_ops mlxsw_sp_port_netdev_ops = {
11538c2ecf20Sopenharmony_ci	.ndo_open		= mlxsw_sp_port_open,
11548c2ecf20Sopenharmony_ci	.ndo_stop		= mlxsw_sp_port_stop,
11558c2ecf20Sopenharmony_ci	.ndo_start_xmit		= mlxsw_sp_port_xmit,
11568c2ecf20Sopenharmony_ci	.ndo_setup_tc           = mlxsw_sp_setup_tc,
11578c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	= mlxsw_sp_set_rx_mode,
11588c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= mlxsw_sp_port_set_mac_address,
11598c2ecf20Sopenharmony_ci	.ndo_change_mtu		= mlxsw_sp_port_change_mtu,
11608c2ecf20Sopenharmony_ci	.ndo_get_stats64	= mlxsw_sp_port_get_stats64,
11618c2ecf20Sopenharmony_ci	.ndo_has_offload_stats	= mlxsw_sp_port_has_offload_stats,
11628c2ecf20Sopenharmony_ci	.ndo_get_offload_stats	= mlxsw_sp_port_get_offload_stats,
11638c2ecf20Sopenharmony_ci	.ndo_vlan_rx_add_vid	= mlxsw_sp_port_add_vid,
11648c2ecf20Sopenharmony_ci	.ndo_vlan_rx_kill_vid	= mlxsw_sp_port_kill_vid,
11658c2ecf20Sopenharmony_ci	.ndo_set_features	= mlxsw_sp_set_features,
11668c2ecf20Sopenharmony_ci	.ndo_get_devlink_port	= mlxsw_sp_port_get_devlink_port,
11678c2ecf20Sopenharmony_ci	.ndo_do_ioctl		= mlxsw_sp_port_ioctl,
11688c2ecf20Sopenharmony_ci};
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_cistatic int
11718c2ecf20Sopenharmony_cimlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port)
11728c2ecf20Sopenharmony_ci{
11738c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
11748c2ecf20Sopenharmony_ci	u32 eth_proto_cap, eth_proto_admin, eth_proto_oper;
11758c2ecf20Sopenharmony_ci	const struct mlxsw_sp_port_type_speed_ops *ops;
11768c2ecf20Sopenharmony_ci	char ptys_pl[MLXSW_REG_PTYS_LEN];
11778c2ecf20Sopenharmony_ci	u32 eth_proto_cap_masked;
11788c2ecf20Sopenharmony_ci	int err;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	ops = mlxsw_sp->port_type_speed_ops;
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	/* Set advertised speeds to speeds supported by both the driver
11838c2ecf20Sopenharmony_ci	 * and the device.
11848c2ecf20Sopenharmony_ci	 */
11858c2ecf20Sopenharmony_ci	ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
11868c2ecf20Sopenharmony_ci			       0, false);
11878c2ecf20Sopenharmony_ci	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
11888c2ecf20Sopenharmony_ci	if (err)
11898c2ecf20Sopenharmony_ci		return err;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, &eth_proto_cap,
11928c2ecf20Sopenharmony_ci				 &eth_proto_admin, &eth_proto_oper);
11938c2ecf20Sopenharmony_ci	eth_proto_cap_masked = ops->ptys_proto_cap_masked_get(eth_proto_cap);
11948c2ecf20Sopenharmony_ci	ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,
11958c2ecf20Sopenharmony_ci			       eth_proto_cap_masked,
11968c2ecf20Sopenharmony_ci			       mlxsw_sp_port->link.autoneg);
11978c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
11988c2ecf20Sopenharmony_ci}
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ciint mlxsw_sp_port_speed_get(struct mlxsw_sp_port *mlxsw_sp_port, u32 *speed)
12018c2ecf20Sopenharmony_ci{
12028c2ecf20Sopenharmony_ci	const struct mlxsw_sp_port_type_speed_ops *port_type_speed_ops;
12038c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
12048c2ecf20Sopenharmony_ci	char ptys_pl[MLXSW_REG_PTYS_LEN];
12058c2ecf20Sopenharmony_ci	u32 eth_proto_oper;
12068c2ecf20Sopenharmony_ci	int err;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	port_type_speed_ops = mlxsw_sp->port_type_speed_ops;
12098c2ecf20Sopenharmony_ci	port_type_speed_ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl,
12108c2ecf20Sopenharmony_ci					       mlxsw_sp_port->local_port, 0,
12118c2ecf20Sopenharmony_ci					       false);
12128c2ecf20Sopenharmony_ci	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
12138c2ecf20Sopenharmony_ci	if (err)
12148c2ecf20Sopenharmony_ci		return err;
12158c2ecf20Sopenharmony_ci	port_type_speed_ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, NULL, NULL,
12168c2ecf20Sopenharmony_ci						 &eth_proto_oper);
12178c2ecf20Sopenharmony_ci	*speed = port_type_speed_ops->from_ptys_speed(mlxsw_sp, eth_proto_oper);
12188c2ecf20Sopenharmony_ci	return 0;
12198c2ecf20Sopenharmony_ci}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ciint mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
12228c2ecf20Sopenharmony_ci			  enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index,
12238c2ecf20Sopenharmony_ci			  bool dwrr, u8 dwrr_weight)
12248c2ecf20Sopenharmony_ci{
12258c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
12268c2ecf20Sopenharmony_ci	char qeec_pl[MLXSW_REG_QEEC_LEN];
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index,
12298c2ecf20Sopenharmony_ci			    next_index);
12308c2ecf20Sopenharmony_ci	mlxsw_reg_qeec_de_set(qeec_pl, true);
12318c2ecf20Sopenharmony_ci	mlxsw_reg_qeec_dwrr_set(qeec_pl, dwrr);
12328c2ecf20Sopenharmony_ci	mlxsw_reg_qeec_dwrr_weight_set(qeec_pl, dwrr_weight);
12338c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);
12348c2ecf20Sopenharmony_ci}
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ciint mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port,
12378c2ecf20Sopenharmony_ci				  enum mlxsw_reg_qeec_hr hr, u8 index,
12388c2ecf20Sopenharmony_ci				  u8 next_index, u32 maxrate, u8 burst_size)
12398c2ecf20Sopenharmony_ci{
12408c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
12418c2ecf20Sopenharmony_ci	char qeec_pl[MLXSW_REG_QEEC_LEN];
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index,
12448c2ecf20Sopenharmony_ci			    next_index);
12458c2ecf20Sopenharmony_ci	mlxsw_reg_qeec_mase_set(qeec_pl, true);
12468c2ecf20Sopenharmony_ci	mlxsw_reg_qeec_max_shaper_rate_set(qeec_pl, maxrate);
12478c2ecf20Sopenharmony_ci	mlxsw_reg_qeec_max_shaper_bs_set(qeec_pl, burst_size);
12488c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);
12498c2ecf20Sopenharmony_ci}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_min_bw_set(struct mlxsw_sp_port *mlxsw_sp_port,
12528c2ecf20Sopenharmony_ci				    enum mlxsw_reg_qeec_hr hr, u8 index,
12538c2ecf20Sopenharmony_ci				    u8 next_index, u32 minrate)
12548c2ecf20Sopenharmony_ci{
12558c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
12568c2ecf20Sopenharmony_ci	char qeec_pl[MLXSW_REG_QEEC_LEN];
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index,
12598c2ecf20Sopenharmony_ci			    next_index);
12608c2ecf20Sopenharmony_ci	mlxsw_reg_qeec_mise_set(qeec_pl, true);
12618c2ecf20Sopenharmony_ci	mlxsw_reg_qeec_min_shaper_rate_set(qeec_pl, minrate);
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);
12648c2ecf20Sopenharmony_ci}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ciint mlxsw_sp_port_prio_tc_set(struct mlxsw_sp_port *mlxsw_sp_port,
12678c2ecf20Sopenharmony_ci			      u8 switch_prio, u8 tclass)
12688c2ecf20Sopenharmony_ci{
12698c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
12708c2ecf20Sopenharmony_ci	char qtct_pl[MLXSW_REG_QTCT_LEN];
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	mlxsw_reg_qtct_pack(qtct_pl, mlxsw_sp_port->local_port, switch_prio,
12738c2ecf20Sopenharmony_ci			    tclass);
12748c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qtct), qtct_pl);
12758c2ecf20Sopenharmony_ci}
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port)
12788c2ecf20Sopenharmony_ci{
12798c2ecf20Sopenharmony_ci	int err, i;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	/* Setup the elements hierarcy, so that each TC is linked to
12828c2ecf20Sopenharmony_ci	 * one subgroup, which are all member in the same group.
12838c2ecf20Sopenharmony_ci	 */
12848c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
12858c2ecf20Sopenharmony_ci				    MLXSW_REG_QEEC_HR_GROUP, 0, 0, false, 0);
12868c2ecf20Sopenharmony_ci	if (err)
12878c2ecf20Sopenharmony_ci		return err;
12888c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
12898c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
12908c2ecf20Sopenharmony_ci					    MLXSW_REG_QEEC_HR_SUBGROUP, i,
12918c2ecf20Sopenharmony_ci					    0, false, 0);
12928c2ecf20Sopenharmony_ci		if (err)
12938c2ecf20Sopenharmony_ci			return err;
12948c2ecf20Sopenharmony_ci	}
12958c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
12968c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
12978c2ecf20Sopenharmony_ci					    MLXSW_REG_QEEC_HR_TC, i, i,
12988c2ecf20Sopenharmony_ci					    false, 0);
12998c2ecf20Sopenharmony_ci		if (err)
13008c2ecf20Sopenharmony_ci			return err;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_ets_set(mlxsw_sp_port,
13038c2ecf20Sopenharmony_ci					    MLXSW_REG_QEEC_HR_TC,
13048c2ecf20Sopenharmony_ci					    i + 8, i,
13058c2ecf20Sopenharmony_ci					    true, 100);
13068c2ecf20Sopenharmony_ci		if (err)
13078c2ecf20Sopenharmony_ci			return err;
13088c2ecf20Sopenharmony_ci	}
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	/* Make sure the max shaper is disabled in all hierarchies that support
13118c2ecf20Sopenharmony_ci	 * it. Note that this disables ptps (PTP shaper), but that is intended
13128c2ecf20Sopenharmony_ci	 * for the initial configuration.
13138c2ecf20Sopenharmony_ci	 */
13148c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
13158c2ecf20Sopenharmony_ci					    MLXSW_REG_QEEC_HR_PORT, 0, 0,
13168c2ecf20Sopenharmony_ci					    MLXSW_REG_QEEC_MAS_DIS, 0);
13178c2ecf20Sopenharmony_ci	if (err)
13188c2ecf20Sopenharmony_ci		return err;
13198c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
13208c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
13218c2ecf20Sopenharmony_ci						    MLXSW_REG_QEEC_HR_SUBGROUP,
13228c2ecf20Sopenharmony_ci						    i, 0,
13238c2ecf20Sopenharmony_ci						    MLXSW_REG_QEEC_MAS_DIS, 0);
13248c2ecf20Sopenharmony_ci		if (err)
13258c2ecf20Sopenharmony_ci			return err;
13268c2ecf20Sopenharmony_ci	}
13278c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
13288c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
13298c2ecf20Sopenharmony_ci						    MLXSW_REG_QEEC_HR_TC,
13308c2ecf20Sopenharmony_ci						    i, i,
13318c2ecf20Sopenharmony_ci						    MLXSW_REG_QEEC_MAS_DIS, 0);
13328c2ecf20Sopenharmony_ci		if (err)
13338c2ecf20Sopenharmony_ci			return err;
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,
13368c2ecf20Sopenharmony_ci						    MLXSW_REG_QEEC_HR_TC,
13378c2ecf20Sopenharmony_ci						    i + 8, i,
13388c2ecf20Sopenharmony_ci						    MLXSW_REG_QEEC_MAS_DIS, 0);
13398c2ecf20Sopenharmony_ci		if (err)
13408c2ecf20Sopenharmony_ci			return err;
13418c2ecf20Sopenharmony_ci	}
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	/* Configure the min shaper for multicast TCs. */
13448c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
13458c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_min_bw_set(mlxsw_sp_port,
13468c2ecf20Sopenharmony_ci					       MLXSW_REG_QEEC_HR_TC,
13478c2ecf20Sopenharmony_ci					       i + 8, i,
13488c2ecf20Sopenharmony_ci					       MLXSW_REG_QEEC_MIS_MIN);
13498c2ecf20Sopenharmony_ci		if (err)
13508c2ecf20Sopenharmony_ci			return err;
13518c2ecf20Sopenharmony_ci	}
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	/* Map all priorities to traffic class 0. */
13548c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
13558c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, 0);
13568c2ecf20Sopenharmony_ci		if (err)
13578c2ecf20Sopenharmony_ci			return err;
13588c2ecf20Sopenharmony_ci	}
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	return 0;
13618c2ecf20Sopenharmony_ci}
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_tc_mc_mode_set(struct mlxsw_sp_port *mlxsw_sp_port,
13648c2ecf20Sopenharmony_ci					bool enable)
13658c2ecf20Sopenharmony_ci{
13668c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
13678c2ecf20Sopenharmony_ci	char qtctm_pl[MLXSW_REG_QTCTM_LEN];
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	mlxsw_reg_qtctm_pack(qtctm_pl, mlxsw_sp_port->local_port, enable);
13708c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qtctm), qtctm_pl);
13718c2ecf20Sopenharmony_ci}
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_overheat_init_val_set(struct mlxsw_sp_port *mlxsw_sp_port)
13748c2ecf20Sopenharmony_ci{
13758c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
13768c2ecf20Sopenharmony_ci	u8 module = mlxsw_sp_port->mapping.module;
13778c2ecf20Sopenharmony_ci	u64 overheat_counter;
13788c2ecf20Sopenharmony_ci	int err;
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	err = mlxsw_env_module_overheat_counter_get(mlxsw_sp->core, module,
13818c2ecf20Sopenharmony_ci						    &overheat_counter);
13828c2ecf20Sopenharmony_ci	if (err)
13838c2ecf20Sopenharmony_ci		return err;
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	mlxsw_sp_port->module_overheat_initial_val = overheat_counter;
13868c2ecf20Sopenharmony_ci	return 0;
13878c2ecf20Sopenharmony_ci}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
13908c2ecf20Sopenharmony_ci				u8 split_base_local_port,
13918c2ecf20Sopenharmony_ci				struct mlxsw_sp_port_mapping *port_mapping)
13928c2ecf20Sopenharmony_ci{
13938c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
13948c2ecf20Sopenharmony_ci	bool split = !!split_base_local_port;
13958c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port;
13968c2ecf20Sopenharmony_ci	u32 lanes = port_mapping->width;
13978c2ecf20Sopenharmony_ci	struct net_device *dev;
13988c2ecf20Sopenharmony_ci	bool splittable;
13998c2ecf20Sopenharmony_ci	int err;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	splittable = lanes > 1 && !split;
14028c2ecf20Sopenharmony_ci	err = mlxsw_core_port_init(mlxsw_sp->core, local_port,
14038c2ecf20Sopenharmony_ci				   port_mapping->module + 1, split,
14048c2ecf20Sopenharmony_ci				   port_mapping->lane / lanes,
14058c2ecf20Sopenharmony_ci				   splittable, lanes,
14068c2ecf20Sopenharmony_ci				   mlxsw_sp->base_mac,
14078c2ecf20Sopenharmony_ci				   sizeof(mlxsw_sp->base_mac));
14088c2ecf20Sopenharmony_ci	if (err) {
14098c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to init core port\n",
14108c2ecf20Sopenharmony_ci			local_port);
14118c2ecf20Sopenharmony_ci		return err;
14128c2ecf20Sopenharmony_ci	}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	dev = alloc_etherdev(sizeof(struct mlxsw_sp_port));
14158c2ecf20Sopenharmony_ci	if (!dev) {
14168c2ecf20Sopenharmony_ci		err = -ENOMEM;
14178c2ecf20Sopenharmony_ci		goto err_alloc_etherdev;
14188c2ecf20Sopenharmony_ci	}
14198c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(dev, mlxsw_sp->bus_info->dev);
14208c2ecf20Sopenharmony_ci	dev_net_set(dev, mlxsw_sp_net(mlxsw_sp));
14218c2ecf20Sopenharmony_ci	mlxsw_sp_port = netdev_priv(dev);
14228c2ecf20Sopenharmony_ci	mlxsw_sp_port->dev = dev;
14238c2ecf20Sopenharmony_ci	mlxsw_sp_port->mlxsw_sp = mlxsw_sp;
14248c2ecf20Sopenharmony_ci	mlxsw_sp_port->local_port = local_port;
14258c2ecf20Sopenharmony_ci	mlxsw_sp_port->pvid = MLXSW_SP_DEFAULT_VID;
14268c2ecf20Sopenharmony_ci	mlxsw_sp_port->split = split;
14278c2ecf20Sopenharmony_ci	mlxsw_sp_port->split_base_local_port = split_base_local_port;
14288c2ecf20Sopenharmony_ci	mlxsw_sp_port->mapping = *port_mapping;
14298c2ecf20Sopenharmony_ci	mlxsw_sp_port->link.autoneg = 1;
14308c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list);
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	mlxsw_sp_port->pcpu_stats =
14338c2ecf20Sopenharmony_ci		netdev_alloc_pcpu_stats(struct mlxsw_sp_port_pcpu_stats);
14348c2ecf20Sopenharmony_ci	if (!mlxsw_sp_port->pcpu_stats) {
14358c2ecf20Sopenharmony_ci		err = -ENOMEM;
14368c2ecf20Sopenharmony_ci		goto err_alloc_stats;
14378c2ecf20Sopenharmony_ci	}
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&mlxsw_sp_port->periodic_hw_stats.update_dw,
14408c2ecf20Sopenharmony_ci			  &update_stats_cache);
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	dev->netdev_ops = &mlxsw_sp_port_netdev_ops;
14438c2ecf20Sopenharmony_ci	dev->ethtool_ops = &mlxsw_sp_port_ethtool_ops;
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_module_map(mlxsw_sp_port);
14468c2ecf20Sopenharmony_ci	if (err) {
14478c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to map module\n",
14488c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
14498c2ecf20Sopenharmony_ci		goto err_port_module_map;
14508c2ecf20Sopenharmony_ci	}
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_swid_set(mlxsw_sp_port, 0);
14538c2ecf20Sopenharmony_ci	if (err) {
14548c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set SWID\n",
14558c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
14568c2ecf20Sopenharmony_ci		goto err_port_swid_set;
14578c2ecf20Sopenharmony_ci	}
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_dev_addr_init(mlxsw_sp_port);
14608c2ecf20Sopenharmony_ci	if (err) {
14618c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unable to init port mac address\n",
14628c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
14638c2ecf20Sopenharmony_ci		goto err_dev_addr_init;
14648c2ecf20Sopenharmony_ci	}
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	netif_carrier_off(dev);
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_LLTX | NETIF_F_SG |
14698c2ecf20Sopenharmony_ci			 NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC;
14708c2ecf20Sopenharmony_ci	dev->hw_features |= NETIF_F_HW_TC | NETIF_F_LOOPBACK;
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	dev->min_mtu = 0;
14738c2ecf20Sopenharmony_ci	dev->max_mtu = ETH_MAX_MTU;
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	/* Each packet needs to have a Tx header (metadata) on top all other
14768c2ecf20Sopenharmony_ci	 * headers.
14778c2ecf20Sopenharmony_ci	 */
14788c2ecf20Sopenharmony_ci	dev->needed_headroom = MLXSW_TXHDR_LEN;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_system_port_mapping_set(mlxsw_sp_port);
14818c2ecf20Sopenharmony_ci	if (err) {
14828c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set system port mapping\n",
14838c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
14848c2ecf20Sopenharmony_ci		goto err_port_system_port_mapping_set;
14858c2ecf20Sopenharmony_ci	}
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_speed_by_width_set(mlxsw_sp_port);
14888c2ecf20Sopenharmony_ci	if (err) {
14898c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to enable speeds\n",
14908c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
14918c2ecf20Sopenharmony_ci		goto err_port_speed_by_width_set;
14928c2ecf20Sopenharmony_ci	}
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	err = mlxsw_sp->port_type_speed_ops->ptys_max_speed(mlxsw_sp_port,
14958c2ecf20Sopenharmony_ci							    &mlxsw_sp_port->max_speed);
14968c2ecf20Sopenharmony_ci	if (err) {
14978c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get maximum speed\n",
14988c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
14998c2ecf20Sopenharmony_ci		goto err_max_speed_get;
15008c2ecf20Sopenharmony_ci	}
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_max_mtu_get(mlxsw_sp_port, &mlxsw_sp_port->max_mtu);
15038c2ecf20Sopenharmony_ci	if (err) {
15048c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get maximum MTU\n",
15058c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
15068c2ecf20Sopenharmony_ci		goto err_port_max_mtu_get;
15078c2ecf20Sopenharmony_ci	}
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, ETH_DATA_LEN);
15108c2ecf20Sopenharmony_ci	if (err) {
15118c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set MTU\n",
15128c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
15138c2ecf20Sopenharmony_ci		goto err_port_mtu_set;
15148c2ecf20Sopenharmony_ci	}
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
15178c2ecf20Sopenharmony_ci	if (err)
15188c2ecf20Sopenharmony_ci		goto err_port_admin_status_set;
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_buffers_init(mlxsw_sp_port);
15218c2ecf20Sopenharmony_ci	if (err) {
15228c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize buffers\n",
15238c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
15248c2ecf20Sopenharmony_ci		goto err_port_buffers_init;
15258c2ecf20Sopenharmony_ci	}
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_ets_init(mlxsw_sp_port);
15288c2ecf20Sopenharmony_ci	if (err) {
15298c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize ETS\n",
15308c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
15318c2ecf20Sopenharmony_ci		goto err_port_ets_init;
15328c2ecf20Sopenharmony_ci	}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, true);
15358c2ecf20Sopenharmony_ci	if (err) {
15368c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize TC MC mode\n",
15378c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
15388c2ecf20Sopenharmony_ci		goto err_port_tc_mc_mode;
15398c2ecf20Sopenharmony_ci	}
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	/* ETS and buffers must be initialized before DCB. */
15428c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_dcb_init(mlxsw_sp_port);
15438c2ecf20Sopenharmony_ci	if (err) {
15448c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize DCB\n",
15458c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
15468c2ecf20Sopenharmony_ci		goto err_port_dcb_init;
15478c2ecf20Sopenharmony_ci	}
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_fids_init(mlxsw_sp_port);
15508c2ecf20Sopenharmony_ci	if (err) {
15518c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize FIDs\n",
15528c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
15538c2ecf20Sopenharmony_ci		goto err_port_fids_init;
15548c2ecf20Sopenharmony_ci	}
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	err = mlxsw_sp_tc_qdisc_init(mlxsw_sp_port);
15578c2ecf20Sopenharmony_ci	if (err) {
15588c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize TC qdiscs\n",
15598c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
15608c2ecf20Sopenharmony_ci		goto err_port_qdiscs_init;
15618c2ecf20Sopenharmony_ci	}
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 0, VLAN_N_VID - 1, false,
15648c2ecf20Sopenharmony_ci				     false);
15658c2ecf20Sopenharmony_ci	if (err) {
15668c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to clear VLAN filter\n",
15678c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
15688c2ecf20Sopenharmony_ci		goto err_port_vlan_clear;
15698c2ecf20Sopenharmony_ci	}
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_nve_init(mlxsw_sp_port);
15728c2ecf20Sopenharmony_ci	if (err) {
15738c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize NVE\n",
15748c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
15758c2ecf20Sopenharmony_ci		goto err_port_nve_init;
15768c2ecf20Sopenharmony_ci	}
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID);
15798c2ecf20Sopenharmony_ci	if (err) {
15808c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set PVID\n",
15818c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
15828c2ecf20Sopenharmony_ci		goto err_port_pvid_set;
15838c2ecf20Sopenharmony_ci	}
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_create(mlxsw_sp_port,
15868c2ecf20Sopenharmony_ci						       MLXSW_SP_DEFAULT_VID);
15878c2ecf20Sopenharmony_ci	if (IS_ERR(mlxsw_sp_port_vlan)) {
15888c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n",
15898c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
15908c2ecf20Sopenharmony_ci		err = PTR_ERR(mlxsw_sp_port_vlan);
15918c2ecf20Sopenharmony_ci		goto err_port_vlan_create;
15928c2ecf20Sopenharmony_ci	}
15938c2ecf20Sopenharmony_ci	mlxsw_sp_port->default_vlan = mlxsw_sp_port_vlan;
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&mlxsw_sp_port->ptp.shaper_dw,
15968c2ecf20Sopenharmony_ci			  mlxsw_sp->ptp_ops->shaper_work);
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	mlxsw_sp->ports[local_port] = mlxsw_sp_port;
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_overheat_init_val_set(mlxsw_sp_port);
16018c2ecf20Sopenharmony_ci	if (err) {
16028c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set overheat initial value\n",
16038c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
16048c2ecf20Sopenharmony_ci		goto err_port_overheat_init_val_set;
16058c2ecf20Sopenharmony_ci	}
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	err = register_netdev(dev);
16088c2ecf20Sopenharmony_ci	if (err) {
16098c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to register netdev\n",
16108c2ecf20Sopenharmony_ci			mlxsw_sp_port->local_port);
16118c2ecf20Sopenharmony_ci		goto err_register_netdev;
16128c2ecf20Sopenharmony_ci	}
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci	mlxsw_core_port_eth_set(mlxsw_sp->core, mlxsw_sp_port->local_port,
16158c2ecf20Sopenharmony_ci				mlxsw_sp_port, dev);
16168c2ecf20Sopenharmony_ci	mlxsw_core_schedule_dw(&mlxsw_sp_port->periodic_hw_stats.update_dw, 0);
16178c2ecf20Sopenharmony_ci	return 0;
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_cierr_register_netdev:
16208c2ecf20Sopenharmony_cierr_port_overheat_init_val_set:
16218c2ecf20Sopenharmony_ci	mlxsw_sp->ports[local_port] = NULL;
16228c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);
16238c2ecf20Sopenharmony_cierr_port_vlan_create:
16248c2ecf20Sopenharmony_cierr_port_pvid_set:
16258c2ecf20Sopenharmony_ci	mlxsw_sp_port_nve_fini(mlxsw_sp_port);
16268c2ecf20Sopenharmony_cierr_port_nve_init:
16278c2ecf20Sopenharmony_cierr_port_vlan_clear:
16288c2ecf20Sopenharmony_ci	mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port);
16298c2ecf20Sopenharmony_cierr_port_qdiscs_init:
16308c2ecf20Sopenharmony_ci	mlxsw_sp_port_fids_fini(mlxsw_sp_port);
16318c2ecf20Sopenharmony_cierr_port_fids_init:
16328c2ecf20Sopenharmony_ci	mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
16338c2ecf20Sopenharmony_cierr_port_dcb_init:
16348c2ecf20Sopenharmony_ci	mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false);
16358c2ecf20Sopenharmony_cierr_port_tc_mc_mode:
16368c2ecf20Sopenharmony_cierr_port_ets_init:
16378c2ecf20Sopenharmony_ci	mlxsw_sp_port_buffers_fini(mlxsw_sp_port);
16388c2ecf20Sopenharmony_cierr_port_buffers_init:
16398c2ecf20Sopenharmony_cierr_port_admin_status_set:
16408c2ecf20Sopenharmony_cierr_port_mtu_set:
16418c2ecf20Sopenharmony_cierr_port_max_mtu_get:
16428c2ecf20Sopenharmony_cierr_max_speed_get:
16438c2ecf20Sopenharmony_cierr_port_speed_by_width_set:
16448c2ecf20Sopenharmony_cierr_port_system_port_mapping_set:
16458c2ecf20Sopenharmony_cierr_dev_addr_init:
16468c2ecf20Sopenharmony_ci	mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
16478c2ecf20Sopenharmony_cierr_port_swid_set:
16488c2ecf20Sopenharmony_ci	mlxsw_sp_port_module_unmap(mlxsw_sp_port);
16498c2ecf20Sopenharmony_cierr_port_module_map:
16508c2ecf20Sopenharmony_ci	free_percpu(mlxsw_sp_port->pcpu_stats);
16518c2ecf20Sopenharmony_cierr_alloc_stats:
16528c2ecf20Sopenharmony_ci	free_netdev(dev);
16538c2ecf20Sopenharmony_cierr_alloc_etherdev:
16548c2ecf20Sopenharmony_ci	mlxsw_core_port_fini(mlxsw_sp->core, local_port);
16558c2ecf20Sopenharmony_ci	return err;
16568c2ecf20Sopenharmony_ci}
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
16598c2ecf20Sopenharmony_ci{
16608c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&mlxsw_sp_port->periodic_hw_stats.update_dw);
16638c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&mlxsw_sp_port->ptp.shaper_dw);
16648c2ecf20Sopenharmony_ci	mlxsw_sp_port_ptp_clear(mlxsw_sp_port);
16658c2ecf20Sopenharmony_ci	mlxsw_core_port_clear(mlxsw_sp->core, local_port, mlxsw_sp);
16668c2ecf20Sopenharmony_ci	unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */
16678c2ecf20Sopenharmony_ci	mlxsw_sp->ports[local_port] = NULL;
16688c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan_flush(mlxsw_sp_port, true);
16698c2ecf20Sopenharmony_ci	mlxsw_sp_port_nve_fini(mlxsw_sp_port);
16708c2ecf20Sopenharmony_ci	mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port);
16718c2ecf20Sopenharmony_ci	mlxsw_sp_port_fids_fini(mlxsw_sp_port);
16728c2ecf20Sopenharmony_ci	mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
16738c2ecf20Sopenharmony_ci	mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false);
16748c2ecf20Sopenharmony_ci	mlxsw_sp_port_buffers_fini(mlxsw_sp_port);
16758c2ecf20Sopenharmony_ci	mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
16768c2ecf20Sopenharmony_ci	mlxsw_sp_port_module_unmap(mlxsw_sp_port);
16778c2ecf20Sopenharmony_ci	free_percpu(mlxsw_sp_port->pcpu_stats);
16788c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vlans_list));
16798c2ecf20Sopenharmony_ci	free_netdev(mlxsw_sp_port->dev);
16808c2ecf20Sopenharmony_ci	mlxsw_core_port_fini(mlxsw_sp->core, local_port);
16818c2ecf20Sopenharmony_ci}
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_cistatic int mlxsw_sp_cpu_port_create(struct mlxsw_sp *mlxsw_sp)
16848c2ecf20Sopenharmony_ci{
16858c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port;
16868c2ecf20Sopenharmony_ci	int err;
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci	mlxsw_sp_port = kzalloc(sizeof(*mlxsw_sp_port), GFP_KERNEL);
16898c2ecf20Sopenharmony_ci	if (!mlxsw_sp_port)
16908c2ecf20Sopenharmony_ci		return -ENOMEM;
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci	mlxsw_sp_port->mlxsw_sp = mlxsw_sp;
16938c2ecf20Sopenharmony_ci	mlxsw_sp_port->local_port = MLXSW_PORT_CPU_PORT;
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci	err = mlxsw_core_cpu_port_init(mlxsw_sp->core,
16968c2ecf20Sopenharmony_ci				       mlxsw_sp_port,
16978c2ecf20Sopenharmony_ci				       mlxsw_sp->base_mac,
16988c2ecf20Sopenharmony_ci				       sizeof(mlxsw_sp->base_mac));
16998c2ecf20Sopenharmony_ci	if (err) {
17008c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize core CPU port\n");
17018c2ecf20Sopenharmony_ci		goto err_core_cpu_port_init;
17028c2ecf20Sopenharmony_ci	}
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = mlxsw_sp_port;
17058c2ecf20Sopenharmony_ci	return 0;
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_cierr_core_cpu_port_init:
17088c2ecf20Sopenharmony_ci	kfree(mlxsw_sp_port);
17098c2ecf20Sopenharmony_ci	return err;
17108c2ecf20Sopenharmony_ci}
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_cistatic void mlxsw_sp_cpu_port_remove(struct mlxsw_sp *mlxsw_sp)
17138c2ecf20Sopenharmony_ci{
17148c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port =
17158c2ecf20Sopenharmony_ci				mlxsw_sp->ports[MLXSW_PORT_CPU_PORT];
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	mlxsw_core_cpu_port_fini(mlxsw_sp->core);
17188c2ecf20Sopenharmony_ci	mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = NULL;
17198c2ecf20Sopenharmony_ci	kfree(mlxsw_sp_port);
17208c2ecf20Sopenharmony_ci}
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_cistatic bool mlxsw_sp_port_created(struct mlxsw_sp *mlxsw_sp, u8 local_port)
17238c2ecf20Sopenharmony_ci{
17248c2ecf20Sopenharmony_ci	return mlxsw_sp->ports[local_port] != NULL;
17258c2ecf20Sopenharmony_ci}
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_cistatic void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp)
17288c2ecf20Sopenharmony_ci{
17298c2ecf20Sopenharmony_ci	int i;
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++)
17328c2ecf20Sopenharmony_ci		if (mlxsw_sp_port_created(mlxsw_sp, i))
17338c2ecf20Sopenharmony_ci			mlxsw_sp_port_remove(mlxsw_sp, i);
17348c2ecf20Sopenharmony_ci	mlxsw_sp_cpu_port_remove(mlxsw_sp);
17358c2ecf20Sopenharmony_ci	kfree(mlxsw_sp->ports);
17368c2ecf20Sopenharmony_ci	mlxsw_sp->ports = NULL;
17378c2ecf20Sopenharmony_ci}
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_cistatic int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
17408c2ecf20Sopenharmony_ci{
17418c2ecf20Sopenharmony_ci	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
17428c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_mapping *port_mapping;
17438c2ecf20Sopenharmony_ci	size_t alloc_size;
17448c2ecf20Sopenharmony_ci	int i;
17458c2ecf20Sopenharmony_ci	int err;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	alloc_size = sizeof(struct mlxsw_sp_port *) * max_ports;
17488c2ecf20Sopenharmony_ci	mlxsw_sp->ports = kzalloc(alloc_size, GFP_KERNEL);
17498c2ecf20Sopenharmony_ci	if (!mlxsw_sp->ports)
17508c2ecf20Sopenharmony_ci		return -ENOMEM;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	err = mlxsw_sp_cpu_port_create(mlxsw_sp);
17538c2ecf20Sopenharmony_ci	if (err)
17548c2ecf20Sopenharmony_ci		goto err_cpu_port_create;
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	for (i = 1; i < max_ports; i++) {
17578c2ecf20Sopenharmony_ci		port_mapping = mlxsw_sp->port_mapping[i];
17588c2ecf20Sopenharmony_ci		if (!port_mapping)
17598c2ecf20Sopenharmony_ci			continue;
17608c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_create(mlxsw_sp, i, 0, port_mapping);
17618c2ecf20Sopenharmony_ci		if (err)
17628c2ecf20Sopenharmony_ci			goto err_port_create;
17638c2ecf20Sopenharmony_ci	}
17648c2ecf20Sopenharmony_ci	return 0;
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_cierr_port_create:
17678c2ecf20Sopenharmony_ci	for (i--; i >= 1; i--)
17688c2ecf20Sopenharmony_ci		if (mlxsw_sp_port_created(mlxsw_sp, i))
17698c2ecf20Sopenharmony_ci			mlxsw_sp_port_remove(mlxsw_sp, i);
17708c2ecf20Sopenharmony_ci	mlxsw_sp_cpu_port_remove(mlxsw_sp);
17718c2ecf20Sopenharmony_cierr_cpu_port_create:
17728c2ecf20Sopenharmony_ci	kfree(mlxsw_sp->ports);
17738c2ecf20Sopenharmony_ci	mlxsw_sp->ports = NULL;
17748c2ecf20Sopenharmony_ci	return err;
17758c2ecf20Sopenharmony_ci}
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_module_info_init(struct mlxsw_sp *mlxsw_sp)
17788c2ecf20Sopenharmony_ci{
17798c2ecf20Sopenharmony_ci	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
17808c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_mapping port_mapping;
17818c2ecf20Sopenharmony_ci	int i;
17828c2ecf20Sopenharmony_ci	int err;
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	mlxsw_sp->port_mapping = kcalloc(max_ports,
17858c2ecf20Sopenharmony_ci					 sizeof(struct mlxsw_sp_port_mapping *),
17868c2ecf20Sopenharmony_ci					 GFP_KERNEL);
17878c2ecf20Sopenharmony_ci	if (!mlxsw_sp->port_mapping)
17888c2ecf20Sopenharmony_ci		return -ENOMEM;
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	for (i = 1; i < max_ports; i++) {
17918c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_module_info_get(mlxsw_sp, i, &port_mapping);
17928c2ecf20Sopenharmony_ci		if (err)
17938c2ecf20Sopenharmony_ci			goto err_port_module_info_get;
17948c2ecf20Sopenharmony_ci		if (!port_mapping.width)
17958c2ecf20Sopenharmony_ci			continue;
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci		mlxsw_sp->port_mapping[i] = kmemdup(&port_mapping,
17988c2ecf20Sopenharmony_ci						    sizeof(port_mapping),
17998c2ecf20Sopenharmony_ci						    GFP_KERNEL);
18008c2ecf20Sopenharmony_ci		if (!mlxsw_sp->port_mapping[i]) {
18018c2ecf20Sopenharmony_ci			err = -ENOMEM;
18028c2ecf20Sopenharmony_ci			goto err_port_module_info_dup;
18038c2ecf20Sopenharmony_ci		}
18048c2ecf20Sopenharmony_ci	}
18058c2ecf20Sopenharmony_ci	return 0;
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_cierr_port_module_info_get:
18088c2ecf20Sopenharmony_cierr_port_module_info_dup:
18098c2ecf20Sopenharmony_ci	for (i--; i >= 1; i--)
18108c2ecf20Sopenharmony_ci		kfree(mlxsw_sp->port_mapping[i]);
18118c2ecf20Sopenharmony_ci	kfree(mlxsw_sp->port_mapping);
18128c2ecf20Sopenharmony_ci	return err;
18138c2ecf20Sopenharmony_ci}
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_module_info_fini(struct mlxsw_sp *mlxsw_sp)
18168c2ecf20Sopenharmony_ci{
18178c2ecf20Sopenharmony_ci	int i;
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++)
18208c2ecf20Sopenharmony_ci		kfree(mlxsw_sp->port_mapping[i]);
18218c2ecf20Sopenharmony_ci	kfree(mlxsw_sp->port_mapping);
18228c2ecf20Sopenharmony_ci}
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_cistatic u8 mlxsw_sp_cluster_base_port_get(u8 local_port, unsigned int max_width)
18258c2ecf20Sopenharmony_ci{
18268c2ecf20Sopenharmony_ci	u8 offset = (local_port - 1) % max_width;
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	return local_port - offset;
18298c2ecf20Sopenharmony_ci}
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_cistatic int
18328c2ecf20Sopenharmony_cimlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port,
18338c2ecf20Sopenharmony_ci			   struct mlxsw_sp_port_mapping *port_mapping,
18348c2ecf20Sopenharmony_ci			   unsigned int count, u8 offset)
18358c2ecf20Sopenharmony_ci{
18368c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_mapping split_port_mapping;
18378c2ecf20Sopenharmony_ci	int err, i;
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	split_port_mapping = *port_mapping;
18408c2ecf20Sopenharmony_ci	split_port_mapping.width /= count;
18418c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
18428c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_create(mlxsw_sp, base_port + i * offset,
18438c2ecf20Sopenharmony_ci					   base_port, &split_port_mapping);
18448c2ecf20Sopenharmony_ci		if (err)
18458c2ecf20Sopenharmony_ci			goto err_port_create;
18468c2ecf20Sopenharmony_ci		split_port_mapping.lane += split_port_mapping.width;
18478c2ecf20Sopenharmony_ci	}
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci	return 0;
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_cierr_port_create:
18528c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
18538c2ecf20Sopenharmony_ci		if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset))
18548c2ecf20Sopenharmony_ci			mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset);
18558c2ecf20Sopenharmony_ci	return err;
18568c2ecf20Sopenharmony_ci}
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp,
18598c2ecf20Sopenharmony_ci					 u8 base_port,
18608c2ecf20Sopenharmony_ci					 unsigned int count, u8 offset)
18618c2ecf20Sopenharmony_ci{
18628c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_mapping *port_mapping;
18638c2ecf20Sopenharmony_ci	int i;
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	/* Go over original unsplit ports in the gap and recreate them. */
18668c2ecf20Sopenharmony_ci	for (i = 0; i < count * offset; i++) {
18678c2ecf20Sopenharmony_ci		port_mapping = mlxsw_sp->port_mapping[base_port + i];
18688c2ecf20Sopenharmony_ci		if (!port_mapping)
18698c2ecf20Sopenharmony_ci			continue;
18708c2ecf20Sopenharmony_ci		mlxsw_sp_port_create(mlxsw_sp, base_port + i, 0, port_mapping);
18718c2ecf20Sopenharmony_ci	}
18728c2ecf20Sopenharmony_ci}
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_cistatic int mlxsw_sp_local_ports_offset(struct mlxsw_core *mlxsw_core,
18758c2ecf20Sopenharmony_ci				       unsigned int count,
18768c2ecf20Sopenharmony_ci				       unsigned int max_width)
18778c2ecf20Sopenharmony_ci{
18788c2ecf20Sopenharmony_ci	enum mlxsw_res_id local_ports_in_x_res_id;
18798c2ecf20Sopenharmony_ci	int split_width = max_width / count;
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	if (split_width == 1)
18828c2ecf20Sopenharmony_ci		local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_1X;
18838c2ecf20Sopenharmony_ci	else if (split_width == 2)
18848c2ecf20Sopenharmony_ci		local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_2X;
18858c2ecf20Sopenharmony_ci	else if (split_width == 4)
18868c2ecf20Sopenharmony_ci		local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_4X;
18878c2ecf20Sopenharmony_ci	else
18888c2ecf20Sopenharmony_ci		return -EINVAL;
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci	if (!mlxsw_core_res_valid(mlxsw_core, local_ports_in_x_res_id))
18918c2ecf20Sopenharmony_ci		return -EINVAL;
18928c2ecf20Sopenharmony_ci	return mlxsw_core_res_get(mlxsw_core, local_ports_in_x_res_id);
18938c2ecf20Sopenharmony_ci}
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_cistatic struct mlxsw_sp_port *
18968c2ecf20Sopenharmony_cimlxsw_sp_port_get_by_local_port(struct mlxsw_sp *mlxsw_sp, u8 local_port)
18978c2ecf20Sopenharmony_ci{
18988c2ecf20Sopenharmony_ci	if (mlxsw_sp->ports && mlxsw_sp->ports[local_port])
18998c2ecf20Sopenharmony_ci		return mlxsw_sp->ports[local_port];
19008c2ecf20Sopenharmony_ci	return NULL;
19018c2ecf20Sopenharmony_ci}
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port,
19048c2ecf20Sopenharmony_ci			       unsigned int count,
19058c2ecf20Sopenharmony_ci			       struct netlink_ext_ack *extack)
19068c2ecf20Sopenharmony_ci{
19078c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
19088c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_mapping port_mapping;
19098c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port;
19108c2ecf20Sopenharmony_ci	int max_width;
19118c2ecf20Sopenharmony_ci	u8 base_port;
19128c2ecf20Sopenharmony_ci	int offset;
19138c2ecf20Sopenharmony_ci	int i;
19148c2ecf20Sopenharmony_ci	int err;
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port);
19178c2ecf20Sopenharmony_ci	if (!mlxsw_sp_port) {
19188c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n",
19198c2ecf20Sopenharmony_ci			local_port);
19208c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Port number does not exist");
19218c2ecf20Sopenharmony_ci		return -EINVAL;
19228c2ecf20Sopenharmony_ci	}
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	max_width = mlxsw_core_module_max_width(mlxsw_core,
19258c2ecf20Sopenharmony_ci						mlxsw_sp_port->mapping.module);
19268c2ecf20Sopenharmony_ci	if (max_width < 0) {
19278c2ecf20Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n");
19288c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module");
19298c2ecf20Sopenharmony_ci		return max_width;
19308c2ecf20Sopenharmony_ci	}
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	/* Split port with non-max cannot be split. */
19338c2ecf20Sopenharmony_ci	if (mlxsw_sp_port->mapping.width != max_width) {
19348c2ecf20Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Port cannot be split\n");
19358c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Port cannot be split");
19368c2ecf20Sopenharmony_ci		return -EINVAL;
19378c2ecf20Sopenharmony_ci	}
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	offset = mlxsw_sp_local_ports_offset(mlxsw_core, count, max_width);
19408c2ecf20Sopenharmony_ci	if (offset < 0) {
19418c2ecf20Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Cannot obtain local port offset\n");
19428c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Cannot obtain local port offset");
19438c2ecf20Sopenharmony_ci		return -EINVAL;
19448c2ecf20Sopenharmony_ci	}
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	/* Only in case max split is being done, the local port and
19478c2ecf20Sopenharmony_ci	 * base port may differ.
19488c2ecf20Sopenharmony_ci	 */
19498c2ecf20Sopenharmony_ci	base_port = count == max_width ?
19508c2ecf20Sopenharmony_ci		    mlxsw_sp_cluster_base_port_get(local_port, max_width) :
19518c2ecf20Sopenharmony_ci		    local_port;
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	for (i = 0; i < count * offset; i++) {
19548c2ecf20Sopenharmony_ci		/* Expect base port to exist and also the one in the middle in
19558c2ecf20Sopenharmony_ci		 * case of maximal split count.
19568c2ecf20Sopenharmony_ci		 */
19578c2ecf20Sopenharmony_ci		if (i == 0 || (count == max_width && i == count / 2))
19588c2ecf20Sopenharmony_ci			continue;
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_ci		if (mlxsw_sp_port_created(mlxsw_sp, base_port + i)) {
19618c2ecf20Sopenharmony_ci			netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n");
19628c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Invalid split configuration");
19638c2ecf20Sopenharmony_ci			return -EINVAL;
19648c2ecf20Sopenharmony_ci		}
19658c2ecf20Sopenharmony_ci	}
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	port_mapping = mlxsw_sp_port->mapping;
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++)
19708c2ecf20Sopenharmony_ci		if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset))
19718c2ecf20Sopenharmony_ci			mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset);
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_split_create(mlxsw_sp, base_port, &port_mapping,
19748c2ecf20Sopenharmony_ci					 count, offset);
19758c2ecf20Sopenharmony_ci	if (err) {
19768c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to create split ports\n");
19778c2ecf20Sopenharmony_ci		goto err_port_split_create;
19788c2ecf20Sopenharmony_ci	}
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci	return 0;
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_cierr_port_split_create:
19838c2ecf20Sopenharmony_ci	mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, offset);
19848c2ecf20Sopenharmony_ci	return err;
19858c2ecf20Sopenharmony_ci}
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port,
19888c2ecf20Sopenharmony_ci				 struct netlink_ext_ack *extack)
19898c2ecf20Sopenharmony_ci{
19908c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
19918c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port;
19928c2ecf20Sopenharmony_ci	unsigned int count;
19938c2ecf20Sopenharmony_ci	int max_width;
19948c2ecf20Sopenharmony_ci	u8 base_port;
19958c2ecf20Sopenharmony_ci	int offset;
19968c2ecf20Sopenharmony_ci	int i;
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port);
19998c2ecf20Sopenharmony_ci	if (!mlxsw_sp_port) {
20008c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n",
20018c2ecf20Sopenharmony_ci			local_port);
20028c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Port number does not exist");
20038c2ecf20Sopenharmony_ci		return -EINVAL;
20048c2ecf20Sopenharmony_ci	}
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_ci	if (!mlxsw_sp_port->split) {
20078c2ecf20Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Port was not split\n");
20088c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Port was not split");
20098c2ecf20Sopenharmony_ci		return -EINVAL;
20108c2ecf20Sopenharmony_ci	}
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci	max_width = mlxsw_core_module_max_width(mlxsw_core,
20138c2ecf20Sopenharmony_ci						mlxsw_sp_port->mapping.module);
20148c2ecf20Sopenharmony_ci	if (max_width < 0) {
20158c2ecf20Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n");
20168c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module");
20178c2ecf20Sopenharmony_ci		return max_width;
20188c2ecf20Sopenharmony_ci	}
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	count = max_width / mlxsw_sp_port->mapping.width;
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	offset = mlxsw_sp_local_ports_offset(mlxsw_core, count, max_width);
20238c2ecf20Sopenharmony_ci	if (WARN_ON(offset < 0)) {
20248c2ecf20Sopenharmony_ci		netdev_err(mlxsw_sp_port->dev, "Cannot obtain local port offset\n");
20258c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Cannot obtain local port offset");
20268c2ecf20Sopenharmony_ci		return -EINVAL;
20278c2ecf20Sopenharmony_ci	}
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	base_port = mlxsw_sp_port->split_base_local_port;
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++)
20328c2ecf20Sopenharmony_ci		if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset))
20338c2ecf20Sopenharmony_ci			mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset);
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, offset);
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci	return 0;
20388c2ecf20Sopenharmony_ci}
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_cistatic void
20418c2ecf20Sopenharmony_cimlxsw_sp_port_down_wipe_counters(struct mlxsw_sp_port *mlxsw_sp_port)
20428c2ecf20Sopenharmony_ci{
20438c2ecf20Sopenharmony_ci	int i;
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci	for (i = 0; i < TC_MAX_QUEUE; i++)
20468c2ecf20Sopenharmony_ci		mlxsw_sp_port->periodic_hw_stats.xstats.backlog[i] = 0;
20478c2ecf20Sopenharmony_ci}
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_cistatic void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
20508c2ecf20Sopenharmony_ci				     char *pude_pl, void *priv)
20518c2ecf20Sopenharmony_ci{
20528c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = priv;
20538c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port;
20548c2ecf20Sopenharmony_ci	enum mlxsw_reg_pude_oper_status status;
20558c2ecf20Sopenharmony_ci	unsigned int max_ports;
20568c2ecf20Sopenharmony_ci	u8 local_port;
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci	max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
20598c2ecf20Sopenharmony_ci	local_port = mlxsw_reg_pude_local_port_get(pude_pl);
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!local_port || local_port >= max_ports))
20628c2ecf20Sopenharmony_ci		return;
20638c2ecf20Sopenharmony_ci	mlxsw_sp_port = mlxsw_sp->ports[local_port];
20648c2ecf20Sopenharmony_ci	if (!mlxsw_sp_port)
20658c2ecf20Sopenharmony_ci		return;
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci	status = mlxsw_reg_pude_oper_status_get(pude_pl);
20688c2ecf20Sopenharmony_ci	if (status == MLXSW_PORT_OPER_STATUS_UP) {
20698c2ecf20Sopenharmony_ci		netdev_info(mlxsw_sp_port->dev, "link up\n");
20708c2ecf20Sopenharmony_ci		netif_carrier_on(mlxsw_sp_port->dev);
20718c2ecf20Sopenharmony_ci		mlxsw_core_schedule_dw(&mlxsw_sp_port->ptp.shaper_dw, 0);
20728c2ecf20Sopenharmony_ci	} else {
20738c2ecf20Sopenharmony_ci		netdev_info(mlxsw_sp_port->dev, "link down\n");
20748c2ecf20Sopenharmony_ci		netif_carrier_off(mlxsw_sp_port->dev);
20758c2ecf20Sopenharmony_ci		mlxsw_sp_port_down_wipe_counters(mlxsw_sp_port);
20768c2ecf20Sopenharmony_ci	}
20778c2ecf20Sopenharmony_ci}
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_cistatic void mlxsw_sp1_ptp_fifo_event_func(struct mlxsw_sp *mlxsw_sp,
20808c2ecf20Sopenharmony_ci					  char *mtpptr_pl, bool ingress)
20818c2ecf20Sopenharmony_ci{
20828c2ecf20Sopenharmony_ci	u8 local_port;
20838c2ecf20Sopenharmony_ci	u8 num_rec;
20848c2ecf20Sopenharmony_ci	int i;
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci	local_port = mlxsw_reg_mtpptr_local_port_get(mtpptr_pl);
20878c2ecf20Sopenharmony_ci	num_rec = mlxsw_reg_mtpptr_num_rec_get(mtpptr_pl);
20888c2ecf20Sopenharmony_ci	for (i = 0; i < num_rec; i++) {
20898c2ecf20Sopenharmony_ci		u8 domain_number;
20908c2ecf20Sopenharmony_ci		u8 message_type;
20918c2ecf20Sopenharmony_ci		u16 sequence_id;
20928c2ecf20Sopenharmony_ci		u64 timestamp;
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci		mlxsw_reg_mtpptr_unpack(mtpptr_pl, i, &message_type,
20958c2ecf20Sopenharmony_ci					&domain_number, &sequence_id,
20968c2ecf20Sopenharmony_ci					&timestamp);
20978c2ecf20Sopenharmony_ci		mlxsw_sp1_ptp_got_timestamp(mlxsw_sp, ingress, local_port,
20988c2ecf20Sopenharmony_ci					    message_type, domain_number,
20998c2ecf20Sopenharmony_ci					    sequence_id, timestamp);
21008c2ecf20Sopenharmony_ci	}
21018c2ecf20Sopenharmony_ci}
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_cistatic void mlxsw_sp1_ptp_ing_fifo_event_func(const struct mlxsw_reg_info *reg,
21048c2ecf20Sopenharmony_ci					      char *mtpptr_pl, void *priv)
21058c2ecf20Sopenharmony_ci{
21068c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = priv;
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci	mlxsw_sp1_ptp_fifo_event_func(mlxsw_sp, mtpptr_pl, true);
21098c2ecf20Sopenharmony_ci}
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_cistatic void mlxsw_sp1_ptp_egr_fifo_event_func(const struct mlxsw_reg_info *reg,
21128c2ecf20Sopenharmony_ci					      char *mtpptr_pl, void *priv)
21138c2ecf20Sopenharmony_ci{
21148c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = priv;
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_ci	mlxsw_sp1_ptp_fifo_event_func(mlxsw_sp, mtpptr_pl, false);
21178c2ecf20Sopenharmony_ci}
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_civoid mlxsw_sp_rx_listener_no_mark_func(struct sk_buff *skb,
21208c2ecf20Sopenharmony_ci				       u8 local_port, void *priv)
21218c2ecf20Sopenharmony_ci{
21228c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = priv;
21238c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
21248c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_pcpu_stats *pcpu_stats;
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_ci	if (unlikely(!mlxsw_sp_port)) {
21278c2ecf20Sopenharmony_ci		dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n",
21288c2ecf20Sopenharmony_ci				     local_port);
21298c2ecf20Sopenharmony_ci		return;
21308c2ecf20Sopenharmony_ci	}
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_ci	skb->dev = mlxsw_sp_port->dev;
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci	pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats);
21358c2ecf20Sopenharmony_ci	u64_stats_update_begin(&pcpu_stats->syncp);
21368c2ecf20Sopenharmony_ci	pcpu_stats->rx_packets++;
21378c2ecf20Sopenharmony_ci	pcpu_stats->rx_bytes += skb->len;
21388c2ecf20Sopenharmony_ci	u64_stats_update_end(&pcpu_stats->syncp);
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	skb->protocol = eth_type_trans(skb, skb->dev);
21418c2ecf20Sopenharmony_ci	netif_receive_skb(skb);
21428c2ecf20Sopenharmony_ci}
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_cistatic void mlxsw_sp_rx_listener_mark_func(struct sk_buff *skb, u8 local_port,
21458c2ecf20Sopenharmony_ci					   void *priv)
21468c2ecf20Sopenharmony_ci{
21478c2ecf20Sopenharmony_ci	skb->offload_fwd_mark = 1;
21488c2ecf20Sopenharmony_ci	return mlxsw_sp_rx_listener_no_mark_func(skb, local_port, priv);
21498c2ecf20Sopenharmony_ci}
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_cistatic void mlxsw_sp_rx_listener_l3_mark_func(struct sk_buff *skb,
21528c2ecf20Sopenharmony_ci					      u8 local_port, void *priv)
21538c2ecf20Sopenharmony_ci{
21548c2ecf20Sopenharmony_ci	skb->offload_l3_fwd_mark = 1;
21558c2ecf20Sopenharmony_ci	skb->offload_fwd_mark = 1;
21568c2ecf20Sopenharmony_ci	return mlxsw_sp_rx_listener_no_mark_func(skb, local_port, priv);
21578c2ecf20Sopenharmony_ci}
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_civoid mlxsw_sp_ptp_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
21608c2ecf20Sopenharmony_ci			  u8 local_port)
21618c2ecf20Sopenharmony_ci{
21628c2ecf20Sopenharmony_ci	mlxsw_sp->ptp_ops->receive(mlxsw_sp, skb, local_port);
21638c2ecf20Sopenharmony_ci}
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_civoid mlxsw_sp_sample_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
21668c2ecf20Sopenharmony_ci			     u8 local_port)
21678c2ecf20Sopenharmony_ci{
21688c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
21698c2ecf20Sopenharmony_ci	struct mlxsw_sp_port_sample *sample;
21708c2ecf20Sopenharmony_ci	u32 size;
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci	if (unlikely(!mlxsw_sp_port)) {
21738c2ecf20Sopenharmony_ci		dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: sample skb received for non-existent port\n",
21748c2ecf20Sopenharmony_ci				     local_port);
21758c2ecf20Sopenharmony_ci		goto out;
21768c2ecf20Sopenharmony_ci	}
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci	rcu_read_lock();
21798c2ecf20Sopenharmony_ci	sample = rcu_dereference(mlxsw_sp_port->sample);
21808c2ecf20Sopenharmony_ci	if (!sample)
21818c2ecf20Sopenharmony_ci		goto out_unlock;
21828c2ecf20Sopenharmony_ci	size = sample->truncate ? sample->trunc_size : skb->len;
21838c2ecf20Sopenharmony_ci	psample_sample_packet(sample->psample_group, skb, size,
21848c2ecf20Sopenharmony_ci			      mlxsw_sp_port->dev->ifindex, 0, sample->rate);
21858c2ecf20Sopenharmony_ciout_unlock:
21868c2ecf20Sopenharmony_ci	rcu_read_unlock();
21878c2ecf20Sopenharmony_ciout:
21888c2ecf20Sopenharmony_ci	consume_skb(skb);
21898c2ecf20Sopenharmony_ci}
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci#define MLXSW_SP_RXL_NO_MARK(_trap_id, _action, _trap_group, _is_ctrl)	\
21928c2ecf20Sopenharmony_ci	MLXSW_RXL(mlxsw_sp_rx_listener_no_mark_func, _trap_id, _action,	\
21938c2ecf20Sopenharmony_ci		  _is_ctrl, SP_##_trap_group, DISCARD)
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci#define MLXSW_SP_RXL_MARK(_trap_id, _action, _trap_group, _is_ctrl)	\
21968c2ecf20Sopenharmony_ci	MLXSW_RXL(mlxsw_sp_rx_listener_mark_func, _trap_id, _action,	\
21978c2ecf20Sopenharmony_ci		_is_ctrl, SP_##_trap_group, DISCARD)
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_ci#define MLXSW_SP_RXL_L3_MARK(_trap_id, _action, _trap_group, _is_ctrl)	\
22008c2ecf20Sopenharmony_ci	MLXSW_RXL(mlxsw_sp_rx_listener_l3_mark_func, _trap_id, _action,	\
22018c2ecf20Sopenharmony_ci		_is_ctrl, SP_##_trap_group, DISCARD)
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci#define MLXSW_SP_EVENTL(_func, _trap_id)		\
22048c2ecf20Sopenharmony_ci	MLXSW_EVENTL(_func, _trap_id, SP_EVENT)
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_cistatic const struct mlxsw_listener mlxsw_sp_listener[] = {
22078c2ecf20Sopenharmony_ci	/* Events */
22088c2ecf20Sopenharmony_ci	MLXSW_SP_EVENTL(mlxsw_sp_pude_event_func, PUDE),
22098c2ecf20Sopenharmony_ci	/* L2 traps */
22108c2ecf20Sopenharmony_ci	MLXSW_SP_RXL_NO_MARK(FID_MISS, TRAP_TO_CPU, FID_MISS, false),
22118c2ecf20Sopenharmony_ci	/* L3 traps */
22128c2ecf20Sopenharmony_ci	MLXSW_SP_RXL_MARK(IPV6_UNSPECIFIED_ADDRESS, TRAP_TO_CPU, ROUTER_EXP,
22138c2ecf20Sopenharmony_ci			  false),
22148c2ecf20Sopenharmony_ci	MLXSW_SP_RXL_MARK(IPV6_LINK_LOCAL_SRC, TRAP_TO_CPU, ROUTER_EXP, false),
22158c2ecf20Sopenharmony_ci	MLXSW_SP_RXL_MARK(IPV6_MC_LINK_LOCAL_DEST, TRAP_TO_CPU, ROUTER_EXP,
22168c2ecf20Sopenharmony_ci			  false),
22178c2ecf20Sopenharmony_ci	MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_SIP_CLASS_E, FORWARD,
22188c2ecf20Sopenharmony_ci			     ROUTER_EXP, false),
22198c2ecf20Sopenharmony_ci	MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_MC_DMAC, FORWARD,
22208c2ecf20Sopenharmony_ci			     ROUTER_EXP, false),
22218c2ecf20Sopenharmony_ci	MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_SIP_DIP, FORWARD,
22228c2ecf20Sopenharmony_ci			     ROUTER_EXP, false),
22238c2ecf20Sopenharmony_ci	MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_DIP_LINK_LOCAL, FORWARD,
22248c2ecf20Sopenharmony_ci			     ROUTER_EXP, false),
22258c2ecf20Sopenharmony_ci	/* Multicast Router Traps */
22268c2ecf20Sopenharmony_ci	MLXSW_SP_RXL_MARK(ACL1, TRAP_TO_CPU, MULTICAST, false),
22278c2ecf20Sopenharmony_ci	MLXSW_SP_RXL_L3_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false),
22288c2ecf20Sopenharmony_ci	/* NVE traps */
22298c2ecf20Sopenharmony_ci	MLXSW_SP_RXL_MARK(NVE_ENCAP_ARP, TRAP_TO_CPU, NEIGH_DISCOVERY, false),
22308c2ecf20Sopenharmony_ci};
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_cistatic const struct mlxsw_listener mlxsw_sp1_listener[] = {
22338c2ecf20Sopenharmony_ci	/* Events */
22348c2ecf20Sopenharmony_ci	MLXSW_EVENTL(mlxsw_sp1_ptp_egr_fifo_event_func, PTP_EGR_FIFO, SP_PTP0),
22358c2ecf20Sopenharmony_ci	MLXSW_EVENTL(mlxsw_sp1_ptp_ing_fifo_event_func, PTP_ING_FIFO, SP_PTP0),
22368c2ecf20Sopenharmony_ci};
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_cistatic int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core)
22398c2ecf20Sopenharmony_ci{
22408c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
22418c2ecf20Sopenharmony_ci	char qpcr_pl[MLXSW_REG_QPCR_LEN];
22428c2ecf20Sopenharmony_ci	enum mlxsw_reg_qpcr_ir_units ir_units;
22438c2ecf20Sopenharmony_ci	int max_cpu_policers;
22448c2ecf20Sopenharmony_ci	bool is_bytes;
22458c2ecf20Sopenharmony_ci	u8 burst_size;
22468c2ecf20Sopenharmony_ci	u32 rate;
22478c2ecf20Sopenharmony_ci	int i, err;
22488c2ecf20Sopenharmony_ci
22498c2ecf20Sopenharmony_ci	if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_CPU_POLICERS))
22508c2ecf20Sopenharmony_ci		return -EIO;
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_ci	max_cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS);
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci	ir_units = MLXSW_REG_QPCR_IR_UNITS_M;
22558c2ecf20Sopenharmony_ci	for (i = 0; i < max_cpu_policers; i++) {
22568c2ecf20Sopenharmony_ci		is_bytes = false;
22578c2ecf20Sopenharmony_ci		switch (i) {
22588c2ecf20Sopenharmony_ci		case MLXSW_REG_HTGT_TRAP_GROUP_SP_ROUTER_EXP:
22598c2ecf20Sopenharmony_ci		case MLXSW_REG_HTGT_TRAP_GROUP_SP_MULTICAST:
22608c2ecf20Sopenharmony_ci		case MLXSW_REG_HTGT_TRAP_GROUP_SP_FID_MISS:
22618c2ecf20Sopenharmony_ci			rate = 1024;
22628c2ecf20Sopenharmony_ci			burst_size = 7;
22638c2ecf20Sopenharmony_ci			break;
22648c2ecf20Sopenharmony_ci		default:
22658c2ecf20Sopenharmony_ci			continue;
22668c2ecf20Sopenharmony_ci		}
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci		__set_bit(i, mlxsw_sp->trap->policers_usage);
22698c2ecf20Sopenharmony_ci		mlxsw_reg_qpcr_pack(qpcr_pl, i, ir_units, is_bytes, rate,
22708c2ecf20Sopenharmony_ci				    burst_size);
22718c2ecf20Sopenharmony_ci		err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(qpcr), qpcr_pl);
22728c2ecf20Sopenharmony_ci		if (err)
22738c2ecf20Sopenharmony_ci			return err;
22748c2ecf20Sopenharmony_ci	}
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	return 0;
22778c2ecf20Sopenharmony_ci}
22788c2ecf20Sopenharmony_ci
22798c2ecf20Sopenharmony_cistatic int mlxsw_sp_trap_groups_set(struct mlxsw_core *mlxsw_core)
22808c2ecf20Sopenharmony_ci{
22818c2ecf20Sopenharmony_ci	char htgt_pl[MLXSW_REG_HTGT_LEN];
22828c2ecf20Sopenharmony_ci	enum mlxsw_reg_htgt_trap_group i;
22838c2ecf20Sopenharmony_ci	int max_cpu_policers;
22848c2ecf20Sopenharmony_ci	int max_trap_groups;
22858c2ecf20Sopenharmony_ci	u8 priority, tc;
22868c2ecf20Sopenharmony_ci	u16 policer_id;
22878c2ecf20Sopenharmony_ci	int err;
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci	if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_TRAP_GROUPS))
22908c2ecf20Sopenharmony_ci		return -EIO;
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_ci	max_trap_groups = MLXSW_CORE_RES_GET(mlxsw_core, MAX_TRAP_GROUPS);
22938c2ecf20Sopenharmony_ci	max_cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS);
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ci	for (i = 0; i < max_trap_groups; i++) {
22968c2ecf20Sopenharmony_ci		policer_id = i;
22978c2ecf20Sopenharmony_ci		switch (i) {
22988c2ecf20Sopenharmony_ci		case MLXSW_REG_HTGT_TRAP_GROUP_SP_ROUTER_EXP:
22998c2ecf20Sopenharmony_ci		case MLXSW_REG_HTGT_TRAP_GROUP_SP_MULTICAST:
23008c2ecf20Sopenharmony_ci		case MLXSW_REG_HTGT_TRAP_GROUP_SP_FID_MISS:
23018c2ecf20Sopenharmony_ci			priority = 1;
23028c2ecf20Sopenharmony_ci			tc = 1;
23038c2ecf20Sopenharmony_ci			break;
23048c2ecf20Sopenharmony_ci		case MLXSW_REG_HTGT_TRAP_GROUP_SP_EVENT:
23058c2ecf20Sopenharmony_ci			priority = MLXSW_REG_HTGT_DEFAULT_PRIORITY;
23068c2ecf20Sopenharmony_ci			tc = MLXSW_REG_HTGT_DEFAULT_TC;
23078c2ecf20Sopenharmony_ci			policer_id = MLXSW_REG_HTGT_INVALID_POLICER;
23088c2ecf20Sopenharmony_ci			break;
23098c2ecf20Sopenharmony_ci		default:
23108c2ecf20Sopenharmony_ci			continue;
23118c2ecf20Sopenharmony_ci		}
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci		if (max_cpu_policers <= policer_id &&
23148c2ecf20Sopenharmony_ci		    policer_id != MLXSW_REG_HTGT_INVALID_POLICER)
23158c2ecf20Sopenharmony_ci			return -EIO;
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ci		mlxsw_reg_htgt_pack(htgt_pl, i, policer_id, priority, tc);
23188c2ecf20Sopenharmony_ci		err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
23198c2ecf20Sopenharmony_ci		if (err)
23208c2ecf20Sopenharmony_ci			return err;
23218c2ecf20Sopenharmony_ci	}
23228c2ecf20Sopenharmony_ci
23238c2ecf20Sopenharmony_ci	return 0;
23248c2ecf20Sopenharmony_ci}
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_cistatic int mlxsw_sp_traps_register(struct mlxsw_sp *mlxsw_sp,
23278c2ecf20Sopenharmony_ci				   const struct mlxsw_listener listeners[],
23288c2ecf20Sopenharmony_ci				   size_t listeners_count)
23298c2ecf20Sopenharmony_ci{
23308c2ecf20Sopenharmony_ci	int i;
23318c2ecf20Sopenharmony_ci	int err;
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	for (i = 0; i < listeners_count; i++) {
23348c2ecf20Sopenharmony_ci		err = mlxsw_core_trap_register(mlxsw_sp->core,
23358c2ecf20Sopenharmony_ci					       &listeners[i],
23368c2ecf20Sopenharmony_ci					       mlxsw_sp);
23378c2ecf20Sopenharmony_ci		if (err)
23388c2ecf20Sopenharmony_ci			goto err_listener_register;
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci	}
23418c2ecf20Sopenharmony_ci	return 0;
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_cierr_listener_register:
23448c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--) {
23458c2ecf20Sopenharmony_ci		mlxsw_core_trap_unregister(mlxsw_sp->core,
23468c2ecf20Sopenharmony_ci					   &listeners[i],
23478c2ecf20Sopenharmony_ci					   mlxsw_sp);
23488c2ecf20Sopenharmony_ci	}
23498c2ecf20Sopenharmony_ci	return err;
23508c2ecf20Sopenharmony_ci}
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_cistatic void mlxsw_sp_traps_unregister(struct mlxsw_sp *mlxsw_sp,
23538c2ecf20Sopenharmony_ci				      const struct mlxsw_listener listeners[],
23548c2ecf20Sopenharmony_ci				      size_t listeners_count)
23558c2ecf20Sopenharmony_ci{
23568c2ecf20Sopenharmony_ci	int i;
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	for (i = 0; i < listeners_count; i++) {
23598c2ecf20Sopenharmony_ci		mlxsw_core_trap_unregister(mlxsw_sp->core,
23608c2ecf20Sopenharmony_ci					   &listeners[i],
23618c2ecf20Sopenharmony_ci					   mlxsw_sp);
23628c2ecf20Sopenharmony_ci	}
23638c2ecf20Sopenharmony_ci}
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_cistatic int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)
23668c2ecf20Sopenharmony_ci{
23678c2ecf20Sopenharmony_ci	struct mlxsw_sp_trap *trap;
23688c2ecf20Sopenharmony_ci	u64 max_policers;
23698c2ecf20Sopenharmony_ci	int err;
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci	if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_CPU_POLICERS))
23728c2ecf20Sopenharmony_ci		return -EIO;
23738c2ecf20Sopenharmony_ci	max_policers = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_CPU_POLICERS);
23748c2ecf20Sopenharmony_ci	trap = kzalloc(struct_size(trap, policers_usage,
23758c2ecf20Sopenharmony_ci				   BITS_TO_LONGS(max_policers)), GFP_KERNEL);
23768c2ecf20Sopenharmony_ci	if (!trap)
23778c2ecf20Sopenharmony_ci		return -ENOMEM;
23788c2ecf20Sopenharmony_ci	trap->max_policers = max_policers;
23798c2ecf20Sopenharmony_ci	mlxsw_sp->trap = trap;
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci	err = mlxsw_sp_cpu_policers_set(mlxsw_sp->core);
23828c2ecf20Sopenharmony_ci	if (err)
23838c2ecf20Sopenharmony_ci		goto err_cpu_policers_set;
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci	err = mlxsw_sp_trap_groups_set(mlxsw_sp->core);
23868c2ecf20Sopenharmony_ci	if (err)
23878c2ecf20Sopenharmony_ci		goto err_trap_groups_set;
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci	err = mlxsw_sp_traps_register(mlxsw_sp, mlxsw_sp_listener,
23908c2ecf20Sopenharmony_ci				      ARRAY_SIZE(mlxsw_sp_listener));
23918c2ecf20Sopenharmony_ci	if (err)
23928c2ecf20Sopenharmony_ci		goto err_traps_register;
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_ci	err = mlxsw_sp_traps_register(mlxsw_sp, mlxsw_sp->listeners,
23958c2ecf20Sopenharmony_ci				      mlxsw_sp->listeners_count);
23968c2ecf20Sopenharmony_ci	if (err)
23978c2ecf20Sopenharmony_ci		goto err_extra_traps_init;
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	return 0;
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_cierr_extra_traps_init:
24028c2ecf20Sopenharmony_ci	mlxsw_sp_traps_unregister(mlxsw_sp, mlxsw_sp_listener,
24038c2ecf20Sopenharmony_ci				  ARRAY_SIZE(mlxsw_sp_listener));
24048c2ecf20Sopenharmony_cierr_traps_register:
24058c2ecf20Sopenharmony_cierr_trap_groups_set:
24068c2ecf20Sopenharmony_cierr_cpu_policers_set:
24078c2ecf20Sopenharmony_ci	kfree(trap);
24088c2ecf20Sopenharmony_ci	return err;
24098c2ecf20Sopenharmony_ci}
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_cistatic void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)
24128c2ecf20Sopenharmony_ci{
24138c2ecf20Sopenharmony_ci	mlxsw_sp_traps_unregister(mlxsw_sp, mlxsw_sp->listeners,
24148c2ecf20Sopenharmony_ci				  mlxsw_sp->listeners_count);
24158c2ecf20Sopenharmony_ci	mlxsw_sp_traps_unregister(mlxsw_sp, mlxsw_sp_listener,
24168c2ecf20Sopenharmony_ci				  ARRAY_SIZE(mlxsw_sp_listener));
24178c2ecf20Sopenharmony_ci	kfree(mlxsw_sp->trap);
24188c2ecf20Sopenharmony_ci}
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci#define MLXSW_SP_LAG_SEED_INIT 0xcafecafe
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp)
24238c2ecf20Sopenharmony_ci{
24248c2ecf20Sopenharmony_ci	char slcr_pl[MLXSW_REG_SLCR_LEN];
24258c2ecf20Sopenharmony_ci	u32 seed;
24268c2ecf20Sopenharmony_ci	int err;
24278c2ecf20Sopenharmony_ci
24288c2ecf20Sopenharmony_ci	seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac),
24298c2ecf20Sopenharmony_ci		     MLXSW_SP_LAG_SEED_INIT);
24308c2ecf20Sopenharmony_ci	mlxsw_reg_slcr_pack(slcr_pl, MLXSW_REG_SLCR_LAG_HASH_SMAC |
24318c2ecf20Sopenharmony_ci				     MLXSW_REG_SLCR_LAG_HASH_DMAC |
24328c2ecf20Sopenharmony_ci				     MLXSW_REG_SLCR_LAG_HASH_ETHERTYPE |
24338c2ecf20Sopenharmony_ci				     MLXSW_REG_SLCR_LAG_HASH_VLANID |
24348c2ecf20Sopenharmony_ci				     MLXSW_REG_SLCR_LAG_HASH_SIP |
24358c2ecf20Sopenharmony_ci				     MLXSW_REG_SLCR_LAG_HASH_DIP |
24368c2ecf20Sopenharmony_ci				     MLXSW_REG_SLCR_LAG_HASH_SPORT |
24378c2ecf20Sopenharmony_ci				     MLXSW_REG_SLCR_LAG_HASH_DPORT |
24388c2ecf20Sopenharmony_ci				     MLXSW_REG_SLCR_LAG_HASH_IPPROTO, seed);
24398c2ecf20Sopenharmony_ci	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcr), slcr_pl);
24408c2ecf20Sopenharmony_ci	if (err)
24418c2ecf20Sopenharmony_ci		return err;
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_ci	if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LAG) ||
24448c2ecf20Sopenharmony_ci	    !MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LAG_MEMBERS))
24458c2ecf20Sopenharmony_ci		return -EIO;
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_ci	mlxsw_sp->lags = kcalloc(MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_LAG),
24488c2ecf20Sopenharmony_ci				 sizeof(struct mlxsw_sp_upper),
24498c2ecf20Sopenharmony_ci				 GFP_KERNEL);
24508c2ecf20Sopenharmony_ci	if (!mlxsw_sp->lags)
24518c2ecf20Sopenharmony_ci		return -ENOMEM;
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ci	return 0;
24548c2ecf20Sopenharmony_ci}
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_cistatic void mlxsw_sp_lag_fini(struct mlxsw_sp *mlxsw_sp)
24578c2ecf20Sopenharmony_ci{
24588c2ecf20Sopenharmony_ci	kfree(mlxsw_sp->lags);
24598c2ecf20Sopenharmony_ci}
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_cistatic int mlxsw_sp_basic_trap_groups_set(struct mlxsw_core *mlxsw_core)
24628c2ecf20Sopenharmony_ci{
24638c2ecf20Sopenharmony_ci	char htgt_pl[MLXSW_REG_HTGT_LEN];
24648c2ecf20Sopenharmony_ci	int err;
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_ci	mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_EMAD,
24678c2ecf20Sopenharmony_ci			    MLXSW_REG_HTGT_INVALID_POLICER,
24688c2ecf20Sopenharmony_ci			    MLXSW_REG_HTGT_DEFAULT_PRIORITY,
24698c2ecf20Sopenharmony_ci			    MLXSW_REG_HTGT_DEFAULT_TC);
24708c2ecf20Sopenharmony_ci	err =  mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
24718c2ecf20Sopenharmony_ci	if (err)
24728c2ecf20Sopenharmony_ci		return err;
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_ci	mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_MFDE,
24758c2ecf20Sopenharmony_ci			    MLXSW_REG_HTGT_INVALID_POLICER,
24768c2ecf20Sopenharmony_ci			    MLXSW_REG_HTGT_DEFAULT_PRIORITY,
24778c2ecf20Sopenharmony_ci			    MLXSW_REG_HTGT_DEFAULT_TC);
24788c2ecf20Sopenharmony_ci	err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
24798c2ecf20Sopenharmony_ci	if (err)
24808c2ecf20Sopenharmony_ci		return err;
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci	mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_MTWE,
24838c2ecf20Sopenharmony_ci			    MLXSW_REG_HTGT_INVALID_POLICER,
24848c2ecf20Sopenharmony_ci			    MLXSW_REG_HTGT_DEFAULT_PRIORITY,
24858c2ecf20Sopenharmony_ci			    MLXSW_REG_HTGT_DEFAULT_TC);
24868c2ecf20Sopenharmony_ci	err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
24878c2ecf20Sopenharmony_ci	if (err)
24888c2ecf20Sopenharmony_ci		return err;
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_ci	mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_PMPE,
24918c2ecf20Sopenharmony_ci			    MLXSW_REG_HTGT_INVALID_POLICER,
24928c2ecf20Sopenharmony_ci			    MLXSW_REG_HTGT_DEFAULT_PRIORITY,
24938c2ecf20Sopenharmony_ci			    MLXSW_REG_HTGT_DEFAULT_TC);
24948c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);
24958c2ecf20Sopenharmony_ci}
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_ptp_ops mlxsw_sp1_ptp_ops = {
24988c2ecf20Sopenharmony_ci	.clock_init	= mlxsw_sp1_ptp_clock_init,
24998c2ecf20Sopenharmony_ci	.clock_fini	= mlxsw_sp1_ptp_clock_fini,
25008c2ecf20Sopenharmony_ci	.init		= mlxsw_sp1_ptp_init,
25018c2ecf20Sopenharmony_ci	.fini		= mlxsw_sp1_ptp_fini,
25028c2ecf20Sopenharmony_ci	.receive	= mlxsw_sp1_ptp_receive,
25038c2ecf20Sopenharmony_ci	.transmitted	= mlxsw_sp1_ptp_transmitted,
25048c2ecf20Sopenharmony_ci	.hwtstamp_get	= mlxsw_sp1_ptp_hwtstamp_get,
25058c2ecf20Sopenharmony_ci	.hwtstamp_set	= mlxsw_sp1_ptp_hwtstamp_set,
25068c2ecf20Sopenharmony_ci	.shaper_work	= mlxsw_sp1_ptp_shaper_work,
25078c2ecf20Sopenharmony_ci	.get_ts_info	= mlxsw_sp1_ptp_get_ts_info,
25088c2ecf20Sopenharmony_ci	.get_stats_count = mlxsw_sp1_get_stats_count,
25098c2ecf20Sopenharmony_ci	.get_stats_strings = mlxsw_sp1_get_stats_strings,
25108c2ecf20Sopenharmony_ci	.get_stats	= mlxsw_sp1_get_stats,
25118c2ecf20Sopenharmony_ci};
25128c2ecf20Sopenharmony_ci
25138c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = {
25148c2ecf20Sopenharmony_ci	.clock_init	= mlxsw_sp2_ptp_clock_init,
25158c2ecf20Sopenharmony_ci	.clock_fini	= mlxsw_sp2_ptp_clock_fini,
25168c2ecf20Sopenharmony_ci	.init		= mlxsw_sp2_ptp_init,
25178c2ecf20Sopenharmony_ci	.fini		= mlxsw_sp2_ptp_fini,
25188c2ecf20Sopenharmony_ci	.receive	= mlxsw_sp2_ptp_receive,
25198c2ecf20Sopenharmony_ci	.transmitted	= mlxsw_sp2_ptp_transmitted,
25208c2ecf20Sopenharmony_ci	.hwtstamp_get	= mlxsw_sp2_ptp_hwtstamp_get,
25218c2ecf20Sopenharmony_ci	.hwtstamp_set	= mlxsw_sp2_ptp_hwtstamp_set,
25228c2ecf20Sopenharmony_ci	.shaper_work	= mlxsw_sp2_ptp_shaper_work,
25238c2ecf20Sopenharmony_ci	.get_ts_info	= mlxsw_sp2_ptp_get_ts_info,
25248c2ecf20Sopenharmony_ci	.get_stats_count = mlxsw_sp2_get_stats_count,
25258c2ecf20Sopenharmony_ci	.get_stats_strings = mlxsw_sp2_get_stats_strings,
25268c2ecf20Sopenharmony_ci	.get_stats	= mlxsw_sp2_get_stats,
25278c2ecf20Sopenharmony_ci};
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_event(struct notifier_block *unused,
25308c2ecf20Sopenharmony_ci				    unsigned long event, void *ptr);
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_cistatic int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
25338c2ecf20Sopenharmony_ci			 const struct mlxsw_bus_info *mlxsw_bus_info,
25348c2ecf20Sopenharmony_ci			 struct netlink_ext_ack *extack)
25358c2ecf20Sopenharmony_ci{
25368c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
25378c2ecf20Sopenharmony_ci	int err;
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci	mlxsw_sp->core = mlxsw_core;
25408c2ecf20Sopenharmony_ci	mlxsw_sp->bus_info = mlxsw_bus_info;
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_ci	mlxsw_core_emad_string_tlv_enable(mlxsw_core);
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci	err = mlxsw_sp_base_mac_get(mlxsw_sp);
25458c2ecf20Sopenharmony_ci	if (err) {
25468c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to get base mac\n");
25478c2ecf20Sopenharmony_ci		return err;
25488c2ecf20Sopenharmony_ci	}
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ci	err = mlxsw_sp_kvdl_init(mlxsw_sp);
25518c2ecf20Sopenharmony_ci	if (err) {
25528c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize KVDL\n");
25538c2ecf20Sopenharmony_ci		return err;
25548c2ecf20Sopenharmony_ci	}
25558c2ecf20Sopenharmony_ci
25568c2ecf20Sopenharmony_ci	err = mlxsw_sp_fids_init(mlxsw_sp);
25578c2ecf20Sopenharmony_ci	if (err) {
25588c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n");
25598c2ecf20Sopenharmony_ci		goto err_fids_init;
25608c2ecf20Sopenharmony_ci	}
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	err = mlxsw_sp_policers_init(mlxsw_sp);
25638c2ecf20Sopenharmony_ci	if (err) {
25648c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize policers\n");
25658c2ecf20Sopenharmony_ci		goto err_policers_init;
25668c2ecf20Sopenharmony_ci	}
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_ci	err = mlxsw_sp_traps_init(mlxsw_sp);
25698c2ecf20Sopenharmony_ci	if (err) {
25708c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n");
25718c2ecf20Sopenharmony_ci		goto err_traps_init;
25728c2ecf20Sopenharmony_ci	}
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci	err = mlxsw_sp_devlink_traps_init(mlxsw_sp);
25758c2ecf20Sopenharmony_ci	if (err) {
25768c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize devlink traps\n");
25778c2ecf20Sopenharmony_ci		goto err_devlink_traps_init;
25788c2ecf20Sopenharmony_ci	}
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	err = mlxsw_sp_buffers_init(mlxsw_sp);
25818c2ecf20Sopenharmony_ci	if (err) {
25828c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize buffers\n");
25838c2ecf20Sopenharmony_ci		goto err_buffers_init;
25848c2ecf20Sopenharmony_ci	}
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_ci	err = mlxsw_sp_lag_init(mlxsw_sp);
25878c2ecf20Sopenharmony_ci	if (err) {
25888c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize LAG\n");
25898c2ecf20Sopenharmony_ci		goto err_lag_init;
25908c2ecf20Sopenharmony_ci	}
25918c2ecf20Sopenharmony_ci
25928c2ecf20Sopenharmony_ci	/* Initialize SPAN before router and switchdev, so that those components
25938c2ecf20Sopenharmony_ci	 * can call mlxsw_sp_span_respin().
25948c2ecf20Sopenharmony_ci	 */
25958c2ecf20Sopenharmony_ci	err = mlxsw_sp_span_init(mlxsw_sp);
25968c2ecf20Sopenharmony_ci	if (err) {
25978c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to init span system\n");
25988c2ecf20Sopenharmony_ci		goto err_span_init;
25998c2ecf20Sopenharmony_ci	}
26008c2ecf20Sopenharmony_ci
26018c2ecf20Sopenharmony_ci	err = mlxsw_sp_switchdev_init(mlxsw_sp);
26028c2ecf20Sopenharmony_ci	if (err) {
26038c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize switchdev\n");
26048c2ecf20Sopenharmony_ci		goto err_switchdev_init;
26058c2ecf20Sopenharmony_ci	}
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci	err = mlxsw_sp_counter_pool_init(mlxsw_sp);
26088c2ecf20Sopenharmony_ci	if (err) {
26098c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to init counter pool\n");
26108c2ecf20Sopenharmony_ci		goto err_counter_pool_init;
26118c2ecf20Sopenharmony_ci	}
26128c2ecf20Sopenharmony_ci
26138c2ecf20Sopenharmony_ci	err = mlxsw_sp_afa_init(mlxsw_sp);
26148c2ecf20Sopenharmony_ci	if (err) {
26158c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL actions\n");
26168c2ecf20Sopenharmony_ci		goto err_afa_init;
26178c2ecf20Sopenharmony_ci	}
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci	err = mlxsw_sp_nve_init(mlxsw_sp);
26208c2ecf20Sopenharmony_ci	if (err) {
26218c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize NVE\n");
26228c2ecf20Sopenharmony_ci		goto err_nve_init;
26238c2ecf20Sopenharmony_ci	}
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci	err = mlxsw_sp_acl_init(mlxsw_sp);
26268c2ecf20Sopenharmony_ci	if (err) {
26278c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL\n");
26288c2ecf20Sopenharmony_ci		goto err_acl_init;
26298c2ecf20Sopenharmony_ci	}
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci	err = mlxsw_sp_router_init(mlxsw_sp, extack);
26328c2ecf20Sopenharmony_ci	if (err) {
26338c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n");
26348c2ecf20Sopenharmony_ci		goto err_router_init;
26358c2ecf20Sopenharmony_ci	}
26368c2ecf20Sopenharmony_ci
26378c2ecf20Sopenharmony_ci	if (mlxsw_sp->bus_info->read_frc_capable) {
26388c2ecf20Sopenharmony_ci		/* NULL is a valid return value from clock_init */
26398c2ecf20Sopenharmony_ci		mlxsw_sp->clock =
26408c2ecf20Sopenharmony_ci			mlxsw_sp->ptp_ops->clock_init(mlxsw_sp,
26418c2ecf20Sopenharmony_ci						      mlxsw_sp->bus_info->dev);
26428c2ecf20Sopenharmony_ci		if (IS_ERR(mlxsw_sp->clock)) {
26438c2ecf20Sopenharmony_ci			err = PTR_ERR(mlxsw_sp->clock);
26448c2ecf20Sopenharmony_ci			dev_err(mlxsw_sp->bus_info->dev, "Failed to init ptp clock\n");
26458c2ecf20Sopenharmony_ci			goto err_ptp_clock_init;
26468c2ecf20Sopenharmony_ci		}
26478c2ecf20Sopenharmony_ci	}
26488c2ecf20Sopenharmony_ci
26498c2ecf20Sopenharmony_ci	if (mlxsw_sp->clock) {
26508c2ecf20Sopenharmony_ci		/* NULL is a valid return value from ptp_ops->init */
26518c2ecf20Sopenharmony_ci		mlxsw_sp->ptp_state = mlxsw_sp->ptp_ops->init(mlxsw_sp);
26528c2ecf20Sopenharmony_ci		if (IS_ERR(mlxsw_sp->ptp_state)) {
26538c2ecf20Sopenharmony_ci			err = PTR_ERR(mlxsw_sp->ptp_state);
26548c2ecf20Sopenharmony_ci			dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize PTP\n");
26558c2ecf20Sopenharmony_ci			goto err_ptp_init;
26568c2ecf20Sopenharmony_ci		}
26578c2ecf20Sopenharmony_ci	}
26588c2ecf20Sopenharmony_ci
26598c2ecf20Sopenharmony_ci	/* Initialize netdevice notifier after router and SPAN is initialized,
26608c2ecf20Sopenharmony_ci	 * so that the event handler can use router structures and call SPAN
26618c2ecf20Sopenharmony_ci	 * respin.
26628c2ecf20Sopenharmony_ci	 */
26638c2ecf20Sopenharmony_ci	mlxsw_sp->netdevice_nb.notifier_call = mlxsw_sp_netdevice_event;
26648c2ecf20Sopenharmony_ci	err = register_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
26658c2ecf20Sopenharmony_ci					      &mlxsw_sp->netdevice_nb);
26668c2ecf20Sopenharmony_ci	if (err) {
26678c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to register netdev notifier\n");
26688c2ecf20Sopenharmony_ci		goto err_netdev_notifier;
26698c2ecf20Sopenharmony_ci	}
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_ci	err = mlxsw_sp_dpipe_init(mlxsw_sp);
26728c2ecf20Sopenharmony_ci	if (err) {
26738c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to init pipeline debug\n");
26748c2ecf20Sopenharmony_ci		goto err_dpipe_init;
26758c2ecf20Sopenharmony_ci	}
26768c2ecf20Sopenharmony_ci
26778c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_module_info_init(mlxsw_sp);
26788c2ecf20Sopenharmony_ci	if (err) {
26798c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to init port module info\n");
26808c2ecf20Sopenharmony_ci		goto err_port_module_info_init;
26818c2ecf20Sopenharmony_ci	}
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci	err = mlxsw_sp_ports_create(mlxsw_sp);
26848c2ecf20Sopenharmony_ci	if (err) {
26858c2ecf20Sopenharmony_ci		dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n");
26868c2ecf20Sopenharmony_ci		goto err_ports_create;
26878c2ecf20Sopenharmony_ci	}
26888c2ecf20Sopenharmony_ci
26898c2ecf20Sopenharmony_ci	return 0;
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_cierr_ports_create:
26928c2ecf20Sopenharmony_ci	mlxsw_sp_port_module_info_fini(mlxsw_sp);
26938c2ecf20Sopenharmony_cierr_port_module_info_init:
26948c2ecf20Sopenharmony_ci	mlxsw_sp_dpipe_fini(mlxsw_sp);
26958c2ecf20Sopenharmony_cierr_dpipe_init:
26968c2ecf20Sopenharmony_ci	unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
26978c2ecf20Sopenharmony_ci					  &mlxsw_sp->netdevice_nb);
26988c2ecf20Sopenharmony_cierr_netdev_notifier:
26998c2ecf20Sopenharmony_ci	if (mlxsw_sp->clock)
27008c2ecf20Sopenharmony_ci		mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state);
27018c2ecf20Sopenharmony_cierr_ptp_init:
27028c2ecf20Sopenharmony_ci	if (mlxsw_sp->clock)
27038c2ecf20Sopenharmony_ci		mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock);
27048c2ecf20Sopenharmony_cierr_ptp_clock_init:
27058c2ecf20Sopenharmony_ci	mlxsw_sp_router_fini(mlxsw_sp);
27068c2ecf20Sopenharmony_cierr_router_init:
27078c2ecf20Sopenharmony_ci	mlxsw_sp_acl_fini(mlxsw_sp);
27088c2ecf20Sopenharmony_cierr_acl_init:
27098c2ecf20Sopenharmony_ci	mlxsw_sp_nve_fini(mlxsw_sp);
27108c2ecf20Sopenharmony_cierr_nve_init:
27118c2ecf20Sopenharmony_ci	mlxsw_sp_afa_fini(mlxsw_sp);
27128c2ecf20Sopenharmony_cierr_afa_init:
27138c2ecf20Sopenharmony_ci	mlxsw_sp_counter_pool_fini(mlxsw_sp);
27148c2ecf20Sopenharmony_cierr_counter_pool_init:
27158c2ecf20Sopenharmony_ci	mlxsw_sp_switchdev_fini(mlxsw_sp);
27168c2ecf20Sopenharmony_cierr_switchdev_init:
27178c2ecf20Sopenharmony_ci	mlxsw_sp_span_fini(mlxsw_sp);
27188c2ecf20Sopenharmony_cierr_span_init:
27198c2ecf20Sopenharmony_ci	mlxsw_sp_lag_fini(mlxsw_sp);
27208c2ecf20Sopenharmony_cierr_lag_init:
27218c2ecf20Sopenharmony_ci	mlxsw_sp_buffers_fini(mlxsw_sp);
27228c2ecf20Sopenharmony_cierr_buffers_init:
27238c2ecf20Sopenharmony_ci	mlxsw_sp_devlink_traps_fini(mlxsw_sp);
27248c2ecf20Sopenharmony_cierr_devlink_traps_init:
27258c2ecf20Sopenharmony_ci	mlxsw_sp_traps_fini(mlxsw_sp);
27268c2ecf20Sopenharmony_cierr_traps_init:
27278c2ecf20Sopenharmony_ci	mlxsw_sp_policers_fini(mlxsw_sp);
27288c2ecf20Sopenharmony_cierr_policers_init:
27298c2ecf20Sopenharmony_ci	mlxsw_sp_fids_fini(mlxsw_sp);
27308c2ecf20Sopenharmony_cierr_fids_init:
27318c2ecf20Sopenharmony_ci	mlxsw_sp_kvdl_fini(mlxsw_sp);
27328c2ecf20Sopenharmony_ci	return err;
27338c2ecf20Sopenharmony_ci}
27348c2ecf20Sopenharmony_ci
27358c2ecf20Sopenharmony_cistatic int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core,
27368c2ecf20Sopenharmony_ci			  const struct mlxsw_bus_info *mlxsw_bus_info,
27378c2ecf20Sopenharmony_ci			  struct netlink_ext_ack *extack)
27388c2ecf20Sopenharmony_ci{
27398c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
27408c2ecf20Sopenharmony_ci
27418c2ecf20Sopenharmony_ci	mlxsw_sp->kvdl_ops = &mlxsw_sp1_kvdl_ops;
27428c2ecf20Sopenharmony_ci	mlxsw_sp->afa_ops = &mlxsw_sp1_act_afa_ops;
27438c2ecf20Sopenharmony_ci	mlxsw_sp->afk_ops = &mlxsw_sp1_afk_ops;
27448c2ecf20Sopenharmony_ci	mlxsw_sp->mr_tcam_ops = &mlxsw_sp1_mr_tcam_ops;
27458c2ecf20Sopenharmony_ci	mlxsw_sp->acl_rulei_ops = &mlxsw_sp1_acl_rulei_ops;
27468c2ecf20Sopenharmony_ci	mlxsw_sp->acl_tcam_ops = &mlxsw_sp1_acl_tcam_ops;
27478c2ecf20Sopenharmony_ci	mlxsw_sp->nve_ops_arr = mlxsw_sp1_nve_ops_arr;
27488c2ecf20Sopenharmony_ci	mlxsw_sp->mac_mask = mlxsw_sp1_mac_mask;
27498c2ecf20Sopenharmony_ci	mlxsw_sp->rif_ops_arr = mlxsw_sp1_rif_ops_arr;
27508c2ecf20Sopenharmony_ci	mlxsw_sp->sb_vals = &mlxsw_sp1_sb_vals;
27518c2ecf20Sopenharmony_ci	mlxsw_sp->sb_ops = &mlxsw_sp1_sb_ops;
27528c2ecf20Sopenharmony_ci	mlxsw_sp->port_type_speed_ops = &mlxsw_sp1_port_type_speed_ops;
27538c2ecf20Sopenharmony_ci	mlxsw_sp->ptp_ops = &mlxsw_sp1_ptp_ops;
27548c2ecf20Sopenharmony_ci	mlxsw_sp->span_ops = &mlxsw_sp1_span_ops;
27558c2ecf20Sopenharmony_ci	mlxsw_sp->policer_core_ops = &mlxsw_sp1_policer_core_ops;
27568c2ecf20Sopenharmony_ci	mlxsw_sp->trap_ops = &mlxsw_sp1_trap_ops;
27578c2ecf20Sopenharmony_ci	mlxsw_sp->listeners = mlxsw_sp1_listener;
27588c2ecf20Sopenharmony_ci	mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener);
27598c2ecf20Sopenharmony_ci	mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP1;
27608c2ecf20Sopenharmony_ci
27618c2ecf20Sopenharmony_ci	return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
27628c2ecf20Sopenharmony_ci}
27638c2ecf20Sopenharmony_ci
27648c2ecf20Sopenharmony_cistatic int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core,
27658c2ecf20Sopenharmony_ci			  const struct mlxsw_bus_info *mlxsw_bus_info,
27668c2ecf20Sopenharmony_ci			  struct netlink_ext_ack *extack)
27678c2ecf20Sopenharmony_ci{
27688c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci	mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops;
27718c2ecf20Sopenharmony_ci	mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops;
27728c2ecf20Sopenharmony_ci	mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops;
27738c2ecf20Sopenharmony_ci	mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops;
27748c2ecf20Sopenharmony_ci	mlxsw_sp->acl_rulei_ops = &mlxsw_sp2_acl_rulei_ops;
27758c2ecf20Sopenharmony_ci	mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops;
27768c2ecf20Sopenharmony_ci	mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr;
27778c2ecf20Sopenharmony_ci	mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask;
27788c2ecf20Sopenharmony_ci	mlxsw_sp->rif_ops_arr = mlxsw_sp2_rif_ops_arr;
27798c2ecf20Sopenharmony_ci	mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;
27808c2ecf20Sopenharmony_ci	mlxsw_sp->sb_ops = &mlxsw_sp2_sb_ops;
27818c2ecf20Sopenharmony_ci	mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;
27828c2ecf20Sopenharmony_ci	mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops;
27838c2ecf20Sopenharmony_ci	mlxsw_sp->span_ops = &mlxsw_sp2_span_ops;
27848c2ecf20Sopenharmony_ci	mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops;
27858c2ecf20Sopenharmony_ci	mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops;
27868c2ecf20Sopenharmony_ci	mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP2;
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_ci	return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
27898c2ecf20Sopenharmony_ci}
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_cistatic int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core,
27928c2ecf20Sopenharmony_ci			  const struct mlxsw_bus_info *mlxsw_bus_info,
27938c2ecf20Sopenharmony_ci			  struct netlink_ext_ack *extack)
27948c2ecf20Sopenharmony_ci{
27958c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci	mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops;
27988c2ecf20Sopenharmony_ci	mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops;
27998c2ecf20Sopenharmony_ci	mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops;
28008c2ecf20Sopenharmony_ci	mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops;
28018c2ecf20Sopenharmony_ci	mlxsw_sp->acl_rulei_ops = &mlxsw_sp2_acl_rulei_ops;
28028c2ecf20Sopenharmony_ci	mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops;
28038c2ecf20Sopenharmony_ci	mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr;
28048c2ecf20Sopenharmony_ci	mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask;
28058c2ecf20Sopenharmony_ci	mlxsw_sp->rif_ops_arr = mlxsw_sp2_rif_ops_arr;
28068c2ecf20Sopenharmony_ci	mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;
28078c2ecf20Sopenharmony_ci	mlxsw_sp->sb_ops = &mlxsw_sp3_sb_ops;
28088c2ecf20Sopenharmony_ci	mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;
28098c2ecf20Sopenharmony_ci	mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops;
28108c2ecf20Sopenharmony_ci	mlxsw_sp->span_ops = &mlxsw_sp3_span_ops;
28118c2ecf20Sopenharmony_ci	mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops;
28128c2ecf20Sopenharmony_ci	mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops;
28138c2ecf20Sopenharmony_ci	mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3;
28148c2ecf20Sopenharmony_ci
28158c2ecf20Sopenharmony_ci	return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
28168c2ecf20Sopenharmony_ci}
28178c2ecf20Sopenharmony_ci
28188c2ecf20Sopenharmony_cistatic void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
28198c2ecf20Sopenharmony_ci{
28208c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
28218c2ecf20Sopenharmony_ci
28228c2ecf20Sopenharmony_ci	mlxsw_sp_ports_remove(mlxsw_sp);
28238c2ecf20Sopenharmony_ci	mlxsw_sp_port_module_info_fini(mlxsw_sp);
28248c2ecf20Sopenharmony_ci	mlxsw_sp_dpipe_fini(mlxsw_sp);
28258c2ecf20Sopenharmony_ci	unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
28268c2ecf20Sopenharmony_ci					  &mlxsw_sp->netdevice_nb);
28278c2ecf20Sopenharmony_ci	if (mlxsw_sp->clock) {
28288c2ecf20Sopenharmony_ci		mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state);
28298c2ecf20Sopenharmony_ci		mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock);
28308c2ecf20Sopenharmony_ci	}
28318c2ecf20Sopenharmony_ci	mlxsw_sp_router_fini(mlxsw_sp);
28328c2ecf20Sopenharmony_ci	mlxsw_sp_acl_fini(mlxsw_sp);
28338c2ecf20Sopenharmony_ci	mlxsw_sp_nve_fini(mlxsw_sp);
28348c2ecf20Sopenharmony_ci	mlxsw_sp_afa_fini(mlxsw_sp);
28358c2ecf20Sopenharmony_ci	mlxsw_sp_counter_pool_fini(mlxsw_sp);
28368c2ecf20Sopenharmony_ci	mlxsw_sp_switchdev_fini(mlxsw_sp);
28378c2ecf20Sopenharmony_ci	mlxsw_sp_span_fini(mlxsw_sp);
28388c2ecf20Sopenharmony_ci	mlxsw_sp_lag_fini(mlxsw_sp);
28398c2ecf20Sopenharmony_ci	mlxsw_sp_buffers_fini(mlxsw_sp);
28408c2ecf20Sopenharmony_ci	mlxsw_sp_devlink_traps_fini(mlxsw_sp);
28418c2ecf20Sopenharmony_ci	mlxsw_sp_traps_fini(mlxsw_sp);
28428c2ecf20Sopenharmony_ci	mlxsw_sp_policers_fini(mlxsw_sp);
28438c2ecf20Sopenharmony_ci	mlxsw_sp_fids_fini(mlxsw_sp);
28448c2ecf20Sopenharmony_ci	mlxsw_sp_kvdl_fini(mlxsw_sp);
28458c2ecf20Sopenharmony_ci}
28468c2ecf20Sopenharmony_ci
28478c2ecf20Sopenharmony_ci/* Per-FID flood tables are used for both "true" 802.1D FIDs and emulated
28488c2ecf20Sopenharmony_ci * 802.1Q FIDs
28498c2ecf20Sopenharmony_ci */
28508c2ecf20Sopenharmony_ci#define MLXSW_SP_FID_FLOOD_TABLE_SIZE	(MLXSW_SP_FID_8021D_MAX + \
28518c2ecf20Sopenharmony_ci					 VLAN_VID_MASK - 1)
28528c2ecf20Sopenharmony_ci
28538c2ecf20Sopenharmony_cistatic const struct mlxsw_config_profile mlxsw_sp1_config_profile = {
28548c2ecf20Sopenharmony_ci	.used_max_mid			= 1,
28558c2ecf20Sopenharmony_ci	.max_mid			= MLXSW_SP_MID_MAX,
28568c2ecf20Sopenharmony_ci	.used_flood_tables		= 1,
28578c2ecf20Sopenharmony_ci	.used_flood_mode		= 1,
28588c2ecf20Sopenharmony_ci	.flood_mode			= 3,
28598c2ecf20Sopenharmony_ci	.max_fid_flood_tables		= 3,
28608c2ecf20Sopenharmony_ci	.fid_flood_table_size		= MLXSW_SP_FID_FLOOD_TABLE_SIZE,
28618c2ecf20Sopenharmony_ci	.used_max_ib_mc			= 1,
28628c2ecf20Sopenharmony_ci	.max_ib_mc			= 0,
28638c2ecf20Sopenharmony_ci	.used_max_pkey			= 1,
28648c2ecf20Sopenharmony_ci	.max_pkey			= 0,
28658c2ecf20Sopenharmony_ci	.used_kvd_sizes			= 1,
28668c2ecf20Sopenharmony_ci	.kvd_hash_single_parts		= 59,
28678c2ecf20Sopenharmony_ci	.kvd_hash_double_parts		= 41,
28688c2ecf20Sopenharmony_ci	.kvd_linear_size		= MLXSW_SP_KVD_LINEAR_SIZE,
28698c2ecf20Sopenharmony_ci	.swid_config			= {
28708c2ecf20Sopenharmony_ci		{
28718c2ecf20Sopenharmony_ci			.used_type	= 1,
28728c2ecf20Sopenharmony_ci			.type		= MLXSW_PORT_SWID_TYPE_ETH,
28738c2ecf20Sopenharmony_ci		}
28748c2ecf20Sopenharmony_ci	},
28758c2ecf20Sopenharmony_ci};
28768c2ecf20Sopenharmony_ci
28778c2ecf20Sopenharmony_cistatic const struct mlxsw_config_profile mlxsw_sp2_config_profile = {
28788c2ecf20Sopenharmony_ci	.used_max_mid			= 1,
28798c2ecf20Sopenharmony_ci	.max_mid			= MLXSW_SP_MID_MAX,
28808c2ecf20Sopenharmony_ci	.used_flood_tables		= 1,
28818c2ecf20Sopenharmony_ci	.used_flood_mode		= 1,
28828c2ecf20Sopenharmony_ci	.flood_mode			= 3,
28838c2ecf20Sopenharmony_ci	.max_fid_flood_tables		= 3,
28848c2ecf20Sopenharmony_ci	.fid_flood_table_size		= MLXSW_SP_FID_FLOOD_TABLE_SIZE,
28858c2ecf20Sopenharmony_ci	.used_max_ib_mc			= 1,
28868c2ecf20Sopenharmony_ci	.max_ib_mc			= 0,
28878c2ecf20Sopenharmony_ci	.used_max_pkey			= 1,
28888c2ecf20Sopenharmony_ci	.max_pkey			= 0,
28898c2ecf20Sopenharmony_ci	.swid_config			= {
28908c2ecf20Sopenharmony_ci		{
28918c2ecf20Sopenharmony_ci			.used_type	= 1,
28928c2ecf20Sopenharmony_ci			.type		= MLXSW_PORT_SWID_TYPE_ETH,
28938c2ecf20Sopenharmony_ci		}
28948c2ecf20Sopenharmony_ci	},
28958c2ecf20Sopenharmony_ci};
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_cistatic void
28988c2ecf20Sopenharmony_cimlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core,
28998c2ecf20Sopenharmony_ci				      struct devlink_resource_size_params *kvd_size_params,
29008c2ecf20Sopenharmony_ci				      struct devlink_resource_size_params *linear_size_params,
29018c2ecf20Sopenharmony_ci				      struct devlink_resource_size_params *hash_double_size_params,
29028c2ecf20Sopenharmony_ci				      struct devlink_resource_size_params *hash_single_size_params)
29038c2ecf20Sopenharmony_ci{
29048c2ecf20Sopenharmony_ci	u32 single_size_min = MLXSW_CORE_RES_GET(mlxsw_core,
29058c2ecf20Sopenharmony_ci						 KVD_SINGLE_MIN_SIZE);
29068c2ecf20Sopenharmony_ci	u32 double_size_min = MLXSW_CORE_RES_GET(mlxsw_core,
29078c2ecf20Sopenharmony_ci						 KVD_DOUBLE_MIN_SIZE);
29088c2ecf20Sopenharmony_ci	u32 kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE);
29098c2ecf20Sopenharmony_ci	u32 linear_size_min = 0;
29108c2ecf20Sopenharmony_ci
29118c2ecf20Sopenharmony_ci	devlink_resource_size_params_init(kvd_size_params, kvd_size, kvd_size,
29128c2ecf20Sopenharmony_ci					  MLXSW_SP_KVD_GRANULARITY,
29138c2ecf20Sopenharmony_ci					  DEVLINK_RESOURCE_UNIT_ENTRY);
29148c2ecf20Sopenharmony_ci	devlink_resource_size_params_init(linear_size_params, linear_size_min,
29158c2ecf20Sopenharmony_ci					  kvd_size - single_size_min -
29168c2ecf20Sopenharmony_ci					  double_size_min,
29178c2ecf20Sopenharmony_ci					  MLXSW_SP_KVD_GRANULARITY,
29188c2ecf20Sopenharmony_ci					  DEVLINK_RESOURCE_UNIT_ENTRY);
29198c2ecf20Sopenharmony_ci	devlink_resource_size_params_init(hash_double_size_params,
29208c2ecf20Sopenharmony_ci					  double_size_min,
29218c2ecf20Sopenharmony_ci					  kvd_size - single_size_min -
29228c2ecf20Sopenharmony_ci					  linear_size_min,
29238c2ecf20Sopenharmony_ci					  MLXSW_SP_KVD_GRANULARITY,
29248c2ecf20Sopenharmony_ci					  DEVLINK_RESOURCE_UNIT_ENTRY);
29258c2ecf20Sopenharmony_ci	devlink_resource_size_params_init(hash_single_size_params,
29268c2ecf20Sopenharmony_ci					  single_size_min,
29278c2ecf20Sopenharmony_ci					  kvd_size - double_size_min -
29288c2ecf20Sopenharmony_ci					  linear_size_min,
29298c2ecf20Sopenharmony_ci					  MLXSW_SP_KVD_GRANULARITY,
29308c2ecf20Sopenharmony_ci					  DEVLINK_RESOURCE_UNIT_ENTRY);
29318c2ecf20Sopenharmony_ci}
29328c2ecf20Sopenharmony_ci
29338c2ecf20Sopenharmony_cistatic int mlxsw_sp1_resources_kvd_register(struct mlxsw_core *mlxsw_core)
29348c2ecf20Sopenharmony_ci{
29358c2ecf20Sopenharmony_ci	struct devlink *devlink = priv_to_devlink(mlxsw_core);
29368c2ecf20Sopenharmony_ci	struct devlink_resource_size_params hash_single_size_params;
29378c2ecf20Sopenharmony_ci	struct devlink_resource_size_params hash_double_size_params;
29388c2ecf20Sopenharmony_ci	struct devlink_resource_size_params linear_size_params;
29398c2ecf20Sopenharmony_ci	struct devlink_resource_size_params kvd_size_params;
29408c2ecf20Sopenharmony_ci	u32 kvd_size, single_size, double_size, linear_size;
29418c2ecf20Sopenharmony_ci	const struct mlxsw_config_profile *profile;
29428c2ecf20Sopenharmony_ci	int err;
29438c2ecf20Sopenharmony_ci
29448c2ecf20Sopenharmony_ci	profile = &mlxsw_sp1_config_profile;
29458c2ecf20Sopenharmony_ci	if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE))
29468c2ecf20Sopenharmony_ci		return -EIO;
29478c2ecf20Sopenharmony_ci
29488c2ecf20Sopenharmony_ci	mlxsw_sp_resource_size_params_prepare(mlxsw_core, &kvd_size_params,
29498c2ecf20Sopenharmony_ci					      &linear_size_params,
29508c2ecf20Sopenharmony_ci					      &hash_double_size_params,
29518c2ecf20Sopenharmony_ci					      &hash_single_size_params);
29528c2ecf20Sopenharmony_ci
29538c2ecf20Sopenharmony_ci	kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE);
29548c2ecf20Sopenharmony_ci	err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD,
29558c2ecf20Sopenharmony_ci					kvd_size, MLXSW_SP_RESOURCE_KVD,
29568c2ecf20Sopenharmony_ci					DEVLINK_RESOURCE_ID_PARENT_TOP,
29578c2ecf20Sopenharmony_ci					&kvd_size_params);
29588c2ecf20Sopenharmony_ci	if (err)
29598c2ecf20Sopenharmony_ci		return err;
29608c2ecf20Sopenharmony_ci
29618c2ecf20Sopenharmony_ci	linear_size = profile->kvd_linear_size;
29628c2ecf20Sopenharmony_ci	err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR,
29638c2ecf20Sopenharmony_ci					linear_size,
29648c2ecf20Sopenharmony_ci					MLXSW_SP_RESOURCE_KVD_LINEAR,
29658c2ecf20Sopenharmony_ci					MLXSW_SP_RESOURCE_KVD,
29668c2ecf20Sopenharmony_ci					&linear_size_params);
29678c2ecf20Sopenharmony_ci	if (err)
29688c2ecf20Sopenharmony_ci		return err;
29698c2ecf20Sopenharmony_ci
29708c2ecf20Sopenharmony_ci	err = mlxsw_sp1_kvdl_resources_register(mlxsw_core);
29718c2ecf20Sopenharmony_ci	if  (err)
29728c2ecf20Sopenharmony_ci		return err;
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_ci	double_size = kvd_size - linear_size;
29758c2ecf20Sopenharmony_ci	double_size *= profile->kvd_hash_double_parts;
29768c2ecf20Sopenharmony_ci	double_size /= profile->kvd_hash_double_parts +
29778c2ecf20Sopenharmony_ci		       profile->kvd_hash_single_parts;
29788c2ecf20Sopenharmony_ci	double_size = rounddown(double_size, MLXSW_SP_KVD_GRANULARITY);
29798c2ecf20Sopenharmony_ci	err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_HASH_DOUBLE,
29808c2ecf20Sopenharmony_ci					double_size,
29818c2ecf20Sopenharmony_ci					MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
29828c2ecf20Sopenharmony_ci					MLXSW_SP_RESOURCE_KVD,
29838c2ecf20Sopenharmony_ci					&hash_double_size_params);
29848c2ecf20Sopenharmony_ci	if (err)
29858c2ecf20Sopenharmony_ci		return err;
29868c2ecf20Sopenharmony_ci
29878c2ecf20Sopenharmony_ci	single_size = kvd_size - double_size - linear_size;
29888c2ecf20Sopenharmony_ci	err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_HASH_SINGLE,
29898c2ecf20Sopenharmony_ci					single_size,
29908c2ecf20Sopenharmony_ci					MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
29918c2ecf20Sopenharmony_ci					MLXSW_SP_RESOURCE_KVD,
29928c2ecf20Sopenharmony_ci					&hash_single_size_params);
29938c2ecf20Sopenharmony_ci	if (err)
29948c2ecf20Sopenharmony_ci		return err;
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_ci	return 0;
29978c2ecf20Sopenharmony_ci}
29988c2ecf20Sopenharmony_ci
29998c2ecf20Sopenharmony_cistatic int mlxsw_sp2_resources_kvd_register(struct mlxsw_core *mlxsw_core)
30008c2ecf20Sopenharmony_ci{
30018c2ecf20Sopenharmony_ci	struct devlink *devlink = priv_to_devlink(mlxsw_core);
30028c2ecf20Sopenharmony_ci	struct devlink_resource_size_params kvd_size_params;
30038c2ecf20Sopenharmony_ci	u32 kvd_size;
30048c2ecf20Sopenharmony_ci
30058c2ecf20Sopenharmony_ci	if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE))
30068c2ecf20Sopenharmony_ci		return -EIO;
30078c2ecf20Sopenharmony_ci
30088c2ecf20Sopenharmony_ci	kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE);
30098c2ecf20Sopenharmony_ci	devlink_resource_size_params_init(&kvd_size_params, kvd_size, kvd_size,
30108c2ecf20Sopenharmony_ci					  MLXSW_SP_KVD_GRANULARITY,
30118c2ecf20Sopenharmony_ci					  DEVLINK_RESOURCE_UNIT_ENTRY);
30128c2ecf20Sopenharmony_ci
30138c2ecf20Sopenharmony_ci	return devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD,
30148c2ecf20Sopenharmony_ci					 kvd_size, MLXSW_SP_RESOURCE_KVD,
30158c2ecf20Sopenharmony_ci					 DEVLINK_RESOURCE_ID_PARENT_TOP,
30168c2ecf20Sopenharmony_ci					 &kvd_size_params);
30178c2ecf20Sopenharmony_ci}
30188c2ecf20Sopenharmony_ci
30198c2ecf20Sopenharmony_cistatic int mlxsw_sp_resources_span_register(struct mlxsw_core *mlxsw_core)
30208c2ecf20Sopenharmony_ci{
30218c2ecf20Sopenharmony_ci	struct devlink *devlink = priv_to_devlink(mlxsw_core);
30228c2ecf20Sopenharmony_ci	struct devlink_resource_size_params span_size_params;
30238c2ecf20Sopenharmony_ci	u32 max_span;
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SPAN))
30268c2ecf20Sopenharmony_ci		return -EIO;
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci	max_span = MLXSW_CORE_RES_GET(mlxsw_core, MAX_SPAN);
30298c2ecf20Sopenharmony_ci	devlink_resource_size_params_init(&span_size_params, max_span, max_span,
30308c2ecf20Sopenharmony_ci					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_ci	return devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_SPAN,
30338c2ecf20Sopenharmony_ci					 max_span, MLXSW_SP_RESOURCE_SPAN,
30348c2ecf20Sopenharmony_ci					 DEVLINK_RESOURCE_ID_PARENT_TOP,
30358c2ecf20Sopenharmony_ci					 &span_size_params);
30368c2ecf20Sopenharmony_ci}
30378c2ecf20Sopenharmony_ci
30388c2ecf20Sopenharmony_cistatic int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core)
30398c2ecf20Sopenharmony_ci{
30408c2ecf20Sopenharmony_ci	int err;
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci	err = mlxsw_sp1_resources_kvd_register(mlxsw_core);
30438c2ecf20Sopenharmony_ci	if (err)
30448c2ecf20Sopenharmony_ci		return err;
30458c2ecf20Sopenharmony_ci
30468c2ecf20Sopenharmony_ci	err = mlxsw_sp_resources_span_register(mlxsw_core);
30478c2ecf20Sopenharmony_ci	if (err)
30488c2ecf20Sopenharmony_ci		goto err_resources_span_register;
30498c2ecf20Sopenharmony_ci
30508c2ecf20Sopenharmony_ci	err = mlxsw_sp_counter_resources_register(mlxsw_core);
30518c2ecf20Sopenharmony_ci	if (err)
30528c2ecf20Sopenharmony_ci		goto err_resources_counter_register;
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_ci	err = mlxsw_sp_policer_resources_register(mlxsw_core);
30558c2ecf20Sopenharmony_ci	if (err)
30568c2ecf20Sopenharmony_ci		goto err_resources_counter_register;
30578c2ecf20Sopenharmony_ci
30588c2ecf20Sopenharmony_ci	return 0;
30598c2ecf20Sopenharmony_ci
30608c2ecf20Sopenharmony_cierr_resources_counter_register:
30618c2ecf20Sopenharmony_cierr_resources_span_register:
30628c2ecf20Sopenharmony_ci	devlink_resources_unregister(priv_to_devlink(mlxsw_core), NULL);
30638c2ecf20Sopenharmony_ci	return err;
30648c2ecf20Sopenharmony_ci}
30658c2ecf20Sopenharmony_ci
30668c2ecf20Sopenharmony_cistatic int mlxsw_sp2_resources_register(struct mlxsw_core *mlxsw_core)
30678c2ecf20Sopenharmony_ci{
30688c2ecf20Sopenharmony_ci	int err;
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ci	err = mlxsw_sp2_resources_kvd_register(mlxsw_core);
30718c2ecf20Sopenharmony_ci	if (err)
30728c2ecf20Sopenharmony_ci		return err;
30738c2ecf20Sopenharmony_ci
30748c2ecf20Sopenharmony_ci	err = mlxsw_sp_resources_span_register(mlxsw_core);
30758c2ecf20Sopenharmony_ci	if (err)
30768c2ecf20Sopenharmony_ci		goto err_resources_span_register;
30778c2ecf20Sopenharmony_ci
30788c2ecf20Sopenharmony_ci	err = mlxsw_sp_counter_resources_register(mlxsw_core);
30798c2ecf20Sopenharmony_ci	if (err)
30808c2ecf20Sopenharmony_ci		goto err_resources_counter_register;
30818c2ecf20Sopenharmony_ci
30828c2ecf20Sopenharmony_ci	err = mlxsw_sp_policer_resources_register(mlxsw_core);
30838c2ecf20Sopenharmony_ci	if (err)
30848c2ecf20Sopenharmony_ci		goto err_resources_counter_register;
30858c2ecf20Sopenharmony_ci
30868c2ecf20Sopenharmony_ci	return 0;
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_cierr_resources_counter_register:
30898c2ecf20Sopenharmony_cierr_resources_span_register:
30908c2ecf20Sopenharmony_ci	devlink_resources_unregister(priv_to_devlink(mlxsw_core), NULL);
30918c2ecf20Sopenharmony_ci	return err;
30928c2ecf20Sopenharmony_ci}
30938c2ecf20Sopenharmony_ci
30948c2ecf20Sopenharmony_cistatic int mlxsw_sp_kvd_sizes_get(struct mlxsw_core *mlxsw_core,
30958c2ecf20Sopenharmony_ci				  const struct mlxsw_config_profile *profile,
30968c2ecf20Sopenharmony_ci				  u64 *p_single_size, u64 *p_double_size,
30978c2ecf20Sopenharmony_ci				  u64 *p_linear_size)
30988c2ecf20Sopenharmony_ci{
30998c2ecf20Sopenharmony_ci	struct devlink *devlink = priv_to_devlink(mlxsw_core);
31008c2ecf20Sopenharmony_ci	u32 double_size;
31018c2ecf20Sopenharmony_ci	int err;
31028c2ecf20Sopenharmony_ci
31038c2ecf20Sopenharmony_ci	if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SINGLE_MIN_SIZE) ||
31048c2ecf20Sopenharmony_ci	    !MLXSW_CORE_RES_VALID(mlxsw_core, KVD_DOUBLE_MIN_SIZE))
31058c2ecf20Sopenharmony_ci		return -EIO;
31068c2ecf20Sopenharmony_ci
31078c2ecf20Sopenharmony_ci	/* The hash part is what left of the kvd without the
31088c2ecf20Sopenharmony_ci	 * linear part. It is split to the single size and
31098c2ecf20Sopenharmony_ci	 * double size by the parts ratio from the profile.
31108c2ecf20Sopenharmony_ci	 * Both sizes must be a multiplications of the
31118c2ecf20Sopenharmony_ci	 * granularity from the profile. In case the user
31128c2ecf20Sopenharmony_ci	 * provided the sizes they are obtained via devlink.
31138c2ecf20Sopenharmony_ci	 */
31148c2ecf20Sopenharmony_ci	err = devlink_resource_size_get(devlink,
31158c2ecf20Sopenharmony_ci					MLXSW_SP_RESOURCE_KVD_LINEAR,
31168c2ecf20Sopenharmony_ci					p_linear_size);
31178c2ecf20Sopenharmony_ci	if (err)
31188c2ecf20Sopenharmony_ci		*p_linear_size = profile->kvd_linear_size;
31198c2ecf20Sopenharmony_ci
31208c2ecf20Sopenharmony_ci	err = devlink_resource_size_get(devlink,
31218c2ecf20Sopenharmony_ci					MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
31228c2ecf20Sopenharmony_ci					p_double_size);
31238c2ecf20Sopenharmony_ci	if (err) {
31248c2ecf20Sopenharmony_ci		double_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) -
31258c2ecf20Sopenharmony_ci			      *p_linear_size;
31268c2ecf20Sopenharmony_ci		double_size *= profile->kvd_hash_double_parts;
31278c2ecf20Sopenharmony_ci		double_size /= profile->kvd_hash_double_parts +
31288c2ecf20Sopenharmony_ci			       profile->kvd_hash_single_parts;
31298c2ecf20Sopenharmony_ci		*p_double_size = rounddown(double_size,
31308c2ecf20Sopenharmony_ci					   MLXSW_SP_KVD_GRANULARITY);
31318c2ecf20Sopenharmony_ci	}
31328c2ecf20Sopenharmony_ci
31338c2ecf20Sopenharmony_ci	err = devlink_resource_size_get(devlink,
31348c2ecf20Sopenharmony_ci					MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
31358c2ecf20Sopenharmony_ci					p_single_size);
31368c2ecf20Sopenharmony_ci	if (err)
31378c2ecf20Sopenharmony_ci		*p_single_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) -
31388c2ecf20Sopenharmony_ci				 *p_double_size - *p_linear_size;
31398c2ecf20Sopenharmony_ci
31408c2ecf20Sopenharmony_ci	/* Check results are legal. */
31418c2ecf20Sopenharmony_ci	if (*p_single_size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE) ||
31428c2ecf20Sopenharmony_ci	    *p_double_size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_DOUBLE_MIN_SIZE) ||
31438c2ecf20Sopenharmony_ci	    MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) < *p_linear_size)
31448c2ecf20Sopenharmony_ci		return -EIO;
31458c2ecf20Sopenharmony_ci
31468c2ecf20Sopenharmony_ci	return 0;
31478c2ecf20Sopenharmony_ci}
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_cistatic int
31508c2ecf20Sopenharmony_cimlxsw_sp_params_acl_region_rehash_intrvl_get(struct devlink *devlink, u32 id,
31518c2ecf20Sopenharmony_ci					     struct devlink_param_gset_ctx *ctx)
31528c2ecf20Sopenharmony_ci{
31538c2ecf20Sopenharmony_ci	struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
31548c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
31558c2ecf20Sopenharmony_ci
31568c2ecf20Sopenharmony_ci	ctx->val.vu32 = mlxsw_sp_acl_region_rehash_intrvl_get(mlxsw_sp);
31578c2ecf20Sopenharmony_ci	return 0;
31588c2ecf20Sopenharmony_ci}
31598c2ecf20Sopenharmony_ci
31608c2ecf20Sopenharmony_cistatic int
31618c2ecf20Sopenharmony_cimlxsw_sp_params_acl_region_rehash_intrvl_set(struct devlink *devlink, u32 id,
31628c2ecf20Sopenharmony_ci					     struct devlink_param_gset_ctx *ctx)
31638c2ecf20Sopenharmony_ci{
31648c2ecf20Sopenharmony_ci	struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
31658c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
31668c2ecf20Sopenharmony_ci
31678c2ecf20Sopenharmony_ci	return mlxsw_sp_acl_region_rehash_intrvl_set(mlxsw_sp, ctx->val.vu32);
31688c2ecf20Sopenharmony_ci}
31698c2ecf20Sopenharmony_ci
31708c2ecf20Sopenharmony_cistatic const struct devlink_param mlxsw_sp2_devlink_params[] = {
31718c2ecf20Sopenharmony_ci	DEVLINK_PARAM_DRIVER(MLXSW_DEVLINK_PARAM_ID_ACL_REGION_REHASH_INTERVAL,
31728c2ecf20Sopenharmony_ci			     "acl_region_rehash_interval",
31738c2ecf20Sopenharmony_ci			     DEVLINK_PARAM_TYPE_U32,
31748c2ecf20Sopenharmony_ci			     BIT(DEVLINK_PARAM_CMODE_RUNTIME),
31758c2ecf20Sopenharmony_ci			     mlxsw_sp_params_acl_region_rehash_intrvl_get,
31768c2ecf20Sopenharmony_ci			     mlxsw_sp_params_acl_region_rehash_intrvl_set,
31778c2ecf20Sopenharmony_ci			     NULL),
31788c2ecf20Sopenharmony_ci};
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_cistatic int mlxsw_sp2_params_register(struct mlxsw_core *mlxsw_core)
31818c2ecf20Sopenharmony_ci{
31828c2ecf20Sopenharmony_ci	struct devlink *devlink = priv_to_devlink(mlxsw_core);
31838c2ecf20Sopenharmony_ci	union devlink_param_value value;
31848c2ecf20Sopenharmony_ci	int err;
31858c2ecf20Sopenharmony_ci
31868c2ecf20Sopenharmony_ci	err = devlink_params_register(devlink, mlxsw_sp2_devlink_params,
31878c2ecf20Sopenharmony_ci				      ARRAY_SIZE(mlxsw_sp2_devlink_params));
31888c2ecf20Sopenharmony_ci	if (err)
31898c2ecf20Sopenharmony_ci		return err;
31908c2ecf20Sopenharmony_ci
31918c2ecf20Sopenharmony_ci	value.vu32 = 0;
31928c2ecf20Sopenharmony_ci	devlink_param_driverinit_value_set(devlink,
31938c2ecf20Sopenharmony_ci					   MLXSW_DEVLINK_PARAM_ID_ACL_REGION_REHASH_INTERVAL,
31948c2ecf20Sopenharmony_ci					   value);
31958c2ecf20Sopenharmony_ci	return 0;
31968c2ecf20Sopenharmony_ci}
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_cistatic void mlxsw_sp2_params_unregister(struct mlxsw_core *mlxsw_core)
31998c2ecf20Sopenharmony_ci{
32008c2ecf20Sopenharmony_ci	devlink_params_unregister(priv_to_devlink(mlxsw_core),
32018c2ecf20Sopenharmony_ci				  mlxsw_sp2_devlink_params,
32028c2ecf20Sopenharmony_ci				  ARRAY_SIZE(mlxsw_sp2_devlink_params));
32038c2ecf20Sopenharmony_ci}
32048c2ecf20Sopenharmony_ci
32058c2ecf20Sopenharmony_cistatic void mlxsw_sp_ptp_transmitted(struct mlxsw_core *mlxsw_core,
32068c2ecf20Sopenharmony_ci				     struct sk_buff *skb, u8 local_port)
32078c2ecf20Sopenharmony_ci{
32088c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);
32098c2ecf20Sopenharmony_ci
32108c2ecf20Sopenharmony_ci	skb_pull(skb, MLXSW_TXHDR_LEN);
32118c2ecf20Sopenharmony_ci	mlxsw_sp->ptp_ops->transmitted(mlxsw_sp, skb, local_port);
32128c2ecf20Sopenharmony_ci}
32138c2ecf20Sopenharmony_ci
32148c2ecf20Sopenharmony_cistatic struct mlxsw_driver mlxsw_sp1_driver = {
32158c2ecf20Sopenharmony_ci	.kind				= mlxsw_sp1_driver_name,
32168c2ecf20Sopenharmony_ci	.priv_size			= sizeof(struct mlxsw_sp),
32178c2ecf20Sopenharmony_ci	.fw_req_rev			= &mlxsw_sp1_fw_rev,
32188c2ecf20Sopenharmony_ci	.fw_filename			= MLXSW_SP1_FW_FILENAME,
32198c2ecf20Sopenharmony_ci	.init				= mlxsw_sp1_init,
32208c2ecf20Sopenharmony_ci	.fini				= mlxsw_sp_fini,
32218c2ecf20Sopenharmony_ci	.basic_trap_groups_set		= mlxsw_sp_basic_trap_groups_set,
32228c2ecf20Sopenharmony_ci	.port_split			= mlxsw_sp_port_split,
32238c2ecf20Sopenharmony_ci	.port_unsplit			= mlxsw_sp_port_unsplit,
32248c2ecf20Sopenharmony_ci	.sb_pool_get			= mlxsw_sp_sb_pool_get,
32258c2ecf20Sopenharmony_ci	.sb_pool_set			= mlxsw_sp_sb_pool_set,
32268c2ecf20Sopenharmony_ci	.sb_port_pool_get		= mlxsw_sp_sb_port_pool_get,
32278c2ecf20Sopenharmony_ci	.sb_port_pool_set		= mlxsw_sp_sb_port_pool_set,
32288c2ecf20Sopenharmony_ci	.sb_tc_pool_bind_get		= mlxsw_sp_sb_tc_pool_bind_get,
32298c2ecf20Sopenharmony_ci	.sb_tc_pool_bind_set		= mlxsw_sp_sb_tc_pool_bind_set,
32308c2ecf20Sopenharmony_ci	.sb_occ_snapshot		= mlxsw_sp_sb_occ_snapshot,
32318c2ecf20Sopenharmony_ci	.sb_occ_max_clear		= mlxsw_sp_sb_occ_max_clear,
32328c2ecf20Sopenharmony_ci	.sb_occ_port_pool_get		= mlxsw_sp_sb_occ_port_pool_get,
32338c2ecf20Sopenharmony_ci	.sb_occ_tc_port_bind_get	= mlxsw_sp_sb_occ_tc_port_bind_get,
32348c2ecf20Sopenharmony_ci	.trap_init			= mlxsw_sp_trap_init,
32358c2ecf20Sopenharmony_ci	.trap_fini			= mlxsw_sp_trap_fini,
32368c2ecf20Sopenharmony_ci	.trap_action_set		= mlxsw_sp_trap_action_set,
32378c2ecf20Sopenharmony_ci	.trap_group_init		= mlxsw_sp_trap_group_init,
32388c2ecf20Sopenharmony_ci	.trap_group_set			= mlxsw_sp_trap_group_set,
32398c2ecf20Sopenharmony_ci	.trap_policer_init		= mlxsw_sp_trap_policer_init,
32408c2ecf20Sopenharmony_ci	.trap_policer_fini		= mlxsw_sp_trap_policer_fini,
32418c2ecf20Sopenharmony_ci	.trap_policer_set		= mlxsw_sp_trap_policer_set,
32428c2ecf20Sopenharmony_ci	.trap_policer_counter_get	= mlxsw_sp_trap_policer_counter_get,
32438c2ecf20Sopenharmony_ci	.txhdr_construct		= mlxsw_sp_txhdr_construct,
32448c2ecf20Sopenharmony_ci	.resources_register		= mlxsw_sp1_resources_register,
32458c2ecf20Sopenharmony_ci	.kvd_sizes_get			= mlxsw_sp_kvd_sizes_get,
32468c2ecf20Sopenharmony_ci	.ptp_transmitted		= mlxsw_sp_ptp_transmitted,
32478c2ecf20Sopenharmony_ci	.txhdr_len			= MLXSW_TXHDR_LEN,
32488c2ecf20Sopenharmony_ci	.profile			= &mlxsw_sp1_config_profile,
32498c2ecf20Sopenharmony_ci	.res_query_enabled		= true,
32508c2ecf20Sopenharmony_ci	.fw_fatal_enabled		= true,
32518c2ecf20Sopenharmony_ci	.temp_warn_enabled		= true,
32528c2ecf20Sopenharmony_ci};
32538c2ecf20Sopenharmony_ci
32548c2ecf20Sopenharmony_cistatic struct mlxsw_driver mlxsw_sp2_driver = {
32558c2ecf20Sopenharmony_ci	.kind				= mlxsw_sp2_driver_name,
32568c2ecf20Sopenharmony_ci	.priv_size			= sizeof(struct mlxsw_sp),
32578c2ecf20Sopenharmony_ci	.fw_req_rev			= &mlxsw_sp2_fw_rev,
32588c2ecf20Sopenharmony_ci	.fw_filename			= MLXSW_SP2_FW_FILENAME,
32598c2ecf20Sopenharmony_ci	.init				= mlxsw_sp2_init,
32608c2ecf20Sopenharmony_ci	.fini				= mlxsw_sp_fini,
32618c2ecf20Sopenharmony_ci	.basic_trap_groups_set		= mlxsw_sp_basic_trap_groups_set,
32628c2ecf20Sopenharmony_ci	.port_split			= mlxsw_sp_port_split,
32638c2ecf20Sopenharmony_ci	.port_unsplit			= mlxsw_sp_port_unsplit,
32648c2ecf20Sopenharmony_ci	.sb_pool_get			= mlxsw_sp_sb_pool_get,
32658c2ecf20Sopenharmony_ci	.sb_pool_set			= mlxsw_sp_sb_pool_set,
32668c2ecf20Sopenharmony_ci	.sb_port_pool_get		= mlxsw_sp_sb_port_pool_get,
32678c2ecf20Sopenharmony_ci	.sb_port_pool_set		= mlxsw_sp_sb_port_pool_set,
32688c2ecf20Sopenharmony_ci	.sb_tc_pool_bind_get		= mlxsw_sp_sb_tc_pool_bind_get,
32698c2ecf20Sopenharmony_ci	.sb_tc_pool_bind_set		= mlxsw_sp_sb_tc_pool_bind_set,
32708c2ecf20Sopenharmony_ci	.sb_occ_snapshot		= mlxsw_sp_sb_occ_snapshot,
32718c2ecf20Sopenharmony_ci	.sb_occ_max_clear		= mlxsw_sp_sb_occ_max_clear,
32728c2ecf20Sopenharmony_ci	.sb_occ_port_pool_get		= mlxsw_sp_sb_occ_port_pool_get,
32738c2ecf20Sopenharmony_ci	.sb_occ_tc_port_bind_get	= mlxsw_sp_sb_occ_tc_port_bind_get,
32748c2ecf20Sopenharmony_ci	.trap_init			= mlxsw_sp_trap_init,
32758c2ecf20Sopenharmony_ci	.trap_fini			= mlxsw_sp_trap_fini,
32768c2ecf20Sopenharmony_ci	.trap_action_set		= mlxsw_sp_trap_action_set,
32778c2ecf20Sopenharmony_ci	.trap_group_init		= mlxsw_sp_trap_group_init,
32788c2ecf20Sopenharmony_ci	.trap_group_set			= mlxsw_sp_trap_group_set,
32798c2ecf20Sopenharmony_ci	.trap_policer_init		= mlxsw_sp_trap_policer_init,
32808c2ecf20Sopenharmony_ci	.trap_policer_fini		= mlxsw_sp_trap_policer_fini,
32818c2ecf20Sopenharmony_ci	.trap_policer_set		= mlxsw_sp_trap_policer_set,
32828c2ecf20Sopenharmony_ci	.trap_policer_counter_get	= mlxsw_sp_trap_policer_counter_get,
32838c2ecf20Sopenharmony_ci	.txhdr_construct		= mlxsw_sp_txhdr_construct,
32848c2ecf20Sopenharmony_ci	.resources_register		= mlxsw_sp2_resources_register,
32858c2ecf20Sopenharmony_ci	.params_register		= mlxsw_sp2_params_register,
32868c2ecf20Sopenharmony_ci	.params_unregister		= mlxsw_sp2_params_unregister,
32878c2ecf20Sopenharmony_ci	.ptp_transmitted		= mlxsw_sp_ptp_transmitted,
32888c2ecf20Sopenharmony_ci	.txhdr_len			= MLXSW_TXHDR_LEN,
32898c2ecf20Sopenharmony_ci	.profile			= &mlxsw_sp2_config_profile,
32908c2ecf20Sopenharmony_ci	.res_query_enabled		= true,
32918c2ecf20Sopenharmony_ci	.fw_fatal_enabled		= true,
32928c2ecf20Sopenharmony_ci	.temp_warn_enabled		= true,
32938c2ecf20Sopenharmony_ci};
32948c2ecf20Sopenharmony_ci
32958c2ecf20Sopenharmony_cistatic struct mlxsw_driver mlxsw_sp3_driver = {
32968c2ecf20Sopenharmony_ci	.kind				= mlxsw_sp3_driver_name,
32978c2ecf20Sopenharmony_ci	.priv_size			= sizeof(struct mlxsw_sp),
32988c2ecf20Sopenharmony_ci	.fw_req_rev			= &mlxsw_sp3_fw_rev,
32998c2ecf20Sopenharmony_ci	.fw_filename			= MLXSW_SP3_FW_FILENAME,
33008c2ecf20Sopenharmony_ci	.init				= mlxsw_sp3_init,
33018c2ecf20Sopenharmony_ci	.fini				= mlxsw_sp_fini,
33028c2ecf20Sopenharmony_ci	.basic_trap_groups_set		= mlxsw_sp_basic_trap_groups_set,
33038c2ecf20Sopenharmony_ci	.port_split			= mlxsw_sp_port_split,
33048c2ecf20Sopenharmony_ci	.port_unsplit			= mlxsw_sp_port_unsplit,
33058c2ecf20Sopenharmony_ci	.sb_pool_get			= mlxsw_sp_sb_pool_get,
33068c2ecf20Sopenharmony_ci	.sb_pool_set			= mlxsw_sp_sb_pool_set,
33078c2ecf20Sopenharmony_ci	.sb_port_pool_get		= mlxsw_sp_sb_port_pool_get,
33088c2ecf20Sopenharmony_ci	.sb_port_pool_set		= mlxsw_sp_sb_port_pool_set,
33098c2ecf20Sopenharmony_ci	.sb_tc_pool_bind_get		= mlxsw_sp_sb_tc_pool_bind_get,
33108c2ecf20Sopenharmony_ci	.sb_tc_pool_bind_set		= mlxsw_sp_sb_tc_pool_bind_set,
33118c2ecf20Sopenharmony_ci	.sb_occ_snapshot		= mlxsw_sp_sb_occ_snapshot,
33128c2ecf20Sopenharmony_ci	.sb_occ_max_clear		= mlxsw_sp_sb_occ_max_clear,
33138c2ecf20Sopenharmony_ci	.sb_occ_port_pool_get		= mlxsw_sp_sb_occ_port_pool_get,
33148c2ecf20Sopenharmony_ci	.sb_occ_tc_port_bind_get	= mlxsw_sp_sb_occ_tc_port_bind_get,
33158c2ecf20Sopenharmony_ci	.trap_init			= mlxsw_sp_trap_init,
33168c2ecf20Sopenharmony_ci	.trap_fini			= mlxsw_sp_trap_fini,
33178c2ecf20Sopenharmony_ci	.trap_action_set		= mlxsw_sp_trap_action_set,
33188c2ecf20Sopenharmony_ci	.trap_group_init		= mlxsw_sp_trap_group_init,
33198c2ecf20Sopenharmony_ci	.trap_group_set			= mlxsw_sp_trap_group_set,
33208c2ecf20Sopenharmony_ci	.trap_policer_init		= mlxsw_sp_trap_policer_init,
33218c2ecf20Sopenharmony_ci	.trap_policer_fini		= mlxsw_sp_trap_policer_fini,
33228c2ecf20Sopenharmony_ci	.trap_policer_set		= mlxsw_sp_trap_policer_set,
33238c2ecf20Sopenharmony_ci	.trap_policer_counter_get	= mlxsw_sp_trap_policer_counter_get,
33248c2ecf20Sopenharmony_ci	.txhdr_construct		= mlxsw_sp_txhdr_construct,
33258c2ecf20Sopenharmony_ci	.resources_register		= mlxsw_sp2_resources_register,
33268c2ecf20Sopenharmony_ci	.params_register		= mlxsw_sp2_params_register,
33278c2ecf20Sopenharmony_ci	.params_unregister		= mlxsw_sp2_params_unregister,
33288c2ecf20Sopenharmony_ci	.ptp_transmitted		= mlxsw_sp_ptp_transmitted,
33298c2ecf20Sopenharmony_ci	.txhdr_len			= MLXSW_TXHDR_LEN,
33308c2ecf20Sopenharmony_ci	.profile			= &mlxsw_sp2_config_profile,
33318c2ecf20Sopenharmony_ci	.res_query_enabled		= true,
33328c2ecf20Sopenharmony_ci	.fw_fatal_enabled		= true,
33338c2ecf20Sopenharmony_ci	.temp_warn_enabled		= true,
33348c2ecf20Sopenharmony_ci};
33358c2ecf20Sopenharmony_ci
33368c2ecf20Sopenharmony_cibool mlxsw_sp_port_dev_check(const struct net_device *dev)
33378c2ecf20Sopenharmony_ci{
33388c2ecf20Sopenharmony_ci	return dev->netdev_ops == &mlxsw_sp_port_netdev_ops;
33398c2ecf20Sopenharmony_ci}
33408c2ecf20Sopenharmony_ci
33418c2ecf20Sopenharmony_cistatic int mlxsw_sp_lower_dev_walk(struct net_device *lower_dev,
33428c2ecf20Sopenharmony_ci				   struct netdev_nested_priv *priv)
33438c2ecf20Sopenharmony_ci{
33448c2ecf20Sopenharmony_ci	int ret = 0;
33458c2ecf20Sopenharmony_ci
33468c2ecf20Sopenharmony_ci	if (mlxsw_sp_port_dev_check(lower_dev)) {
33478c2ecf20Sopenharmony_ci		priv->data = (void *)netdev_priv(lower_dev);
33488c2ecf20Sopenharmony_ci		ret = 1;
33498c2ecf20Sopenharmony_ci	}
33508c2ecf20Sopenharmony_ci
33518c2ecf20Sopenharmony_ci	return ret;
33528c2ecf20Sopenharmony_ci}
33538c2ecf20Sopenharmony_ci
33548c2ecf20Sopenharmony_cistruct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev)
33558c2ecf20Sopenharmony_ci{
33568c2ecf20Sopenharmony_ci	struct netdev_nested_priv priv = {
33578c2ecf20Sopenharmony_ci		.data = NULL,
33588c2ecf20Sopenharmony_ci	};
33598c2ecf20Sopenharmony_ci
33608c2ecf20Sopenharmony_ci	if (mlxsw_sp_port_dev_check(dev))
33618c2ecf20Sopenharmony_ci		return netdev_priv(dev);
33628c2ecf20Sopenharmony_ci
33638c2ecf20Sopenharmony_ci	netdev_walk_all_lower_dev(dev, mlxsw_sp_lower_dev_walk, &priv);
33648c2ecf20Sopenharmony_ci
33658c2ecf20Sopenharmony_ci	return (struct mlxsw_sp_port *)priv.data;
33668c2ecf20Sopenharmony_ci}
33678c2ecf20Sopenharmony_ci
33688c2ecf20Sopenharmony_cistruct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev)
33698c2ecf20Sopenharmony_ci{
33708c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port;
33718c2ecf20Sopenharmony_ci
33728c2ecf20Sopenharmony_ci	mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev);
33738c2ecf20Sopenharmony_ci	return mlxsw_sp_port ? mlxsw_sp_port->mlxsw_sp : NULL;
33748c2ecf20Sopenharmony_ci}
33758c2ecf20Sopenharmony_ci
33768c2ecf20Sopenharmony_cistruct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev)
33778c2ecf20Sopenharmony_ci{
33788c2ecf20Sopenharmony_ci	struct netdev_nested_priv priv = {
33798c2ecf20Sopenharmony_ci		.data = NULL,
33808c2ecf20Sopenharmony_ci	};
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_ci	if (mlxsw_sp_port_dev_check(dev))
33838c2ecf20Sopenharmony_ci		return netdev_priv(dev);
33848c2ecf20Sopenharmony_ci
33858c2ecf20Sopenharmony_ci	netdev_walk_all_lower_dev_rcu(dev, mlxsw_sp_lower_dev_walk,
33868c2ecf20Sopenharmony_ci				      &priv);
33878c2ecf20Sopenharmony_ci
33888c2ecf20Sopenharmony_ci	return (struct mlxsw_sp_port *)priv.data;
33898c2ecf20Sopenharmony_ci}
33908c2ecf20Sopenharmony_ci
33918c2ecf20Sopenharmony_cistruct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev)
33928c2ecf20Sopenharmony_ci{
33938c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port;
33948c2ecf20Sopenharmony_ci
33958c2ecf20Sopenharmony_ci	rcu_read_lock();
33968c2ecf20Sopenharmony_ci	mlxsw_sp_port = mlxsw_sp_port_dev_lower_find_rcu(dev);
33978c2ecf20Sopenharmony_ci	if (mlxsw_sp_port)
33988c2ecf20Sopenharmony_ci		dev_hold(mlxsw_sp_port->dev);
33998c2ecf20Sopenharmony_ci	rcu_read_unlock();
34008c2ecf20Sopenharmony_ci	return mlxsw_sp_port;
34018c2ecf20Sopenharmony_ci}
34028c2ecf20Sopenharmony_ci
34038c2ecf20Sopenharmony_civoid mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port)
34048c2ecf20Sopenharmony_ci{
34058c2ecf20Sopenharmony_ci	dev_put(mlxsw_sp_port->dev);
34068c2ecf20Sopenharmony_ci}
34078c2ecf20Sopenharmony_ci
34088c2ecf20Sopenharmony_cistatic void
34098c2ecf20Sopenharmony_cimlxsw_sp_port_lag_uppers_cleanup(struct mlxsw_sp_port *mlxsw_sp_port,
34108c2ecf20Sopenharmony_ci				 struct net_device *lag_dev)
34118c2ecf20Sopenharmony_ci{
34128c2ecf20Sopenharmony_ci	struct net_device *br_dev = netdev_master_upper_dev_get(lag_dev);
34138c2ecf20Sopenharmony_ci	struct net_device *upper_dev;
34148c2ecf20Sopenharmony_ci	struct list_head *iter;
34158c2ecf20Sopenharmony_ci
34168c2ecf20Sopenharmony_ci	if (netif_is_bridge_port(lag_dev))
34178c2ecf20Sopenharmony_ci		mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, br_dev);
34188c2ecf20Sopenharmony_ci
34198c2ecf20Sopenharmony_ci	netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {
34208c2ecf20Sopenharmony_ci		if (!netif_is_bridge_port(upper_dev))
34218c2ecf20Sopenharmony_ci			continue;
34228c2ecf20Sopenharmony_ci		br_dev = netdev_master_upper_dev_get(upper_dev);
34238c2ecf20Sopenharmony_ci		mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, br_dev);
34248c2ecf20Sopenharmony_ci	}
34258c2ecf20Sopenharmony_ci}
34268c2ecf20Sopenharmony_ci
34278c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
34288c2ecf20Sopenharmony_ci{
34298c2ecf20Sopenharmony_ci	char sldr_pl[MLXSW_REG_SLDR_LEN];
34308c2ecf20Sopenharmony_ci
34318c2ecf20Sopenharmony_ci	mlxsw_reg_sldr_lag_create_pack(sldr_pl, lag_id);
34328c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);
34338c2ecf20Sopenharmony_ci}
34348c2ecf20Sopenharmony_ci
34358c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_destroy(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
34368c2ecf20Sopenharmony_ci{
34378c2ecf20Sopenharmony_ci	char sldr_pl[MLXSW_REG_SLDR_LEN];
34388c2ecf20Sopenharmony_ci
34398c2ecf20Sopenharmony_ci	mlxsw_reg_sldr_lag_destroy_pack(sldr_pl, lag_id);
34408c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);
34418c2ecf20Sopenharmony_ci}
34428c2ecf20Sopenharmony_ci
34438c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_col_port_add(struct mlxsw_sp_port *mlxsw_sp_port,
34448c2ecf20Sopenharmony_ci				     u16 lag_id, u8 port_index)
34458c2ecf20Sopenharmony_ci{
34468c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
34478c2ecf20Sopenharmony_ci	char slcor_pl[MLXSW_REG_SLCOR_LEN];
34488c2ecf20Sopenharmony_ci
34498c2ecf20Sopenharmony_ci	mlxsw_reg_slcor_port_add_pack(slcor_pl, mlxsw_sp_port->local_port,
34508c2ecf20Sopenharmony_ci				      lag_id, port_index);
34518c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl);
34528c2ecf20Sopenharmony_ci}
34538c2ecf20Sopenharmony_ci
34548c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_col_port_remove(struct mlxsw_sp_port *mlxsw_sp_port,
34558c2ecf20Sopenharmony_ci					u16 lag_id)
34568c2ecf20Sopenharmony_ci{
34578c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
34588c2ecf20Sopenharmony_ci	char slcor_pl[MLXSW_REG_SLCOR_LEN];
34598c2ecf20Sopenharmony_ci
34608c2ecf20Sopenharmony_ci	mlxsw_reg_slcor_port_remove_pack(slcor_pl, mlxsw_sp_port->local_port,
34618c2ecf20Sopenharmony_ci					 lag_id);
34628c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl);
34638c2ecf20Sopenharmony_ci}
34648c2ecf20Sopenharmony_ci
34658c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_col_port_enable(struct mlxsw_sp_port *mlxsw_sp_port,
34668c2ecf20Sopenharmony_ci					u16 lag_id)
34678c2ecf20Sopenharmony_ci{
34688c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
34698c2ecf20Sopenharmony_ci	char slcor_pl[MLXSW_REG_SLCOR_LEN];
34708c2ecf20Sopenharmony_ci
34718c2ecf20Sopenharmony_ci	mlxsw_reg_slcor_col_enable_pack(slcor_pl, mlxsw_sp_port->local_port,
34728c2ecf20Sopenharmony_ci					lag_id);
34738c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl);
34748c2ecf20Sopenharmony_ci}
34758c2ecf20Sopenharmony_ci
34768c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_col_port_disable(struct mlxsw_sp_port *mlxsw_sp_port,
34778c2ecf20Sopenharmony_ci					 u16 lag_id)
34788c2ecf20Sopenharmony_ci{
34798c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
34808c2ecf20Sopenharmony_ci	char slcor_pl[MLXSW_REG_SLCOR_LEN];
34818c2ecf20Sopenharmony_ci
34828c2ecf20Sopenharmony_ci	mlxsw_reg_slcor_col_disable_pack(slcor_pl, mlxsw_sp_port->local_port,
34838c2ecf20Sopenharmony_ci					 lag_id);
34848c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl);
34858c2ecf20Sopenharmony_ci}
34868c2ecf20Sopenharmony_ci
34878c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp,
34888c2ecf20Sopenharmony_ci				  struct net_device *lag_dev,
34898c2ecf20Sopenharmony_ci				  u16 *p_lag_id)
34908c2ecf20Sopenharmony_ci{
34918c2ecf20Sopenharmony_ci	struct mlxsw_sp_upper *lag;
34928c2ecf20Sopenharmony_ci	int free_lag_id = -1;
34938c2ecf20Sopenharmony_ci	u64 max_lag;
34948c2ecf20Sopenharmony_ci	int i;
34958c2ecf20Sopenharmony_ci
34968c2ecf20Sopenharmony_ci	max_lag = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_LAG);
34978c2ecf20Sopenharmony_ci	for (i = 0; i < max_lag; i++) {
34988c2ecf20Sopenharmony_ci		lag = mlxsw_sp_lag_get(mlxsw_sp, i);
34998c2ecf20Sopenharmony_ci		if (lag->ref_count) {
35008c2ecf20Sopenharmony_ci			if (lag->dev == lag_dev) {
35018c2ecf20Sopenharmony_ci				*p_lag_id = i;
35028c2ecf20Sopenharmony_ci				return 0;
35038c2ecf20Sopenharmony_ci			}
35048c2ecf20Sopenharmony_ci		} else if (free_lag_id < 0) {
35058c2ecf20Sopenharmony_ci			free_lag_id = i;
35068c2ecf20Sopenharmony_ci		}
35078c2ecf20Sopenharmony_ci	}
35088c2ecf20Sopenharmony_ci	if (free_lag_id < 0)
35098c2ecf20Sopenharmony_ci		return -EBUSY;
35108c2ecf20Sopenharmony_ci	*p_lag_id = free_lag_id;
35118c2ecf20Sopenharmony_ci	return 0;
35128c2ecf20Sopenharmony_ci}
35138c2ecf20Sopenharmony_ci
35148c2ecf20Sopenharmony_cistatic bool
35158c2ecf20Sopenharmony_cimlxsw_sp_master_lag_check(struct mlxsw_sp *mlxsw_sp,
35168c2ecf20Sopenharmony_ci			  struct net_device *lag_dev,
35178c2ecf20Sopenharmony_ci			  struct netdev_lag_upper_info *lag_upper_info,
35188c2ecf20Sopenharmony_ci			  struct netlink_ext_ack *extack)
35198c2ecf20Sopenharmony_ci{
35208c2ecf20Sopenharmony_ci	u16 lag_id;
35218c2ecf20Sopenharmony_ci
35228c2ecf20Sopenharmony_ci	if (mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id) != 0) {
35238c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported LAG devices");
35248c2ecf20Sopenharmony_ci		return false;
35258c2ecf20Sopenharmony_ci	}
35268c2ecf20Sopenharmony_ci	if (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
35278c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "LAG device using unsupported Tx type");
35288c2ecf20Sopenharmony_ci		return false;
35298c2ecf20Sopenharmony_ci	}
35308c2ecf20Sopenharmony_ci	return true;
35318c2ecf20Sopenharmony_ci}
35328c2ecf20Sopenharmony_ci
35338c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_lag_index_get(struct mlxsw_sp *mlxsw_sp,
35348c2ecf20Sopenharmony_ci				       u16 lag_id, u8 *p_port_index)
35358c2ecf20Sopenharmony_ci{
35368c2ecf20Sopenharmony_ci	u64 max_lag_members;
35378c2ecf20Sopenharmony_ci	int i;
35388c2ecf20Sopenharmony_ci
35398c2ecf20Sopenharmony_ci	max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core,
35408c2ecf20Sopenharmony_ci					     MAX_LAG_MEMBERS);
35418c2ecf20Sopenharmony_ci	for (i = 0; i < max_lag_members; i++) {
35428c2ecf20Sopenharmony_ci		if (!mlxsw_sp_port_lagged_get(mlxsw_sp, lag_id, i)) {
35438c2ecf20Sopenharmony_ci			*p_port_index = i;
35448c2ecf20Sopenharmony_ci			return 0;
35458c2ecf20Sopenharmony_ci		}
35468c2ecf20Sopenharmony_ci	}
35478c2ecf20Sopenharmony_ci	return -EBUSY;
35488c2ecf20Sopenharmony_ci}
35498c2ecf20Sopenharmony_ci
35508c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
35518c2ecf20Sopenharmony_ci				  struct net_device *lag_dev)
35528c2ecf20Sopenharmony_ci{
35538c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
35548c2ecf20Sopenharmony_ci	struct mlxsw_sp_upper *lag;
35558c2ecf20Sopenharmony_ci	u16 lag_id;
35568c2ecf20Sopenharmony_ci	u8 port_index;
35578c2ecf20Sopenharmony_ci	int err;
35588c2ecf20Sopenharmony_ci
35598c2ecf20Sopenharmony_ci	err = mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id);
35608c2ecf20Sopenharmony_ci	if (err)
35618c2ecf20Sopenharmony_ci		return err;
35628c2ecf20Sopenharmony_ci	lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id);
35638c2ecf20Sopenharmony_ci	if (!lag->ref_count) {
35648c2ecf20Sopenharmony_ci		err = mlxsw_sp_lag_create(mlxsw_sp, lag_id);
35658c2ecf20Sopenharmony_ci		if (err)
35668c2ecf20Sopenharmony_ci			return err;
35678c2ecf20Sopenharmony_ci		lag->dev = lag_dev;
35688c2ecf20Sopenharmony_ci	}
35698c2ecf20Sopenharmony_ci
35708c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_lag_index_get(mlxsw_sp, lag_id, &port_index);
35718c2ecf20Sopenharmony_ci	if (err)
35728c2ecf20Sopenharmony_ci		return err;
35738c2ecf20Sopenharmony_ci	err = mlxsw_sp_lag_col_port_add(mlxsw_sp_port, lag_id, port_index);
35748c2ecf20Sopenharmony_ci	if (err)
35758c2ecf20Sopenharmony_ci		goto err_col_port_add;
35768c2ecf20Sopenharmony_ci
35778c2ecf20Sopenharmony_ci	mlxsw_core_lag_mapping_set(mlxsw_sp->core, lag_id, port_index,
35788c2ecf20Sopenharmony_ci				   mlxsw_sp_port->local_port);
35798c2ecf20Sopenharmony_ci	mlxsw_sp_port->lag_id = lag_id;
35808c2ecf20Sopenharmony_ci	mlxsw_sp_port->lagged = 1;
35818c2ecf20Sopenharmony_ci	lag->ref_count++;
35828c2ecf20Sopenharmony_ci
35838c2ecf20Sopenharmony_ci	/* Port is no longer usable as a router interface */
35848c2ecf20Sopenharmony_ci	if (mlxsw_sp_port->default_vlan->fid)
35858c2ecf20Sopenharmony_ci		mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port->default_vlan);
35868c2ecf20Sopenharmony_ci
35878c2ecf20Sopenharmony_ci	return 0;
35888c2ecf20Sopenharmony_ci
35898c2ecf20Sopenharmony_cierr_col_port_add:
35908c2ecf20Sopenharmony_ci	if (!lag->ref_count)
35918c2ecf20Sopenharmony_ci		mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);
35928c2ecf20Sopenharmony_ci	return err;
35938c2ecf20Sopenharmony_ci}
35948c2ecf20Sopenharmony_ci
35958c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,
35968c2ecf20Sopenharmony_ci				    struct net_device *lag_dev)
35978c2ecf20Sopenharmony_ci{
35988c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
35998c2ecf20Sopenharmony_ci	u16 lag_id = mlxsw_sp_port->lag_id;
36008c2ecf20Sopenharmony_ci	struct mlxsw_sp_upper *lag;
36018c2ecf20Sopenharmony_ci
36028c2ecf20Sopenharmony_ci	if (!mlxsw_sp_port->lagged)
36038c2ecf20Sopenharmony_ci		return;
36048c2ecf20Sopenharmony_ci	lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id);
36058c2ecf20Sopenharmony_ci	WARN_ON(lag->ref_count == 0);
36068c2ecf20Sopenharmony_ci
36078c2ecf20Sopenharmony_ci	mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id);
36088c2ecf20Sopenharmony_ci
36098c2ecf20Sopenharmony_ci	/* Any VLANs configured on the port are no longer valid */
36108c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan_flush(mlxsw_sp_port, false);
36118c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan_cleanup(mlxsw_sp_port->default_vlan);
36128c2ecf20Sopenharmony_ci	/* Make the LAG and its directly linked uppers leave bridges they
36138c2ecf20Sopenharmony_ci	 * are memeber in
36148c2ecf20Sopenharmony_ci	 */
36158c2ecf20Sopenharmony_ci	mlxsw_sp_port_lag_uppers_cleanup(mlxsw_sp_port, lag_dev);
36168c2ecf20Sopenharmony_ci
36178c2ecf20Sopenharmony_ci	if (lag->ref_count == 1)
36188c2ecf20Sopenharmony_ci		mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);
36198c2ecf20Sopenharmony_ci
36208c2ecf20Sopenharmony_ci	mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id,
36218c2ecf20Sopenharmony_ci				     mlxsw_sp_port->local_port);
36228c2ecf20Sopenharmony_ci	mlxsw_sp_port->lagged = 0;
36238c2ecf20Sopenharmony_ci	lag->ref_count--;
36248c2ecf20Sopenharmony_ci
36258c2ecf20Sopenharmony_ci	/* Make sure untagged frames are allowed to ingress */
36268c2ecf20Sopenharmony_ci	mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID);
36278c2ecf20Sopenharmony_ci}
36288c2ecf20Sopenharmony_ci
36298c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_dist_port_add(struct mlxsw_sp_port *mlxsw_sp_port,
36308c2ecf20Sopenharmony_ci				      u16 lag_id)
36318c2ecf20Sopenharmony_ci{
36328c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
36338c2ecf20Sopenharmony_ci	char sldr_pl[MLXSW_REG_SLDR_LEN];
36348c2ecf20Sopenharmony_ci
36358c2ecf20Sopenharmony_ci	mlxsw_reg_sldr_lag_add_port_pack(sldr_pl, lag_id,
36368c2ecf20Sopenharmony_ci					 mlxsw_sp_port->local_port);
36378c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);
36388c2ecf20Sopenharmony_ci}
36398c2ecf20Sopenharmony_ci
36408c2ecf20Sopenharmony_cistatic int mlxsw_sp_lag_dist_port_remove(struct mlxsw_sp_port *mlxsw_sp_port,
36418c2ecf20Sopenharmony_ci					 u16 lag_id)
36428c2ecf20Sopenharmony_ci{
36438c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
36448c2ecf20Sopenharmony_ci	char sldr_pl[MLXSW_REG_SLDR_LEN];
36458c2ecf20Sopenharmony_ci
36468c2ecf20Sopenharmony_ci	mlxsw_reg_sldr_lag_remove_port_pack(sldr_pl, lag_id,
36478c2ecf20Sopenharmony_ci					    mlxsw_sp_port->local_port);
36488c2ecf20Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);
36498c2ecf20Sopenharmony_ci}
36508c2ecf20Sopenharmony_ci
36518c2ecf20Sopenharmony_cistatic int
36528c2ecf20Sopenharmony_cimlxsw_sp_port_lag_col_dist_enable(struct mlxsw_sp_port *mlxsw_sp_port)
36538c2ecf20Sopenharmony_ci{
36548c2ecf20Sopenharmony_ci	int err;
36558c2ecf20Sopenharmony_ci
36568c2ecf20Sopenharmony_ci	err = mlxsw_sp_lag_col_port_enable(mlxsw_sp_port,
36578c2ecf20Sopenharmony_ci					   mlxsw_sp_port->lag_id);
36588c2ecf20Sopenharmony_ci	if (err)
36598c2ecf20Sopenharmony_ci		return err;
36608c2ecf20Sopenharmony_ci
36618c2ecf20Sopenharmony_ci	err = mlxsw_sp_lag_dist_port_add(mlxsw_sp_port, mlxsw_sp_port->lag_id);
36628c2ecf20Sopenharmony_ci	if (err)
36638c2ecf20Sopenharmony_ci		goto err_dist_port_add;
36648c2ecf20Sopenharmony_ci
36658c2ecf20Sopenharmony_ci	return 0;
36668c2ecf20Sopenharmony_ci
36678c2ecf20Sopenharmony_cierr_dist_port_add:
36688c2ecf20Sopenharmony_ci	mlxsw_sp_lag_col_port_disable(mlxsw_sp_port, mlxsw_sp_port->lag_id);
36698c2ecf20Sopenharmony_ci	return err;
36708c2ecf20Sopenharmony_ci}
36718c2ecf20Sopenharmony_ci
36728c2ecf20Sopenharmony_cistatic int
36738c2ecf20Sopenharmony_cimlxsw_sp_port_lag_col_dist_disable(struct mlxsw_sp_port *mlxsw_sp_port)
36748c2ecf20Sopenharmony_ci{
36758c2ecf20Sopenharmony_ci	int err;
36768c2ecf20Sopenharmony_ci
36778c2ecf20Sopenharmony_ci	err = mlxsw_sp_lag_dist_port_remove(mlxsw_sp_port,
36788c2ecf20Sopenharmony_ci					    mlxsw_sp_port->lag_id);
36798c2ecf20Sopenharmony_ci	if (err)
36808c2ecf20Sopenharmony_ci		return err;
36818c2ecf20Sopenharmony_ci
36828c2ecf20Sopenharmony_ci	err = mlxsw_sp_lag_col_port_disable(mlxsw_sp_port,
36838c2ecf20Sopenharmony_ci					    mlxsw_sp_port->lag_id);
36848c2ecf20Sopenharmony_ci	if (err)
36858c2ecf20Sopenharmony_ci		goto err_col_port_disable;
36868c2ecf20Sopenharmony_ci
36878c2ecf20Sopenharmony_ci	return 0;
36888c2ecf20Sopenharmony_ci
36898c2ecf20Sopenharmony_cierr_col_port_disable:
36908c2ecf20Sopenharmony_ci	mlxsw_sp_lag_dist_port_add(mlxsw_sp_port, mlxsw_sp_port->lag_id);
36918c2ecf20Sopenharmony_ci	return err;
36928c2ecf20Sopenharmony_ci}
36938c2ecf20Sopenharmony_ci
36948c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_lag_changed(struct mlxsw_sp_port *mlxsw_sp_port,
36958c2ecf20Sopenharmony_ci				     struct netdev_lag_lower_state_info *info)
36968c2ecf20Sopenharmony_ci{
36978c2ecf20Sopenharmony_ci	if (info->tx_enabled)
36988c2ecf20Sopenharmony_ci		return mlxsw_sp_port_lag_col_dist_enable(mlxsw_sp_port);
36998c2ecf20Sopenharmony_ci	else
37008c2ecf20Sopenharmony_ci		return mlxsw_sp_port_lag_col_dist_disable(mlxsw_sp_port);
37018c2ecf20Sopenharmony_ci}
37028c2ecf20Sopenharmony_ci
37038c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_stp_set(struct mlxsw_sp_port *mlxsw_sp_port,
37048c2ecf20Sopenharmony_ci				 bool enable)
37058c2ecf20Sopenharmony_ci{
37068c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
37078c2ecf20Sopenharmony_ci	enum mlxsw_reg_spms_state spms_state;
37088c2ecf20Sopenharmony_ci	char *spms_pl;
37098c2ecf20Sopenharmony_ci	u16 vid;
37108c2ecf20Sopenharmony_ci	int err;
37118c2ecf20Sopenharmony_ci
37128c2ecf20Sopenharmony_ci	spms_state = enable ? MLXSW_REG_SPMS_STATE_FORWARDING :
37138c2ecf20Sopenharmony_ci			      MLXSW_REG_SPMS_STATE_DISCARDING;
37148c2ecf20Sopenharmony_ci
37158c2ecf20Sopenharmony_ci	spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL);
37168c2ecf20Sopenharmony_ci	if (!spms_pl)
37178c2ecf20Sopenharmony_ci		return -ENOMEM;
37188c2ecf20Sopenharmony_ci	mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port);
37198c2ecf20Sopenharmony_ci
37208c2ecf20Sopenharmony_ci	for (vid = 0; vid < VLAN_N_VID; vid++)
37218c2ecf20Sopenharmony_ci		mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state);
37228c2ecf20Sopenharmony_ci
37238c2ecf20Sopenharmony_ci	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl);
37248c2ecf20Sopenharmony_ci	kfree(spms_pl);
37258c2ecf20Sopenharmony_ci	return err;
37268c2ecf20Sopenharmony_ci}
37278c2ecf20Sopenharmony_ci
37288c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port)
37298c2ecf20Sopenharmony_ci{
37308c2ecf20Sopenharmony_ci	u16 vid = 1;
37318c2ecf20Sopenharmony_ci	int err;
37328c2ecf20Sopenharmony_ci
37338c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
37348c2ecf20Sopenharmony_ci	if (err)
37358c2ecf20Sopenharmony_ci		return err;
37368c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_stp_set(mlxsw_sp_port, true);
37378c2ecf20Sopenharmony_ci	if (err)
37388c2ecf20Sopenharmony_ci		goto err_port_stp_set;
37398c2ecf20Sopenharmony_ci	err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 1, VLAN_N_VID - 2,
37408c2ecf20Sopenharmony_ci				     true, false);
37418c2ecf20Sopenharmony_ci	if (err)
37428c2ecf20Sopenharmony_ci		goto err_port_vlan_set;
37438c2ecf20Sopenharmony_ci
37448c2ecf20Sopenharmony_ci	for (; vid <= VLAN_N_VID - 1; vid++) {
37458c2ecf20Sopenharmony_ci		err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port,
37468c2ecf20Sopenharmony_ci						     vid, false);
37478c2ecf20Sopenharmony_ci		if (err)
37488c2ecf20Sopenharmony_ci			goto err_vid_learning_set;
37498c2ecf20Sopenharmony_ci	}
37508c2ecf20Sopenharmony_ci
37518c2ecf20Sopenharmony_ci	return 0;
37528c2ecf20Sopenharmony_ci
37538c2ecf20Sopenharmony_cierr_vid_learning_set:
37548c2ecf20Sopenharmony_ci	for (vid--; vid >= 1; vid--)
37558c2ecf20Sopenharmony_ci		mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);
37568c2ecf20Sopenharmony_cierr_port_vlan_set:
37578c2ecf20Sopenharmony_ci	mlxsw_sp_port_stp_set(mlxsw_sp_port, false);
37588c2ecf20Sopenharmony_cierr_port_stp_set:
37598c2ecf20Sopenharmony_ci	mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
37608c2ecf20Sopenharmony_ci	return err;
37618c2ecf20Sopenharmony_ci}
37628c2ecf20Sopenharmony_ci
37638c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port)
37648c2ecf20Sopenharmony_ci{
37658c2ecf20Sopenharmony_ci	u16 vid;
37668c2ecf20Sopenharmony_ci
37678c2ecf20Sopenharmony_ci	for (vid = VLAN_N_VID - 1; vid >= 1; vid--)
37688c2ecf20Sopenharmony_ci		mlxsw_sp_port_vid_learning_set(mlxsw_sp_port,
37698c2ecf20Sopenharmony_ci					       vid, true);
37708c2ecf20Sopenharmony_ci
37718c2ecf20Sopenharmony_ci	mlxsw_sp_port_vlan_set(mlxsw_sp_port, 1, VLAN_N_VID - 2,
37728c2ecf20Sopenharmony_ci			       false, false);
37738c2ecf20Sopenharmony_ci	mlxsw_sp_port_stp_set(mlxsw_sp_port, false);
37748c2ecf20Sopenharmony_ci	mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
37758c2ecf20Sopenharmony_ci}
37768c2ecf20Sopenharmony_ci
37778c2ecf20Sopenharmony_cistatic bool mlxsw_sp_bridge_has_multiple_vxlans(struct net_device *br_dev)
37788c2ecf20Sopenharmony_ci{
37798c2ecf20Sopenharmony_ci	unsigned int num_vxlans = 0;
37808c2ecf20Sopenharmony_ci	struct net_device *dev;
37818c2ecf20Sopenharmony_ci	struct list_head *iter;
37828c2ecf20Sopenharmony_ci
37838c2ecf20Sopenharmony_ci	netdev_for_each_lower_dev(br_dev, dev, iter) {
37848c2ecf20Sopenharmony_ci		if (netif_is_vxlan(dev))
37858c2ecf20Sopenharmony_ci			num_vxlans++;
37868c2ecf20Sopenharmony_ci	}
37878c2ecf20Sopenharmony_ci
37888c2ecf20Sopenharmony_ci	return num_vxlans > 1;
37898c2ecf20Sopenharmony_ci}
37908c2ecf20Sopenharmony_ci
37918c2ecf20Sopenharmony_cistatic bool mlxsw_sp_bridge_vxlan_vlan_is_valid(struct net_device *br_dev)
37928c2ecf20Sopenharmony_ci{
37938c2ecf20Sopenharmony_ci	DECLARE_BITMAP(vlans, VLAN_N_VID) = {0};
37948c2ecf20Sopenharmony_ci	struct net_device *dev;
37958c2ecf20Sopenharmony_ci	struct list_head *iter;
37968c2ecf20Sopenharmony_ci
37978c2ecf20Sopenharmony_ci	netdev_for_each_lower_dev(br_dev, dev, iter) {
37988c2ecf20Sopenharmony_ci		u16 pvid;
37998c2ecf20Sopenharmony_ci		int err;
38008c2ecf20Sopenharmony_ci
38018c2ecf20Sopenharmony_ci		if (!netif_is_vxlan(dev))
38028c2ecf20Sopenharmony_ci			continue;
38038c2ecf20Sopenharmony_ci
38048c2ecf20Sopenharmony_ci		err = mlxsw_sp_vxlan_mapped_vid(dev, &pvid);
38058c2ecf20Sopenharmony_ci		if (err || !pvid)
38068c2ecf20Sopenharmony_ci			continue;
38078c2ecf20Sopenharmony_ci
38088c2ecf20Sopenharmony_ci		if (test_and_set_bit(pvid, vlans))
38098c2ecf20Sopenharmony_ci			return false;
38108c2ecf20Sopenharmony_ci	}
38118c2ecf20Sopenharmony_ci
38128c2ecf20Sopenharmony_ci	return true;
38138c2ecf20Sopenharmony_ci}
38148c2ecf20Sopenharmony_ci
38158c2ecf20Sopenharmony_cistatic bool mlxsw_sp_bridge_vxlan_is_valid(struct net_device *br_dev,
38168c2ecf20Sopenharmony_ci					   struct netlink_ext_ack *extack)
38178c2ecf20Sopenharmony_ci{
38188c2ecf20Sopenharmony_ci	if (br_multicast_enabled(br_dev)) {
38198c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Multicast can not be enabled on a bridge with a VxLAN device");
38208c2ecf20Sopenharmony_ci		return false;
38218c2ecf20Sopenharmony_ci	}
38228c2ecf20Sopenharmony_ci
38238c2ecf20Sopenharmony_ci	if (!br_vlan_enabled(br_dev) &&
38248c2ecf20Sopenharmony_ci	    mlxsw_sp_bridge_has_multiple_vxlans(br_dev)) {
38258c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices are not supported in a VLAN-unaware bridge");
38268c2ecf20Sopenharmony_ci		return false;
38278c2ecf20Sopenharmony_ci	}
38288c2ecf20Sopenharmony_ci
38298c2ecf20Sopenharmony_ci	if (br_vlan_enabled(br_dev) &&
38308c2ecf20Sopenharmony_ci	    !mlxsw_sp_bridge_vxlan_vlan_is_valid(br_dev)) {
38318c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices cannot have the same VLAN as PVID and egress untagged");
38328c2ecf20Sopenharmony_ci		return false;
38338c2ecf20Sopenharmony_ci	}
38348c2ecf20Sopenharmony_ci
38358c2ecf20Sopenharmony_ci	return true;
38368c2ecf20Sopenharmony_ci}
38378c2ecf20Sopenharmony_ci
38388c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,
38398c2ecf20Sopenharmony_ci					       struct net_device *dev,
38408c2ecf20Sopenharmony_ci					       unsigned long event, void *ptr)
38418c2ecf20Sopenharmony_ci{
38428c2ecf20Sopenharmony_ci	struct netdev_notifier_changeupper_info *info;
38438c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port;
38448c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack;
38458c2ecf20Sopenharmony_ci	struct net_device *upper_dev;
38468c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp;
38478c2ecf20Sopenharmony_ci	int err = 0;
38488c2ecf20Sopenharmony_ci
38498c2ecf20Sopenharmony_ci	mlxsw_sp_port = netdev_priv(dev);
38508c2ecf20Sopenharmony_ci	mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
38518c2ecf20Sopenharmony_ci	info = ptr;
38528c2ecf20Sopenharmony_ci	extack = netdev_notifier_info_to_extack(&info->info);
38538c2ecf20Sopenharmony_ci
38548c2ecf20Sopenharmony_ci	switch (event) {
38558c2ecf20Sopenharmony_ci	case NETDEV_PRECHANGEUPPER:
38568c2ecf20Sopenharmony_ci		upper_dev = info->upper_dev;
38578c2ecf20Sopenharmony_ci		if (!is_vlan_dev(upper_dev) &&
38588c2ecf20Sopenharmony_ci		    !netif_is_lag_master(upper_dev) &&
38598c2ecf20Sopenharmony_ci		    !netif_is_bridge_master(upper_dev) &&
38608c2ecf20Sopenharmony_ci		    !netif_is_ovs_master(upper_dev) &&
38618c2ecf20Sopenharmony_ci		    !netif_is_macvlan(upper_dev)) {
38628c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
38638c2ecf20Sopenharmony_ci			return -EINVAL;
38648c2ecf20Sopenharmony_ci		}
38658c2ecf20Sopenharmony_ci		if (!info->linking)
38668c2ecf20Sopenharmony_ci			break;
38678c2ecf20Sopenharmony_ci		if (netif_is_bridge_master(upper_dev) &&
38688c2ecf20Sopenharmony_ci		    !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) &&
38698c2ecf20Sopenharmony_ci		    mlxsw_sp_bridge_has_vxlan(upper_dev) &&
38708c2ecf20Sopenharmony_ci		    !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack))
38718c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
38728c2ecf20Sopenharmony_ci		if (netdev_has_any_upper_dev(upper_dev) &&
38738c2ecf20Sopenharmony_ci		    (!netif_is_bridge_master(upper_dev) ||
38748c2ecf20Sopenharmony_ci		     !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,
38758c2ecf20Sopenharmony_ci							  upper_dev))) {
38768c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Enslaving a port to a device that already has an upper device is not supported");
38778c2ecf20Sopenharmony_ci			return -EINVAL;
38788c2ecf20Sopenharmony_ci		}
38798c2ecf20Sopenharmony_ci		if (netif_is_lag_master(upper_dev) &&
38808c2ecf20Sopenharmony_ci		    !mlxsw_sp_master_lag_check(mlxsw_sp, upper_dev,
38818c2ecf20Sopenharmony_ci					       info->upper_info, extack))
38828c2ecf20Sopenharmony_ci			return -EINVAL;
38838c2ecf20Sopenharmony_ci		if (netif_is_lag_master(upper_dev) && vlan_uses_dev(dev)) {
38848c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Master device is a LAG master and this device has a VLAN");
38858c2ecf20Sopenharmony_ci			return -EINVAL;
38868c2ecf20Sopenharmony_ci		}
38878c2ecf20Sopenharmony_ci		if (netif_is_lag_port(dev) && is_vlan_dev(upper_dev) &&
38888c2ecf20Sopenharmony_ci		    !netif_is_lag_master(vlan_dev_real_dev(upper_dev))) {
38898c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on a LAG port");
38908c2ecf20Sopenharmony_ci			return -EINVAL;
38918c2ecf20Sopenharmony_ci		}
38928c2ecf20Sopenharmony_ci		if (netif_is_macvlan(upper_dev) &&
38938c2ecf20Sopenharmony_ci		    !mlxsw_sp_rif_exists(mlxsw_sp, lower_dev)) {
38948c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
38958c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
38968c2ecf20Sopenharmony_ci		}
38978c2ecf20Sopenharmony_ci		if (netif_is_ovs_master(upper_dev) && vlan_uses_dev(dev)) {
38988c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Master device is an OVS master and this device has a VLAN");
38998c2ecf20Sopenharmony_ci			return -EINVAL;
39008c2ecf20Sopenharmony_ci		}
39018c2ecf20Sopenharmony_ci		if (netif_is_ovs_port(dev) && is_vlan_dev(upper_dev)) {
39028c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on an OVS port");
39038c2ecf20Sopenharmony_ci			return -EINVAL;
39048c2ecf20Sopenharmony_ci		}
39058c2ecf20Sopenharmony_ci		break;
39068c2ecf20Sopenharmony_ci	case NETDEV_CHANGEUPPER:
39078c2ecf20Sopenharmony_ci		upper_dev = info->upper_dev;
39088c2ecf20Sopenharmony_ci		if (netif_is_bridge_master(upper_dev)) {
39098c2ecf20Sopenharmony_ci			if (info->linking)
39108c2ecf20Sopenharmony_ci				err = mlxsw_sp_port_bridge_join(mlxsw_sp_port,
39118c2ecf20Sopenharmony_ci								lower_dev,
39128c2ecf20Sopenharmony_ci								upper_dev,
39138c2ecf20Sopenharmony_ci								extack);
39148c2ecf20Sopenharmony_ci			else
39158c2ecf20Sopenharmony_ci				mlxsw_sp_port_bridge_leave(mlxsw_sp_port,
39168c2ecf20Sopenharmony_ci							   lower_dev,
39178c2ecf20Sopenharmony_ci							   upper_dev);
39188c2ecf20Sopenharmony_ci		} else if (netif_is_lag_master(upper_dev)) {
39198c2ecf20Sopenharmony_ci			if (info->linking) {
39208c2ecf20Sopenharmony_ci				err = mlxsw_sp_port_lag_join(mlxsw_sp_port,
39218c2ecf20Sopenharmony_ci							     upper_dev);
39228c2ecf20Sopenharmony_ci			} else {
39238c2ecf20Sopenharmony_ci				mlxsw_sp_port_lag_col_dist_disable(mlxsw_sp_port);
39248c2ecf20Sopenharmony_ci				mlxsw_sp_port_lag_leave(mlxsw_sp_port,
39258c2ecf20Sopenharmony_ci							upper_dev);
39268c2ecf20Sopenharmony_ci			}
39278c2ecf20Sopenharmony_ci		} else if (netif_is_ovs_master(upper_dev)) {
39288c2ecf20Sopenharmony_ci			if (info->linking)
39298c2ecf20Sopenharmony_ci				err = mlxsw_sp_port_ovs_join(mlxsw_sp_port);
39308c2ecf20Sopenharmony_ci			else
39318c2ecf20Sopenharmony_ci				mlxsw_sp_port_ovs_leave(mlxsw_sp_port);
39328c2ecf20Sopenharmony_ci		} else if (netif_is_macvlan(upper_dev)) {
39338c2ecf20Sopenharmony_ci			if (!info->linking)
39348c2ecf20Sopenharmony_ci				mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
39358c2ecf20Sopenharmony_ci		} else if (is_vlan_dev(upper_dev)) {
39368c2ecf20Sopenharmony_ci			struct net_device *br_dev;
39378c2ecf20Sopenharmony_ci
39388c2ecf20Sopenharmony_ci			if (!netif_is_bridge_port(upper_dev))
39398c2ecf20Sopenharmony_ci				break;
39408c2ecf20Sopenharmony_ci			if (info->linking)
39418c2ecf20Sopenharmony_ci				break;
39428c2ecf20Sopenharmony_ci			br_dev = netdev_master_upper_dev_get(upper_dev);
39438c2ecf20Sopenharmony_ci			mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev,
39448c2ecf20Sopenharmony_ci						   br_dev);
39458c2ecf20Sopenharmony_ci		}
39468c2ecf20Sopenharmony_ci		break;
39478c2ecf20Sopenharmony_ci	}
39488c2ecf20Sopenharmony_ci
39498c2ecf20Sopenharmony_ci	return err;
39508c2ecf20Sopenharmony_ci}
39518c2ecf20Sopenharmony_ci
39528c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_port_lower_event(struct net_device *dev,
39538c2ecf20Sopenharmony_ci					       unsigned long event, void *ptr)
39548c2ecf20Sopenharmony_ci{
39558c2ecf20Sopenharmony_ci	struct netdev_notifier_changelowerstate_info *info;
39568c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port;
39578c2ecf20Sopenharmony_ci	int err;
39588c2ecf20Sopenharmony_ci
39598c2ecf20Sopenharmony_ci	mlxsw_sp_port = netdev_priv(dev);
39608c2ecf20Sopenharmony_ci	info = ptr;
39618c2ecf20Sopenharmony_ci
39628c2ecf20Sopenharmony_ci	switch (event) {
39638c2ecf20Sopenharmony_ci	case NETDEV_CHANGELOWERSTATE:
39648c2ecf20Sopenharmony_ci		if (netif_is_lag_port(dev) && mlxsw_sp_port->lagged) {
39658c2ecf20Sopenharmony_ci			err = mlxsw_sp_port_lag_changed(mlxsw_sp_port,
39668c2ecf20Sopenharmony_ci							info->lower_state_info);
39678c2ecf20Sopenharmony_ci			if (err)
39688c2ecf20Sopenharmony_ci				netdev_err(dev, "Failed to reflect link aggregation lower state change\n");
39698c2ecf20Sopenharmony_ci		}
39708c2ecf20Sopenharmony_ci		break;
39718c2ecf20Sopenharmony_ci	}
39728c2ecf20Sopenharmony_ci
39738c2ecf20Sopenharmony_ci	return 0;
39748c2ecf20Sopenharmony_ci}
39758c2ecf20Sopenharmony_ci
39768c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_port_event(struct net_device *lower_dev,
39778c2ecf20Sopenharmony_ci					 struct net_device *port_dev,
39788c2ecf20Sopenharmony_ci					 unsigned long event, void *ptr)
39798c2ecf20Sopenharmony_ci{
39808c2ecf20Sopenharmony_ci	switch (event) {
39818c2ecf20Sopenharmony_ci	case NETDEV_PRECHANGEUPPER:
39828c2ecf20Sopenharmony_ci	case NETDEV_CHANGEUPPER:
39838c2ecf20Sopenharmony_ci		return mlxsw_sp_netdevice_port_upper_event(lower_dev, port_dev,
39848c2ecf20Sopenharmony_ci							   event, ptr);
39858c2ecf20Sopenharmony_ci	case NETDEV_CHANGELOWERSTATE:
39868c2ecf20Sopenharmony_ci		return mlxsw_sp_netdevice_port_lower_event(port_dev, event,
39878c2ecf20Sopenharmony_ci							   ptr);
39888c2ecf20Sopenharmony_ci	}
39898c2ecf20Sopenharmony_ci
39908c2ecf20Sopenharmony_ci	return 0;
39918c2ecf20Sopenharmony_ci}
39928c2ecf20Sopenharmony_ci
39938c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev,
39948c2ecf20Sopenharmony_ci					unsigned long event, void *ptr)
39958c2ecf20Sopenharmony_ci{
39968c2ecf20Sopenharmony_ci	struct net_device *dev;
39978c2ecf20Sopenharmony_ci	struct list_head *iter;
39988c2ecf20Sopenharmony_ci	int ret;
39998c2ecf20Sopenharmony_ci
40008c2ecf20Sopenharmony_ci	netdev_for_each_lower_dev(lag_dev, dev, iter) {
40018c2ecf20Sopenharmony_ci		if (mlxsw_sp_port_dev_check(dev)) {
40028c2ecf20Sopenharmony_ci			ret = mlxsw_sp_netdevice_port_event(lag_dev, dev, event,
40038c2ecf20Sopenharmony_ci							    ptr);
40048c2ecf20Sopenharmony_ci			if (ret)
40058c2ecf20Sopenharmony_ci				return ret;
40068c2ecf20Sopenharmony_ci		}
40078c2ecf20Sopenharmony_ci	}
40088c2ecf20Sopenharmony_ci
40098c2ecf20Sopenharmony_ci	return 0;
40108c2ecf20Sopenharmony_ci}
40118c2ecf20Sopenharmony_ci
40128c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev,
40138c2ecf20Sopenharmony_ci					      struct net_device *dev,
40148c2ecf20Sopenharmony_ci					      unsigned long event, void *ptr,
40158c2ecf20Sopenharmony_ci					      u16 vid)
40168c2ecf20Sopenharmony_ci{
40178c2ecf20Sopenharmony_ci	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
40188c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
40198c2ecf20Sopenharmony_ci	struct netdev_notifier_changeupper_info *info = ptr;
40208c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack;
40218c2ecf20Sopenharmony_ci	struct net_device *upper_dev;
40228c2ecf20Sopenharmony_ci	int err = 0;
40238c2ecf20Sopenharmony_ci
40248c2ecf20Sopenharmony_ci	extack = netdev_notifier_info_to_extack(&info->info);
40258c2ecf20Sopenharmony_ci
40268c2ecf20Sopenharmony_ci	switch (event) {
40278c2ecf20Sopenharmony_ci	case NETDEV_PRECHANGEUPPER:
40288c2ecf20Sopenharmony_ci		upper_dev = info->upper_dev;
40298c2ecf20Sopenharmony_ci		if (!netif_is_bridge_master(upper_dev) &&
40308c2ecf20Sopenharmony_ci		    !netif_is_macvlan(upper_dev)) {
40318c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
40328c2ecf20Sopenharmony_ci			return -EINVAL;
40338c2ecf20Sopenharmony_ci		}
40348c2ecf20Sopenharmony_ci		if (!info->linking)
40358c2ecf20Sopenharmony_ci			break;
40368c2ecf20Sopenharmony_ci		if (netif_is_bridge_master(upper_dev) &&
40378c2ecf20Sopenharmony_ci		    !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) &&
40388c2ecf20Sopenharmony_ci		    mlxsw_sp_bridge_has_vxlan(upper_dev) &&
40398c2ecf20Sopenharmony_ci		    !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack))
40408c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
40418c2ecf20Sopenharmony_ci		if (netdev_has_any_upper_dev(upper_dev) &&
40428c2ecf20Sopenharmony_ci		    (!netif_is_bridge_master(upper_dev) ||
40438c2ecf20Sopenharmony_ci		     !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,
40448c2ecf20Sopenharmony_ci							  upper_dev))) {
40458c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Enslaving a port to a device that already has an upper device is not supported");
40468c2ecf20Sopenharmony_ci			return -EINVAL;
40478c2ecf20Sopenharmony_ci		}
40488c2ecf20Sopenharmony_ci		if (netif_is_macvlan(upper_dev) &&
40498c2ecf20Sopenharmony_ci		    !mlxsw_sp_rif_exists(mlxsw_sp, vlan_dev)) {
40508c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
40518c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
40528c2ecf20Sopenharmony_ci		}
40538c2ecf20Sopenharmony_ci		break;
40548c2ecf20Sopenharmony_ci	case NETDEV_CHANGEUPPER:
40558c2ecf20Sopenharmony_ci		upper_dev = info->upper_dev;
40568c2ecf20Sopenharmony_ci		if (netif_is_bridge_master(upper_dev)) {
40578c2ecf20Sopenharmony_ci			if (info->linking)
40588c2ecf20Sopenharmony_ci				err = mlxsw_sp_port_bridge_join(mlxsw_sp_port,
40598c2ecf20Sopenharmony_ci								vlan_dev,
40608c2ecf20Sopenharmony_ci								upper_dev,
40618c2ecf20Sopenharmony_ci								extack);
40628c2ecf20Sopenharmony_ci			else
40638c2ecf20Sopenharmony_ci				mlxsw_sp_port_bridge_leave(mlxsw_sp_port,
40648c2ecf20Sopenharmony_ci							   vlan_dev,
40658c2ecf20Sopenharmony_ci							   upper_dev);
40668c2ecf20Sopenharmony_ci		} else if (netif_is_macvlan(upper_dev)) {
40678c2ecf20Sopenharmony_ci			if (!info->linking)
40688c2ecf20Sopenharmony_ci				mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
40698c2ecf20Sopenharmony_ci		} else {
40708c2ecf20Sopenharmony_ci			err = -EINVAL;
40718c2ecf20Sopenharmony_ci			WARN_ON(1);
40728c2ecf20Sopenharmony_ci		}
40738c2ecf20Sopenharmony_ci		break;
40748c2ecf20Sopenharmony_ci	}
40758c2ecf20Sopenharmony_ci
40768c2ecf20Sopenharmony_ci	return err;
40778c2ecf20Sopenharmony_ci}
40788c2ecf20Sopenharmony_ci
40798c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_lag_port_vlan_event(struct net_device *vlan_dev,
40808c2ecf20Sopenharmony_ci						  struct net_device *lag_dev,
40818c2ecf20Sopenharmony_ci						  unsigned long event,
40828c2ecf20Sopenharmony_ci						  void *ptr, u16 vid)
40838c2ecf20Sopenharmony_ci{
40848c2ecf20Sopenharmony_ci	struct net_device *dev;
40858c2ecf20Sopenharmony_ci	struct list_head *iter;
40868c2ecf20Sopenharmony_ci	int ret;
40878c2ecf20Sopenharmony_ci
40888c2ecf20Sopenharmony_ci	netdev_for_each_lower_dev(lag_dev, dev, iter) {
40898c2ecf20Sopenharmony_ci		if (mlxsw_sp_port_dev_check(dev)) {
40908c2ecf20Sopenharmony_ci			ret = mlxsw_sp_netdevice_port_vlan_event(vlan_dev, dev,
40918c2ecf20Sopenharmony_ci								 event, ptr,
40928c2ecf20Sopenharmony_ci								 vid);
40938c2ecf20Sopenharmony_ci			if (ret)
40948c2ecf20Sopenharmony_ci				return ret;
40958c2ecf20Sopenharmony_ci		}
40968c2ecf20Sopenharmony_ci	}
40978c2ecf20Sopenharmony_ci
40988c2ecf20Sopenharmony_ci	return 0;
40998c2ecf20Sopenharmony_ci}
41008c2ecf20Sopenharmony_ci
41018c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_bridge_vlan_event(struct net_device *vlan_dev,
41028c2ecf20Sopenharmony_ci						struct net_device *br_dev,
41038c2ecf20Sopenharmony_ci						unsigned long event, void *ptr,
41048c2ecf20Sopenharmony_ci						u16 vid)
41058c2ecf20Sopenharmony_ci{
41068c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(vlan_dev);
41078c2ecf20Sopenharmony_ci	struct netdev_notifier_changeupper_info *info = ptr;
41088c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack;
41098c2ecf20Sopenharmony_ci	struct net_device *upper_dev;
41108c2ecf20Sopenharmony_ci
41118c2ecf20Sopenharmony_ci	if (!mlxsw_sp)
41128c2ecf20Sopenharmony_ci		return 0;
41138c2ecf20Sopenharmony_ci
41148c2ecf20Sopenharmony_ci	extack = netdev_notifier_info_to_extack(&info->info);
41158c2ecf20Sopenharmony_ci
41168c2ecf20Sopenharmony_ci	switch (event) {
41178c2ecf20Sopenharmony_ci	case NETDEV_PRECHANGEUPPER:
41188c2ecf20Sopenharmony_ci		upper_dev = info->upper_dev;
41198c2ecf20Sopenharmony_ci		if (!netif_is_macvlan(upper_dev)) {
41208c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
41218c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
41228c2ecf20Sopenharmony_ci		}
41238c2ecf20Sopenharmony_ci		if (!info->linking)
41248c2ecf20Sopenharmony_ci			break;
41258c2ecf20Sopenharmony_ci		if (netif_is_macvlan(upper_dev) &&
41268c2ecf20Sopenharmony_ci		    !mlxsw_sp_rif_exists(mlxsw_sp, vlan_dev)) {
41278c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
41288c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
41298c2ecf20Sopenharmony_ci		}
41308c2ecf20Sopenharmony_ci		break;
41318c2ecf20Sopenharmony_ci	case NETDEV_CHANGEUPPER:
41328c2ecf20Sopenharmony_ci		upper_dev = info->upper_dev;
41338c2ecf20Sopenharmony_ci		if (info->linking)
41348c2ecf20Sopenharmony_ci			break;
41358c2ecf20Sopenharmony_ci		if (netif_is_macvlan(upper_dev))
41368c2ecf20Sopenharmony_ci			mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
41378c2ecf20Sopenharmony_ci		break;
41388c2ecf20Sopenharmony_ci	}
41398c2ecf20Sopenharmony_ci
41408c2ecf20Sopenharmony_ci	return 0;
41418c2ecf20Sopenharmony_ci}
41428c2ecf20Sopenharmony_ci
41438c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_vlan_event(struct net_device *vlan_dev,
41448c2ecf20Sopenharmony_ci					 unsigned long event, void *ptr)
41458c2ecf20Sopenharmony_ci{
41468c2ecf20Sopenharmony_ci	struct net_device *real_dev = vlan_dev_real_dev(vlan_dev);
41478c2ecf20Sopenharmony_ci	u16 vid = vlan_dev_vlan_id(vlan_dev);
41488c2ecf20Sopenharmony_ci
41498c2ecf20Sopenharmony_ci	if (mlxsw_sp_port_dev_check(real_dev))
41508c2ecf20Sopenharmony_ci		return mlxsw_sp_netdevice_port_vlan_event(vlan_dev, real_dev,
41518c2ecf20Sopenharmony_ci							  event, ptr, vid);
41528c2ecf20Sopenharmony_ci	else if (netif_is_lag_master(real_dev))
41538c2ecf20Sopenharmony_ci		return mlxsw_sp_netdevice_lag_port_vlan_event(vlan_dev,
41548c2ecf20Sopenharmony_ci							      real_dev, event,
41558c2ecf20Sopenharmony_ci							      ptr, vid);
41568c2ecf20Sopenharmony_ci	else if (netif_is_bridge_master(real_dev))
41578c2ecf20Sopenharmony_ci		return mlxsw_sp_netdevice_bridge_vlan_event(vlan_dev, real_dev,
41588c2ecf20Sopenharmony_ci							    event, ptr, vid);
41598c2ecf20Sopenharmony_ci
41608c2ecf20Sopenharmony_ci	return 0;
41618c2ecf20Sopenharmony_ci}
41628c2ecf20Sopenharmony_ci
41638c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev,
41648c2ecf20Sopenharmony_ci					   unsigned long event, void *ptr)
41658c2ecf20Sopenharmony_ci{
41668c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(br_dev);
41678c2ecf20Sopenharmony_ci	struct netdev_notifier_changeupper_info *info = ptr;
41688c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack;
41698c2ecf20Sopenharmony_ci	struct net_device *upper_dev;
41708c2ecf20Sopenharmony_ci
41718c2ecf20Sopenharmony_ci	if (!mlxsw_sp)
41728c2ecf20Sopenharmony_ci		return 0;
41738c2ecf20Sopenharmony_ci
41748c2ecf20Sopenharmony_ci	extack = netdev_notifier_info_to_extack(&info->info);
41758c2ecf20Sopenharmony_ci
41768c2ecf20Sopenharmony_ci	switch (event) {
41778c2ecf20Sopenharmony_ci	case NETDEV_PRECHANGEUPPER:
41788c2ecf20Sopenharmony_ci		upper_dev = info->upper_dev;
41798c2ecf20Sopenharmony_ci		if (!is_vlan_dev(upper_dev) && !netif_is_macvlan(upper_dev)) {
41808c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
41818c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
41828c2ecf20Sopenharmony_ci		}
41838c2ecf20Sopenharmony_ci		if (!info->linking)
41848c2ecf20Sopenharmony_ci			break;
41858c2ecf20Sopenharmony_ci		if (netif_is_macvlan(upper_dev) &&
41868c2ecf20Sopenharmony_ci		    !mlxsw_sp_rif_exists(mlxsw_sp, br_dev)) {
41878c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "macvlan is only supported on top of router interfaces");
41888c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
41898c2ecf20Sopenharmony_ci		}
41908c2ecf20Sopenharmony_ci		break;
41918c2ecf20Sopenharmony_ci	case NETDEV_CHANGEUPPER:
41928c2ecf20Sopenharmony_ci		upper_dev = info->upper_dev;
41938c2ecf20Sopenharmony_ci		if (info->linking)
41948c2ecf20Sopenharmony_ci			break;
41958c2ecf20Sopenharmony_ci		if (is_vlan_dev(upper_dev))
41968c2ecf20Sopenharmony_ci			mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, upper_dev);
41978c2ecf20Sopenharmony_ci		if (netif_is_macvlan(upper_dev))
41988c2ecf20Sopenharmony_ci			mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);
41998c2ecf20Sopenharmony_ci		break;
42008c2ecf20Sopenharmony_ci	}
42018c2ecf20Sopenharmony_ci
42028c2ecf20Sopenharmony_ci	return 0;
42038c2ecf20Sopenharmony_ci}
42048c2ecf20Sopenharmony_ci
42058c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_macvlan_event(struct net_device *macvlan_dev,
42068c2ecf20Sopenharmony_ci					    unsigned long event, void *ptr)
42078c2ecf20Sopenharmony_ci{
42088c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(macvlan_dev);
42098c2ecf20Sopenharmony_ci	struct netdev_notifier_changeupper_info *info = ptr;
42108c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack;
42118c2ecf20Sopenharmony_ci
42128c2ecf20Sopenharmony_ci	if (!mlxsw_sp || event != NETDEV_PRECHANGEUPPER)
42138c2ecf20Sopenharmony_ci		return 0;
42148c2ecf20Sopenharmony_ci
42158c2ecf20Sopenharmony_ci	extack = netdev_notifier_info_to_extack(&info->info);
42168c2ecf20Sopenharmony_ci
42178c2ecf20Sopenharmony_ci	/* VRF enslavement is handled in mlxsw_sp_netdevice_vrf_event() */
42188c2ecf20Sopenharmony_ci	NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");
42198c2ecf20Sopenharmony_ci
42208c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
42218c2ecf20Sopenharmony_ci}
42228c2ecf20Sopenharmony_ci
42238c2ecf20Sopenharmony_cistatic bool mlxsw_sp_is_vrf_event(unsigned long event, void *ptr)
42248c2ecf20Sopenharmony_ci{
42258c2ecf20Sopenharmony_ci	struct netdev_notifier_changeupper_info *info = ptr;
42268c2ecf20Sopenharmony_ci
42278c2ecf20Sopenharmony_ci	if (event != NETDEV_PRECHANGEUPPER && event != NETDEV_CHANGEUPPER)
42288c2ecf20Sopenharmony_ci		return false;
42298c2ecf20Sopenharmony_ci	return netif_is_l3_master(info->upper_dev);
42308c2ecf20Sopenharmony_ci}
42318c2ecf20Sopenharmony_ci
42328c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_vxlan_event(struct mlxsw_sp *mlxsw_sp,
42338c2ecf20Sopenharmony_ci					  struct net_device *dev,
42348c2ecf20Sopenharmony_ci					  unsigned long event, void *ptr)
42358c2ecf20Sopenharmony_ci{
42368c2ecf20Sopenharmony_ci	struct netdev_notifier_changeupper_info *cu_info;
42378c2ecf20Sopenharmony_ci	struct netdev_notifier_info *info = ptr;
42388c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack;
42398c2ecf20Sopenharmony_ci	struct net_device *upper_dev;
42408c2ecf20Sopenharmony_ci
42418c2ecf20Sopenharmony_ci	extack = netdev_notifier_info_to_extack(info);
42428c2ecf20Sopenharmony_ci
42438c2ecf20Sopenharmony_ci	switch (event) {
42448c2ecf20Sopenharmony_ci	case NETDEV_CHANGEUPPER:
42458c2ecf20Sopenharmony_ci		cu_info = container_of(info,
42468c2ecf20Sopenharmony_ci				       struct netdev_notifier_changeupper_info,
42478c2ecf20Sopenharmony_ci				       info);
42488c2ecf20Sopenharmony_ci		upper_dev = cu_info->upper_dev;
42498c2ecf20Sopenharmony_ci		if (!netif_is_bridge_master(upper_dev))
42508c2ecf20Sopenharmony_ci			return 0;
42518c2ecf20Sopenharmony_ci		if (!mlxsw_sp_lower_get(upper_dev))
42528c2ecf20Sopenharmony_ci			return 0;
42538c2ecf20Sopenharmony_ci		if (!mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack))
42548c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
42558c2ecf20Sopenharmony_ci		if (cu_info->linking) {
42568c2ecf20Sopenharmony_ci			if (!netif_running(dev))
42578c2ecf20Sopenharmony_ci				return 0;
42588c2ecf20Sopenharmony_ci			/* When the bridge is VLAN-aware, the VNI of the VxLAN
42598c2ecf20Sopenharmony_ci			 * device needs to be mapped to a VLAN, but at this
42608c2ecf20Sopenharmony_ci			 * point no VLANs are configured on the VxLAN device
42618c2ecf20Sopenharmony_ci			 */
42628c2ecf20Sopenharmony_ci			if (br_vlan_enabled(upper_dev))
42638c2ecf20Sopenharmony_ci				return 0;
42648c2ecf20Sopenharmony_ci			return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev,
42658c2ecf20Sopenharmony_ci							  dev, 0, extack);
42668c2ecf20Sopenharmony_ci		} else {
42678c2ecf20Sopenharmony_ci			/* VLANs were already flushed, which triggered the
42688c2ecf20Sopenharmony_ci			 * necessary cleanup
42698c2ecf20Sopenharmony_ci			 */
42708c2ecf20Sopenharmony_ci			if (br_vlan_enabled(upper_dev))
42718c2ecf20Sopenharmony_ci				return 0;
42728c2ecf20Sopenharmony_ci			mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev);
42738c2ecf20Sopenharmony_ci		}
42748c2ecf20Sopenharmony_ci		break;
42758c2ecf20Sopenharmony_ci	case NETDEV_PRE_UP:
42768c2ecf20Sopenharmony_ci		upper_dev = netdev_master_upper_dev_get(dev);
42778c2ecf20Sopenharmony_ci		if (!upper_dev)
42788c2ecf20Sopenharmony_ci			return 0;
42798c2ecf20Sopenharmony_ci		if (!netif_is_bridge_master(upper_dev))
42808c2ecf20Sopenharmony_ci			return 0;
42818c2ecf20Sopenharmony_ci		if (!mlxsw_sp_lower_get(upper_dev))
42828c2ecf20Sopenharmony_ci			return 0;
42838c2ecf20Sopenharmony_ci		return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, dev, 0,
42848c2ecf20Sopenharmony_ci						  extack);
42858c2ecf20Sopenharmony_ci	case NETDEV_DOWN:
42868c2ecf20Sopenharmony_ci		upper_dev = netdev_master_upper_dev_get(dev);
42878c2ecf20Sopenharmony_ci		if (!upper_dev)
42888c2ecf20Sopenharmony_ci			return 0;
42898c2ecf20Sopenharmony_ci		if (!netif_is_bridge_master(upper_dev))
42908c2ecf20Sopenharmony_ci			return 0;
42918c2ecf20Sopenharmony_ci		if (!mlxsw_sp_lower_get(upper_dev))
42928c2ecf20Sopenharmony_ci			return 0;
42938c2ecf20Sopenharmony_ci		mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev);
42948c2ecf20Sopenharmony_ci		break;
42958c2ecf20Sopenharmony_ci	}
42968c2ecf20Sopenharmony_ci
42978c2ecf20Sopenharmony_ci	return 0;
42988c2ecf20Sopenharmony_ci}
42998c2ecf20Sopenharmony_ci
43008c2ecf20Sopenharmony_cistatic int mlxsw_sp_netdevice_event(struct notifier_block *nb,
43018c2ecf20Sopenharmony_ci				    unsigned long event, void *ptr)
43028c2ecf20Sopenharmony_ci{
43038c2ecf20Sopenharmony_ci	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
43048c2ecf20Sopenharmony_ci	struct mlxsw_sp_span_entry *span_entry;
43058c2ecf20Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp;
43068c2ecf20Sopenharmony_ci	int err = 0;
43078c2ecf20Sopenharmony_ci
43088c2ecf20Sopenharmony_ci	mlxsw_sp = container_of(nb, struct mlxsw_sp, netdevice_nb);
43098c2ecf20Sopenharmony_ci	if (event == NETDEV_UNREGISTER) {
43108c2ecf20Sopenharmony_ci		span_entry = mlxsw_sp_span_entry_find_by_port(mlxsw_sp, dev);
43118c2ecf20Sopenharmony_ci		if (span_entry)
43128c2ecf20Sopenharmony_ci			mlxsw_sp_span_entry_invalidate(mlxsw_sp, span_entry);
43138c2ecf20Sopenharmony_ci	}
43148c2ecf20Sopenharmony_ci	mlxsw_sp_span_respin(mlxsw_sp);
43158c2ecf20Sopenharmony_ci
43168c2ecf20Sopenharmony_ci	if (netif_is_vxlan(dev))
43178c2ecf20Sopenharmony_ci		err = mlxsw_sp_netdevice_vxlan_event(mlxsw_sp, dev, event, ptr);
43188c2ecf20Sopenharmony_ci	if (mlxsw_sp_netdev_is_ipip_ol(mlxsw_sp, dev))
43198c2ecf20Sopenharmony_ci		err = mlxsw_sp_netdevice_ipip_ol_event(mlxsw_sp, dev,
43208c2ecf20Sopenharmony_ci						       event, ptr);
43218c2ecf20Sopenharmony_ci	else if (mlxsw_sp_netdev_is_ipip_ul(mlxsw_sp, dev))
43228c2ecf20Sopenharmony_ci		err = mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, dev,
43238c2ecf20Sopenharmony_ci						       event, ptr);
43248c2ecf20Sopenharmony_ci	else if (event == NETDEV_PRE_CHANGEADDR ||
43258c2ecf20Sopenharmony_ci		 event == NETDEV_CHANGEADDR ||
43268c2ecf20Sopenharmony_ci		 event == NETDEV_CHANGEMTU)
43278c2ecf20Sopenharmony_ci		err = mlxsw_sp_netdevice_router_port_event(dev, event, ptr);
43288c2ecf20Sopenharmony_ci	else if (mlxsw_sp_is_vrf_event(event, ptr))
43298c2ecf20Sopenharmony_ci		err = mlxsw_sp_netdevice_vrf_event(dev, event, ptr);
43308c2ecf20Sopenharmony_ci	else if (mlxsw_sp_port_dev_check(dev))
43318c2ecf20Sopenharmony_ci		err = mlxsw_sp_netdevice_port_event(dev, dev, event, ptr);
43328c2ecf20Sopenharmony_ci	else if (netif_is_lag_master(dev))
43338c2ecf20Sopenharmony_ci		err = mlxsw_sp_netdevice_lag_event(dev, event, ptr);
43348c2ecf20Sopenharmony_ci	else if (is_vlan_dev(dev))
43358c2ecf20Sopenharmony_ci		err = mlxsw_sp_netdevice_vlan_event(dev, event, ptr);
43368c2ecf20Sopenharmony_ci	else if (netif_is_bridge_master(dev))
43378c2ecf20Sopenharmony_ci		err = mlxsw_sp_netdevice_bridge_event(dev, event, ptr);
43388c2ecf20Sopenharmony_ci	else if (netif_is_macvlan(dev))
43398c2ecf20Sopenharmony_ci		err = mlxsw_sp_netdevice_macvlan_event(dev, event, ptr);
43408c2ecf20Sopenharmony_ci
43418c2ecf20Sopenharmony_ci	return notifier_from_errno(err);
43428c2ecf20Sopenharmony_ci}
43438c2ecf20Sopenharmony_ci
43448c2ecf20Sopenharmony_cistatic struct notifier_block mlxsw_sp_inetaddr_valid_nb __read_mostly = {
43458c2ecf20Sopenharmony_ci	.notifier_call = mlxsw_sp_inetaddr_valid_event,
43468c2ecf20Sopenharmony_ci};
43478c2ecf20Sopenharmony_ci
43488c2ecf20Sopenharmony_cistatic struct notifier_block mlxsw_sp_inet6addr_valid_nb __read_mostly = {
43498c2ecf20Sopenharmony_ci	.notifier_call = mlxsw_sp_inet6addr_valid_event,
43508c2ecf20Sopenharmony_ci};
43518c2ecf20Sopenharmony_ci
43528c2ecf20Sopenharmony_cistatic const struct pci_device_id mlxsw_sp1_pci_id_table[] = {
43538c2ecf20Sopenharmony_ci	{PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM), 0},
43548c2ecf20Sopenharmony_ci	{0, },
43558c2ecf20Sopenharmony_ci};
43568c2ecf20Sopenharmony_ci
43578c2ecf20Sopenharmony_cistatic struct pci_driver mlxsw_sp1_pci_driver = {
43588c2ecf20Sopenharmony_ci	.name = mlxsw_sp1_driver_name,
43598c2ecf20Sopenharmony_ci	.id_table = mlxsw_sp1_pci_id_table,
43608c2ecf20Sopenharmony_ci};
43618c2ecf20Sopenharmony_ci
43628c2ecf20Sopenharmony_cistatic const struct pci_device_id mlxsw_sp2_pci_id_table[] = {
43638c2ecf20Sopenharmony_ci	{PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM2), 0},
43648c2ecf20Sopenharmony_ci	{0, },
43658c2ecf20Sopenharmony_ci};
43668c2ecf20Sopenharmony_ci
43678c2ecf20Sopenharmony_cistatic struct pci_driver mlxsw_sp2_pci_driver = {
43688c2ecf20Sopenharmony_ci	.name = mlxsw_sp2_driver_name,
43698c2ecf20Sopenharmony_ci	.id_table = mlxsw_sp2_pci_id_table,
43708c2ecf20Sopenharmony_ci};
43718c2ecf20Sopenharmony_ci
43728c2ecf20Sopenharmony_cistatic const struct pci_device_id mlxsw_sp3_pci_id_table[] = {
43738c2ecf20Sopenharmony_ci	{PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM3), 0},
43748c2ecf20Sopenharmony_ci	{0, },
43758c2ecf20Sopenharmony_ci};
43768c2ecf20Sopenharmony_ci
43778c2ecf20Sopenharmony_cistatic struct pci_driver mlxsw_sp3_pci_driver = {
43788c2ecf20Sopenharmony_ci	.name = mlxsw_sp3_driver_name,
43798c2ecf20Sopenharmony_ci	.id_table = mlxsw_sp3_pci_id_table,
43808c2ecf20Sopenharmony_ci};
43818c2ecf20Sopenharmony_ci
43828c2ecf20Sopenharmony_cistatic int __init mlxsw_sp_module_init(void)
43838c2ecf20Sopenharmony_ci{
43848c2ecf20Sopenharmony_ci	int err;
43858c2ecf20Sopenharmony_ci
43868c2ecf20Sopenharmony_ci	register_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb);
43878c2ecf20Sopenharmony_ci	register_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb);
43888c2ecf20Sopenharmony_ci
43898c2ecf20Sopenharmony_ci	err = mlxsw_core_driver_register(&mlxsw_sp1_driver);
43908c2ecf20Sopenharmony_ci	if (err)
43918c2ecf20Sopenharmony_ci		goto err_sp1_core_driver_register;
43928c2ecf20Sopenharmony_ci
43938c2ecf20Sopenharmony_ci	err = mlxsw_core_driver_register(&mlxsw_sp2_driver);
43948c2ecf20Sopenharmony_ci	if (err)
43958c2ecf20Sopenharmony_ci		goto err_sp2_core_driver_register;
43968c2ecf20Sopenharmony_ci
43978c2ecf20Sopenharmony_ci	err = mlxsw_core_driver_register(&mlxsw_sp3_driver);
43988c2ecf20Sopenharmony_ci	if (err)
43998c2ecf20Sopenharmony_ci		goto err_sp3_core_driver_register;
44008c2ecf20Sopenharmony_ci
44018c2ecf20Sopenharmony_ci	err = mlxsw_pci_driver_register(&mlxsw_sp1_pci_driver);
44028c2ecf20Sopenharmony_ci	if (err)
44038c2ecf20Sopenharmony_ci		goto err_sp1_pci_driver_register;
44048c2ecf20Sopenharmony_ci
44058c2ecf20Sopenharmony_ci	err = mlxsw_pci_driver_register(&mlxsw_sp2_pci_driver);
44068c2ecf20Sopenharmony_ci	if (err)
44078c2ecf20Sopenharmony_ci		goto err_sp2_pci_driver_register;
44088c2ecf20Sopenharmony_ci
44098c2ecf20Sopenharmony_ci	err = mlxsw_pci_driver_register(&mlxsw_sp3_pci_driver);
44108c2ecf20Sopenharmony_ci	if (err)
44118c2ecf20Sopenharmony_ci		goto err_sp3_pci_driver_register;
44128c2ecf20Sopenharmony_ci
44138c2ecf20Sopenharmony_ci	return 0;
44148c2ecf20Sopenharmony_ci
44158c2ecf20Sopenharmony_cierr_sp3_pci_driver_register:
44168c2ecf20Sopenharmony_ci	mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver);
44178c2ecf20Sopenharmony_cierr_sp2_pci_driver_register:
44188c2ecf20Sopenharmony_ci	mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver);
44198c2ecf20Sopenharmony_cierr_sp1_pci_driver_register:
44208c2ecf20Sopenharmony_ci	mlxsw_core_driver_unregister(&mlxsw_sp3_driver);
44218c2ecf20Sopenharmony_cierr_sp3_core_driver_register:
44228c2ecf20Sopenharmony_ci	mlxsw_core_driver_unregister(&mlxsw_sp2_driver);
44238c2ecf20Sopenharmony_cierr_sp2_core_driver_register:
44248c2ecf20Sopenharmony_ci	mlxsw_core_driver_unregister(&mlxsw_sp1_driver);
44258c2ecf20Sopenharmony_cierr_sp1_core_driver_register:
44268c2ecf20Sopenharmony_ci	unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb);
44278c2ecf20Sopenharmony_ci	unregister_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb);
44288c2ecf20Sopenharmony_ci	return err;
44298c2ecf20Sopenharmony_ci}
44308c2ecf20Sopenharmony_ci
44318c2ecf20Sopenharmony_cistatic void __exit mlxsw_sp_module_exit(void)
44328c2ecf20Sopenharmony_ci{
44338c2ecf20Sopenharmony_ci	mlxsw_pci_driver_unregister(&mlxsw_sp3_pci_driver);
44348c2ecf20Sopenharmony_ci	mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver);
44358c2ecf20Sopenharmony_ci	mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver);
44368c2ecf20Sopenharmony_ci	mlxsw_core_driver_unregister(&mlxsw_sp3_driver);
44378c2ecf20Sopenharmony_ci	mlxsw_core_driver_unregister(&mlxsw_sp2_driver);
44388c2ecf20Sopenharmony_ci	mlxsw_core_driver_unregister(&mlxsw_sp1_driver);
44398c2ecf20Sopenharmony_ci	unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb);
44408c2ecf20Sopenharmony_ci	unregister_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb);
44418c2ecf20Sopenharmony_ci}
44428c2ecf20Sopenharmony_ci
44438c2ecf20Sopenharmony_cimodule_init(mlxsw_sp_module_init);
44448c2ecf20Sopenharmony_cimodule_exit(mlxsw_sp_module_exit);
44458c2ecf20Sopenharmony_ci
44468c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
44478c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
44488c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Mellanox Spectrum driver");
44498c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mlxsw_sp1_pci_id_table);
44508c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mlxsw_sp2_pci_id_table);
44518c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mlxsw_sp3_pci_id_table);
44528c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MLXSW_SP1_FW_FILENAME);
44538c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MLXSW_SP2_FW_FILENAME);
44548c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MLXSW_SP3_FW_FILENAME);
4455