brintos

brintos / linux-shallow public Read only

0
0
Text · 156.5 KiB · 3f5e5d9 Raw
5557 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */3 4#include <linux/kernel.h>5#include <linux/module.h>6#include <linux/types.h>7#include <linux/pci.h>8#include <linux/netdevice.h>9#include <linux/etherdevice.h>10#include <linux/ethtool.h>11#include <linux/slab.h>12#include <linux/device.h>13#include <linux/skbuff.h>14#include <linux/if_vlan.h>15#include <linux/if_bridge.h>16#include <linux/workqueue.h>17#include <linux/jiffies.h>18#include <linux/bitops.h>19#include <linux/list.h>20#include <linux/notifier.h>21#include <linux/dcbnl.h>22#include <linux/inetdevice.h>23#include <linux/netlink.h>24#include <linux/jhash.h>25#include <linux/log2.h>26#include <linux/refcount.h>27#include <linux/rhashtable.h>28#include <net/switchdev.h>29#include <net/pkt_cls.h>30#include <net/netevent.h>31#include <net/addrconf.h>32#include <linux/ptp_classify.h>33 34#include "spectrum.h"35#include "pci.h"36#include "core.h"37#include "core_env.h"38#include "reg.h"39#include "port.h"40#include "trap.h"41#include "txheader.h"42#include "spectrum_cnt.h"43#include "spectrum_dpipe.h"44#include "spectrum_acl_flex_actions.h"45#include "spectrum_span.h"46#include "spectrum_ptp.h"47#include "spectrum_trap.h"48 49#define MLXSW_SP_FWREV_MINOR 201050#define MLXSW_SP_FWREV_SUBMINOR 100651 52#define MLXSW_SP1_FWREV_MAJOR 1353#define MLXSW_SP1_FWREV_CAN_RESET_MINOR 170254 55static const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = {56	.major = MLXSW_SP1_FWREV_MAJOR,57	.minor = MLXSW_SP_FWREV_MINOR,58	.subminor = MLXSW_SP_FWREV_SUBMINOR,59	.can_reset_minor = MLXSW_SP1_FWREV_CAN_RESET_MINOR,60};61 62#define MLXSW_SP1_FW_FILENAME \63	"mellanox/mlxsw_spectrum-" __stringify(MLXSW_SP1_FWREV_MAJOR) \64	"." __stringify(MLXSW_SP_FWREV_MINOR) \65	"." __stringify(MLXSW_SP_FWREV_SUBMINOR) ".mfa2"66 67#define MLXSW_SP2_FWREV_MAJOR 2968 69static const struct mlxsw_fw_rev mlxsw_sp2_fw_rev = {70	.major = MLXSW_SP2_FWREV_MAJOR,71	.minor = MLXSW_SP_FWREV_MINOR,72	.subminor = MLXSW_SP_FWREV_SUBMINOR,73};74 75#define MLXSW_SP2_FW_FILENAME \76	"mellanox/mlxsw_spectrum2-" __stringify(MLXSW_SP2_FWREV_MAJOR) \77	"." __stringify(MLXSW_SP_FWREV_MINOR) \78	"." __stringify(MLXSW_SP_FWREV_SUBMINOR) ".mfa2"79 80#define MLXSW_SP3_FWREV_MAJOR 3081 82static const struct mlxsw_fw_rev mlxsw_sp3_fw_rev = {83	.major = MLXSW_SP3_FWREV_MAJOR,84	.minor = MLXSW_SP_FWREV_MINOR,85	.subminor = MLXSW_SP_FWREV_SUBMINOR,86};87 88#define MLXSW_SP3_FW_FILENAME \89	"mellanox/mlxsw_spectrum3-" __stringify(MLXSW_SP3_FWREV_MAJOR) \90	"." __stringify(MLXSW_SP_FWREV_MINOR) \91	"." __stringify(MLXSW_SP_FWREV_SUBMINOR) ".mfa2"92 93#define MLXSW_SP_LINECARDS_INI_BUNDLE_FILENAME \94	"mellanox/lc_ini_bundle_" \95	__stringify(MLXSW_SP_FWREV_MINOR) "_" \96	__stringify(MLXSW_SP_FWREV_SUBMINOR) ".bin"97 98static const char mlxsw_sp1_driver_name[] = "mlxsw_spectrum";99static const char mlxsw_sp2_driver_name[] = "mlxsw_spectrum2";100static const char mlxsw_sp3_driver_name[] = "mlxsw_spectrum3";101static const char mlxsw_sp4_driver_name[] = "mlxsw_spectrum4";102 103static const unsigned char mlxsw_sp1_mac_mask[ETH_ALEN] = {104	0xff, 0xff, 0xff, 0xff, 0xfc, 0x00105};106static const unsigned char mlxsw_sp2_mac_mask[ETH_ALEN] = {107	0xff, 0xff, 0xff, 0xff, 0xf0, 0x00108};109 110/* tx_hdr_version111 * Tx header version.112 * Must be set to 1.113 */114MLXSW_ITEM32(tx, hdr, version, 0x00, 28, 4);115 116/* tx_hdr_ctl117 * Packet control type.118 * 0 - Ethernet control (e.g. EMADs, LACP)119 * 1 - Ethernet data120 */121MLXSW_ITEM32(tx, hdr, ctl, 0x00, 26, 2);122 123/* tx_hdr_proto124 * Packet protocol type. Must be set to 1 (Ethernet).125 */126MLXSW_ITEM32(tx, hdr, proto, 0x00, 21, 3);127 128/* tx_hdr_rx_is_router129 * Packet is sent from the router. Valid for data packets only.130 */131MLXSW_ITEM32(tx, hdr, rx_is_router, 0x00, 19, 1);132 133/* tx_hdr_fid_valid134 * Indicates if the 'fid' field is valid and should be used for135 * forwarding lookup. Valid for data packets only.136 */137MLXSW_ITEM32(tx, hdr, fid_valid, 0x00, 16, 1);138 139/* tx_hdr_swid140 * Switch partition ID. Must be set to 0.141 */142MLXSW_ITEM32(tx, hdr, swid, 0x00, 12, 3);143 144/* tx_hdr_control_tclass145 * Indicates if the packet should use the control TClass and not one146 * of the data TClasses.147 */148MLXSW_ITEM32(tx, hdr, control_tclass, 0x00, 6, 1);149 150/* tx_hdr_etclass151 * Egress TClass to be used on the egress device on the egress port.152 */153MLXSW_ITEM32(tx, hdr, etclass, 0x00, 0, 4);154 155/* tx_hdr_port_mid156 * Destination local port for unicast packets.157 * Destination multicast ID for multicast packets.158 *159 * Control packets are directed to a specific egress port, while data160 * packets are transmitted through the CPU port (0) into the switch partition,161 * where forwarding rules are applied.162 */163MLXSW_ITEM32(tx, hdr, port_mid, 0x04, 16, 16);164 165/* tx_hdr_fid166 * Forwarding ID used for L2 forwarding lookup. Valid only if 'fid_valid' is167 * set, otherwise calculated based on the packet's VID using VID to FID mapping.168 * Valid for data packets only.169 */170MLXSW_ITEM32(tx, hdr, fid, 0x08, 16, 16);171 172/* tx_hdr_type173 * 0 - Data packets174 * 6 - Control packets175 */176MLXSW_ITEM32(tx, hdr, type, 0x0C, 0, 4);177 178int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp,179			      unsigned int counter_index, bool clear,180			      u64 *packets, u64 *bytes)181{182	enum mlxsw_reg_mgpc_opcode op = clear ? MLXSW_REG_MGPC_OPCODE_CLEAR :183						MLXSW_REG_MGPC_OPCODE_NOP;184	char mgpc_pl[MLXSW_REG_MGPC_LEN];185	int err;186 187	mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, op,188			    MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES);189	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl);190	if (err)191		return err;192	if (packets)193		*packets = mlxsw_reg_mgpc_packet_counter_get(mgpc_pl);194	if (bytes)195		*bytes = mlxsw_reg_mgpc_byte_counter_get(mgpc_pl);196	return 0;197}198 199static int mlxsw_sp_flow_counter_clear(struct mlxsw_sp *mlxsw_sp,200				       unsigned int counter_index)201{202	char mgpc_pl[MLXSW_REG_MGPC_LEN];203 204	mlxsw_reg_mgpc_pack(mgpc_pl, counter_index, MLXSW_REG_MGPC_OPCODE_CLEAR,205			    MLXSW_REG_FLOW_COUNTER_SET_TYPE_PACKETS_BYTES);206	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mgpc), mgpc_pl);207}208 209int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp,210				unsigned int *p_counter_index)211{212	int err;213 214	err = mlxsw_sp_counter_alloc(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW,215				     p_counter_index);216	if (err)217		return err;218	err = mlxsw_sp_flow_counter_clear(mlxsw_sp, *p_counter_index);219	if (err)220		goto err_counter_clear;221	return 0;222 223err_counter_clear:224	mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW,225			      *p_counter_index);226	return err;227}228 229void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp,230				unsigned int counter_index)231{232	 mlxsw_sp_counter_free(mlxsw_sp, MLXSW_SP_COUNTER_SUB_POOL_FLOW,233			       counter_index);234}235 236void mlxsw_sp_txhdr_construct(struct sk_buff *skb,237			      const struct mlxsw_tx_info *tx_info)238{239	char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN);240 241	memset(txhdr, 0, MLXSW_TXHDR_LEN);242 243	mlxsw_tx_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1);244	mlxsw_tx_hdr_ctl_set(txhdr, MLXSW_TXHDR_ETH_CTL);245	mlxsw_tx_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH);246	mlxsw_tx_hdr_swid_set(txhdr, 0);247	mlxsw_tx_hdr_control_tclass_set(txhdr, 1);248	mlxsw_tx_hdr_port_mid_set(txhdr, tx_info->local_port);249	mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL);250}251 252int253mlxsw_sp_txhdr_ptp_data_construct(struct mlxsw_core *mlxsw_core,254				  struct mlxsw_sp_port *mlxsw_sp_port,255				  struct sk_buff *skb,256				  const struct mlxsw_tx_info *tx_info)257{258	char *txhdr;259	u16 max_fid;260	int err;261 262	if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {263		err = -ENOMEM;264		goto err_skb_cow_head;265	}266 267	if (!MLXSW_CORE_RES_VALID(mlxsw_core, FID)) {268		err = -EIO;269		goto err_res_valid;270	}271	max_fid = MLXSW_CORE_RES_GET(mlxsw_core, FID);272 273	txhdr = skb_push(skb, MLXSW_TXHDR_LEN);274	memset(txhdr, 0, MLXSW_TXHDR_LEN);275 276	mlxsw_tx_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_1);277	mlxsw_tx_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH);278	mlxsw_tx_hdr_rx_is_router_set(txhdr, true);279	mlxsw_tx_hdr_fid_valid_set(txhdr, true);280	mlxsw_tx_hdr_fid_set(txhdr, max_fid + tx_info->local_port - 1);281	mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_DATA);282	return 0;283 284err_res_valid:285err_skb_cow_head:286	this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);287	dev_kfree_skb_any(skb);288	return err;289}290 291static bool mlxsw_sp_skb_requires_ts(struct sk_buff *skb)292{293	unsigned int type;294 295	if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))296		return false;297 298	type = ptp_classify_raw(skb);299	return !!ptp_parse_header(skb, type);300}301 302static int mlxsw_sp_txhdr_handle(struct mlxsw_core *mlxsw_core,303				 struct mlxsw_sp_port *mlxsw_sp_port,304				 struct sk_buff *skb,305				 const struct mlxsw_tx_info *tx_info)306{307	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);308 309	/* In Spectrum-2 and Spectrum-3, PTP events that require a time stamp310	 * need special handling and cannot be transmitted as regular control311	 * packets.312	 */313	if (unlikely(mlxsw_sp_skb_requires_ts(skb)))314		return mlxsw_sp->ptp_ops->txhdr_construct(mlxsw_core,315							  mlxsw_sp_port, skb,316							  tx_info);317 318	if (skb_cow_head(skb, MLXSW_TXHDR_LEN)) {319		this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);320		dev_kfree_skb_any(skb);321		return -ENOMEM;322	}323 324	mlxsw_sp_txhdr_construct(skb, tx_info);325	return 0;326}327 328enum mlxsw_reg_spms_state mlxsw_sp_stp_spms_state(u8 state)329{330	switch (state) {331	case BR_STATE_FORWARDING:332		return MLXSW_REG_SPMS_STATE_FORWARDING;333	case BR_STATE_LEARNING:334		return MLXSW_REG_SPMS_STATE_LEARNING;335	case BR_STATE_LISTENING:336	case BR_STATE_DISABLED:337	case BR_STATE_BLOCKING:338		return MLXSW_REG_SPMS_STATE_DISCARDING;339	default:340		BUG();341	}342}343 344int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,345			      u8 state)346{347	enum mlxsw_reg_spms_state spms_state = mlxsw_sp_stp_spms_state(state);348	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;349	char *spms_pl;350	int err;351 352	spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL);353	if (!spms_pl)354		return -ENOMEM;355	mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port);356	mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state);357 358	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl);359	kfree(spms_pl);360	return err;361}362 363static int mlxsw_sp_base_mac_get(struct mlxsw_sp *mlxsw_sp)364{365	char spad_pl[MLXSW_REG_SPAD_LEN] = {0};366	int err;367 368	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(spad), spad_pl);369	if (err)370		return err;371	mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_sp->base_mac);372	return 0;373}374 375int mlxsw_sp_port_admin_status_set(struct mlxsw_sp_port *mlxsw_sp_port,376				   bool is_up)377{378	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;379	char paos_pl[MLXSW_REG_PAOS_LEN];380 381	mlxsw_reg_paos_pack(paos_pl, mlxsw_sp_port->local_port,382			    is_up ? MLXSW_PORT_ADMIN_STATUS_UP :383			    MLXSW_PORT_ADMIN_STATUS_DOWN);384	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(paos), paos_pl);385}386 387static int mlxsw_sp_port_dev_addr_set(struct mlxsw_sp_port *mlxsw_sp_port,388				      const unsigned char *addr)389{390	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;391	char ppad_pl[MLXSW_REG_PPAD_LEN];392 393	mlxsw_reg_ppad_pack(ppad_pl, true, mlxsw_sp_port->local_port);394	mlxsw_reg_ppad_mac_memcpy_to(ppad_pl, addr);395	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ppad), ppad_pl);396}397 398static int mlxsw_sp_port_dev_addr_init(struct mlxsw_sp_port *mlxsw_sp_port)399{400	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;401 402	eth_hw_addr_gen(mlxsw_sp_port->dev, mlxsw_sp->base_mac,403			mlxsw_sp_port->local_port);404	return mlxsw_sp_port_dev_addr_set(mlxsw_sp_port,405					  mlxsw_sp_port->dev->dev_addr);406}407 408static int mlxsw_sp_port_mtu_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mtu)409{410	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;411	char pmtu_pl[MLXSW_REG_PMTU_LEN];412 413	mtu += MLXSW_PORT_ETH_FRAME_HDR;414 415	mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sp_port->local_port, mtu);416	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmtu), pmtu_pl);417}418 419static int mlxsw_sp_port_swid_set(struct mlxsw_sp *mlxsw_sp,420				  u16 local_port, u8 swid)421{422	char pspa_pl[MLXSW_REG_PSPA_LEN];423 424	mlxsw_reg_pspa_pack(pspa_pl, swid, local_port);425	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pspa), pspa_pl);426}427 428int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable)429{430	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;431	char svpe_pl[MLXSW_REG_SVPE_LEN];432 433	mlxsw_reg_svpe_pack(svpe_pl, mlxsw_sp_port->local_port, enable);434	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svpe), svpe_pl);435}436 437int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,438				   bool learn_enable)439{440	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;441	char *spvmlr_pl;442	int err;443 444	spvmlr_pl = kmalloc(MLXSW_REG_SPVMLR_LEN, GFP_KERNEL);445	if (!spvmlr_pl)446		return -ENOMEM;447	mlxsw_reg_spvmlr_pack(spvmlr_pl, mlxsw_sp_port->local_port, vid, vid,448			      learn_enable);449	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvmlr), spvmlr_pl);450	kfree(spvmlr_pl);451	return err;452}453 454int mlxsw_sp_port_security_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable)455{456	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;457	char spfsr_pl[MLXSW_REG_SPFSR_LEN];458	int err;459 460	if (mlxsw_sp_port->security == enable)461		return 0;462 463	mlxsw_reg_spfsr_pack(spfsr_pl, mlxsw_sp_port->local_port, enable);464	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spfsr), spfsr_pl);465	if (err)466		return err;467 468	mlxsw_sp_port->security = enable;469	return 0;470}471 472int mlxsw_sp_ethtype_to_sver_type(u16 ethtype, u8 *p_sver_type)473{474	switch (ethtype) {475	case ETH_P_8021Q:476		*p_sver_type = 0;477		break;478	case ETH_P_8021AD:479		*p_sver_type = 1;480		break;481	default:482		return -EINVAL;483	}484 485	return 0;486}487 488int mlxsw_sp_port_egress_ethtype_set(struct mlxsw_sp_port *mlxsw_sp_port,489				     u16 ethtype)490{491	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;492	char spevet_pl[MLXSW_REG_SPEVET_LEN];493	u8 sver_type;494	int err;495 496	err = mlxsw_sp_ethtype_to_sver_type(ethtype, &sver_type);497	if (err)498		return err;499 500	mlxsw_reg_spevet_pack(spevet_pl, mlxsw_sp_port->local_port, sver_type);501	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spevet), spevet_pl);502}503 504static int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port,505				    u16 vid, u16 ethtype)506{507	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;508	char spvid_pl[MLXSW_REG_SPVID_LEN];509	u8 sver_type;510	int err;511 512	err = mlxsw_sp_ethtype_to_sver_type(ethtype, &sver_type);513	if (err)514		return err;515 516	mlxsw_reg_spvid_pack(spvid_pl, mlxsw_sp_port->local_port, vid,517			     sver_type);518 519	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl);520}521 522static int mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port *mlxsw_sp_port,523					    bool allow)524{525	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;526	char spaft_pl[MLXSW_REG_SPAFT_LEN];527 528	mlxsw_reg_spaft_pack(spaft_pl, mlxsw_sp_port->local_port, allow);529	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spaft), spaft_pl);530}531 532int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid,533			   u16 ethtype)534{535	int err;536 537	if (!vid) {538		err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, false);539		if (err)540			return err;541	} else {542		err = __mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid, ethtype);543		if (err)544			return err;545		err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, true);546		if (err)547			goto err_port_allow_untagged_set;548	}549 550	mlxsw_sp_port->pvid = vid;551	return 0;552 553err_port_allow_untagged_set:554	__mlxsw_sp_port_pvid_set(mlxsw_sp_port, mlxsw_sp_port->pvid, ethtype);555	return err;556}557 558static int559mlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port)560{561	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;562	char sspr_pl[MLXSW_REG_SSPR_LEN];563 564	mlxsw_reg_sspr_pack(sspr_pl, mlxsw_sp_port->local_port);565	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sspr), sspr_pl);566}567 568static int569mlxsw_sp_port_module_info_parse(struct mlxsw_sp *mlxsw_sp,570				u16 local_port, char *pmlp_pl,571				struct mlxsw_sp_port_mapping *port_mapping)572{573	bool separate_rxtx;574	u8 first_lane;575	u8 slot_index;576	u8 module;577	u8 width;578	int i;579 580	module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);581	slot_index = mlxsw_reg_pmlp_slot_index_get(pmlp_pl, 0);582	width = mlxsw_reg_pmlp_width_get(pmlp_pl);583	separate_rxtx = mlxsw_reg_pmlp_rxtx_get(pmlp_pl);584	first_lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0);585 586	if (width && !is_power_of_2(width)) {587		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: width value is not power of 2\n",588			local_port);589		return -EINVAL;590	}591 592	for (i = 0; i < width; i++) {593		if (mlxsw_reg_pmlp_module_get(pmlp_pl, i) != module) {594			dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: contains multiple modules\n",595				local_port);596			return -EINVAL;597		}598		if (mlxsw_reg_pmlp_slot_index_get(pmlp_pl, i) != slot_index) {599			dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: contains multiple slot indexes\n",600				local_port);601			return -EINVAL;602		}603		if (separate_rxtx &&604		    mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) !=605		    mlxsw_reg_pmlp_rx_lane_get(pmlp_pl, i)) {606			dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are different\n",607				local_port);608			return -EINVAL;609		}610		if (mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) != i + first_lane) {611			dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are not sequential\n",612				local_port);613			return -EINVAL;614		}615	}616 617	port_mapping->module = module;618	port_mapping->slot_index = slot_index;619	port_mapping->width = width;620	port_mapping->module_width = width;621	port_mapping->lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0);622	return 0;623}624 625static int626mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, u16 local_port,627			      struct mlxsw_sp_port_mapping *port_mapping)628{629	char pmlp_pl[MLXSW_REG_PMLP_LEN];630	int err;631 632	mlxsw_reg_pmlp_pack(pmlp_pl, local_port);633	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);634	if (err)635		return err;636	return mlxsw_sp_port_module_info_parse(mlxsw_sp, local_port,637					       pmlp_pl, port_mapping);638}639 640static int641mlxsw_sp_port_module_map(struct mlxsw_sp *mlxsw_sp, u16 local_port,642			 const struct mlxsw_sp_port_mapping *port_mapping)643{644	char pmlp_pl[MLXSW_REG_PMLP_LEN];645	int i, err;646 647	mlxsw_env_module_port_map(mlxsw_sp->core, port_mapping->slot_index,648				  port_mapping->module);649 650	mlxsw_reg_pmlp_pack(pmlp_pl, local_port);651	mlxsw_reg_pmlp_width_set(pmlp_pl, port_mapping->width);652	for (i = 0; i < port_mapping->width; i++) {653		mlxsw_reg_pmlp_slot_index_set(pmlp_pl, i,654					      port_mapping->slot_index);655		mlxsw_reg_pmlp_module_set(pmlp_pl, i, port_mapping->module);656		mlxsw_reg_pmlp_tx_lane_set(pmlp_pl, i, port_mapping->lane + i); /* Rx & Tx */657	}658 659	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);660	if (err)661		goto err_pmlp_write;662	return 0;663 664err_pmlp_write:665	mlxsw_env_module_port_unmap(mlxsw_sp->core, port_mapping->slot_index,666				    port_mapping->module);667	return err;668}669 670static void mlxsw_sp_port_module_unmap(struct mlxsw_sp *mlxsw_sp, u16 local_port,671				       u8 slot_index, u8 module)672{673	char pmlp_pl[MLXSW_REG_PMLP_LEN];674 675	mlxsw_reg_pmlp_pack(pmlp_pl, local_port);676	mlxsw_reg_pmlp_width_set(pmlp_pl, 0);677	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);678	mlxsw_env_module_port_unmap(mlxsw_sp->core, slot_index, module);679}680 681static int mlxsw_sp_port_open(struct net_device *dev)682{683	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);684	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;685	int err;686 687	err = mlxsw_env_module_port_up(mlxsw_sp->core,688				       mlxsw_sp_port->mapping.slot_index,689				       mlxsw_sp_port->mapping.module);690	if (err)691		return err;692	err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);693	if (err)694		goto err_port_admin_status_set;695	netif_start_queue(dev);696	return 0;697 698err_port_admin_status_set:699	mlxsw_env_module_port_down(mlxsw_sp->core,700				   mlxsw_sp_port->mapping.slot_index,701				   mlxsw_sp_port->mapping.module);702	return err;703}704 705static int mlxsw_sp_port_stop(struct net_device *dev)706{707	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);708	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;709 710	netif_stop_queue(dev);711	mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);712	mlxsw_env_module_port_down(mlxsw_sp->core,713				   mlxsw_sp_port->mapping.slot_index,714				   mlxsw_sp_port->mapping.module);715	return 0;716}717 718static netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb,719				      struct net_device *dev)720{721	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);722	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;723	struct mlxsw_sp_port_pcpu_stats *pcpu_stats;724	const struct mlxsw_tx_info tx_info = {725		.local_port = mlxsw_sp_port->local_port,726		.is_emad = false,727	};728	u64 len;729	int err;730 731	memset(skb->cb, 0, sizeof(struct mlxsw_skb_cb));732 733	if (mlxsw_core_skb_transmit_busy(mlxsw_sp->core, &tx_info))734		return NETDEV_TX_BUSY;735 736	if (eth_skb_pad(skb)) {737		this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);738		return NETDEV_TX_OK;739	}740 741	err = mlxsw_sp_txhdr_handle(mlxsw_sp->core, mlxsw_sp_port, skb,742				    &tx_info);743	if (err)744		return NETDEV_TX_OK;745 746	/* TX header is consumed by HW on the way so we shouldn't count its747	 * bytes as being sent.748	 */749	len = skb->len - MLXSW_TXHDR_LEN;750 751	/* Due to a race we might fail here because of a full queue. In that752	 * unlikely case we simply drop the packet.753	 */754	err = mlxsw_core_skb_transmit(mlxsw_sp->core, skb, &tx_info);755 756	if (!err) {757		pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats);758		u64_stats_update_begin(&pcpu_stats->syncp);759		pcpu_stats->tx_packets++;760		pcpu_stats->tx_bytes += len;761		u64_stats_update_end(&pcpu_stats->syncp);762	} else {763		this_cpu_inc(mlxsw_sp_port->pcpu_stats->tx_dropped);764		dev_kfree_skb_any(skb);765	}766	return NETDEV_TX_OK;767}768 769static void mlxsw_sp_set_rx_mode(struct net_device *dev)770{771}772 773static int mlxsw_sp_port_set_mac_address(struct net_device *dev, void *p)774{775	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);776	struct sockaddr *addr = p;777	int err;778 779	if (!is_valid_ether_addr(addr->sa_data))780		return -EADDRNOTAVAIL;781 782	err = mlxsw_sp_port_dev_addr_set(mlxsw_sp_port, addr->sa_data);783	if (err)784		return err;785	eth_hw_addr_set(dev, addr->sa_data);786	return 0;787}788 789static int mlxsw_sp_port_change_mtu(struct net_device *dev, int mtu)790{791	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);792	struct mlxsw_sp_hdroom orig_hdroom;793	struct mlxsw_sp_hdroom hdroom;794	int err;795 796	orig_hdroom = *mlxsw_sp_port->hdroom;797 798	hdroom = orig_hdroom;799	hdroom.mtu = mtu;800	mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);801 802	err = mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);803	if (err) {804		netdev_err(dev, "Failed to configure port's headroom\n");805		return err;806	}807 808	err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, mtu);809	if (err)810		goto err_port_mtu_set;811	WRITE_ONCE(dev->mtu, mtu);812	return 0;813 814err_port_mtu_set:815	mlxsw_sp_hdroom_configure(mlxsw_sp_port, &orig_hdroom);816	return err;817}818 819static int820mlxsw_sp_port_get_sw_stats64(const struct net_device *dev,821			     struct rtnl_link_stats64 *stats)822{823	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);824	struct mlxsw_sp_port_pcpu_stats *p;825	u64 rx_packets, rx_bytes, tx_packets, tx_bytes;826	u32 tx_dropped = 0;827	unsigned int start;828	int i;829 830	for_each_possible_cpu(i) {831		p = per_cpu_ptr(mlxsw_sp_port->pcpu_stats, i);832		do {833			start = u64_stats_fetch_begin(&p->syncp);834			rx_packets	= p->rx_packets;835			rx_bytes	= p->rx_bytes;836			tx_packets	= p->tx_packets;837			tx_bytes	= p->tx_bytes;838		} while (u64_stats_fetch_retry(&p->syncp, start));839 840		stats->rx_packets	+= rx_packets;841		stats->rx_bytes		+= rx_bytes;842		stats->tx_packets	+= tx_packets;843		stats->tx_bytes		+= tx_bytes;844		/* tx_dropped is u32, updated without syncp protection. */845		tx_dropped	+= p->tx_dropped;846	}847	stats->tx_dropped	= tx_dropped;848	return 0;849}850 851static bool mlxsw_sp_port_has_offload_stats(const struct net_device *dev, int attr_id)852{853	switch (attr_id) {854	case IFLA_OFFLOAD_XSTATS_CPU_HIT:855		return true;856	}857 858	return false;859}860 861static int mlxsw_sp_port_get_offload_stats(int attr_id, const struct net_device *dev,862					   void *sp)863{864	switch (attr_id) {865	case IFLA_OFFLOAD_XSTATS_CPU_HIT:866		return mlxsw_sp_port_get_sw_stats64(dev, sp);867	}868 869	return -EINVAL;870}871 872int mlxsw_sp_port_get_stats_raw(struct net_device *dev, int grp,873				int prio, char *ppcnt_pl)874{875	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);876	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;877 878	mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sp_port->local_port, grp, prio);879	return mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ppcnt), ppcnt_pl);880}881 882static int mlxsw_sp_port_get_hw_stats(struct net_device *dev,883				      struct rtnl_link_stats64 *stats)884{885	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];886	int err;887 888	err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_IEEE_8023_CNT,889					  0, ppcnt_pl);890	if (err)891		goto out;892 893	stats->tx_packets =894		mlxsw_reg_ppcnt_a_frames_transmitted_ok_get(ppcnt_pl);895	stats->rx_packets =896		mlxsw_reg_ppcnt_a_frames_received_ok_get(ppcnt_pl);897	stats->tx_bytes =898		mlxsw_reg_ppcnt_a_octets_transmitted_ok_get(ppcnt_pl);899	stats->rx_bytes =900		mlxsw_reg_ppcnt_a_octets_received_ok_get(ppcnt_pl);901	stats->multicast =902		mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get(ppcnt_pl);903 904	stats->rx_crc_errors =905		mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get(ppcnt_pl);906	stats->rx_frame_errors =907		mlxsw_reg_ppcnt_a_alignment_errors_get(ppcnt_pl);908 909	stats->rx_length_errors = (910		mlxsw_reg_ppcnt_a_in_range_length_errors_get(ppcnt_pl) +911		mlxsw_reg_ppcnt_a_out_of_range_length_field_get(ppcnt_pl) +912		mlxsw_reg_ppcnt_a_frame_too_long_errors_get(ppcnt_pl));913 914	stats->rx_errors = (stats->rx_crc_errors +915		stats->rx_frame_errors + stats->rx_length_errors);916 917out:918	return err;919}920 921static void922mlxsw_sp_port_get_hw_xstats(struct net_device *dev,923			    struct mlxsw_sp_port_xstats *xstats)924{925	char ppcnt_pl[MLXSW_REG_PPCNT_LEN];926	int err, i;927 928	err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_EXT_CNT, 0,929					  ppcnt_pl);930	if (!err)931		xstats->ecn = mlxsw_reg_ppcnt_ecn_marked_get(ppcnt_pl);932 933	for (i = 0; i < TC_MAX_QUEUE; i++) {934		err = mlxsw_sp_port_get_stats_raw(dev,935						  MLXSW_REG_PPCNT_TC_CONG_CNT,936						  i, ppcnt_pl);937		if (err)938			goto tc_cnt;939 940		xstats->wred_drop[i] =941			mlxsw_reg_ppcnt_wred_discard_get(ppcnt_pl);942		xstats->tc_ecn[i] = mlxsw_reg_ppcnt_ecn_marked_tc_get(ppcnt_pl);943 944tc_cnt:945		err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_TC_CNT,946						  i, ppcnt_pl);947		if (err)948			continue;949 950		xstats->backlog[i] =951			mlxsw_reg_ppcnt_tc_transmit_queue_get(ppcnt_pl);952		xstats->tail_drop[i] =953			mlxsw_reg_ppcnt_tc_no_buffer_discard_uc_get(ppcnt_pl);954	}955 956	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {957		err = mlxsw_sp_port_get_stats_raw(dev, MLXSW_REG_PPCNT_PRIO_CNT,958						  i, ppcnt_pl);959		if (err)960			continue;961 962		xstats->tx_packets[i] = mlxsw_reg_ppcnt_tx_frames_get(ppcnt_pl);963		xstats->tx_bytes[i] = mlxsw_reg_ppcnt_tx_octets_get(ppcnt_pl);964	}965}966 967static void update_stats_cache(struct work_struct *work)968{969	struct mlxsw_sp_port *mlxsw_sp_port =970		container_of(work, struct mlxsw_sp_port,971			     periodic_hw_stats.update_dw.work);972 973	if (!netif_carrier_ok(mlxsw_sp_port->dev))974		/* Note: mlxsw_sp_port_down_wipe_counters() clears the cache as975		 * necessary when port goes down.976		 */977		goto out;978 979	mlxsw_sp_port_get_hw_stats(mlxsw_sp_port->dev,980				   &mlxsw_sp_port->periodic_hw_stats.stats);981	mlxsw_sp_port_get_hw_xstats(mlxsw_sp_port->dev,982				    &mlxsw_sp_port->periodic_hw_stats.xstats);983 984out:985	mlxsw_core_schedule_dw(&mlxsw_sp_port->periodic_hw_stats.update_dw,986			       MLXSW_HW_STATS_UPDATE_TIME);987}988 989/* Return the stats from a cache that is updated periodically,990 * as this function might get called in an atomic context.991 */992static void993mlxsw_sp_port_get_stats64(struct net_device *dev,994			  struct rtnl_link_stats64 *stats)995{996	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);997 998	memcpy(stats, &mlxsw_sp_port->periodic_hw_stats.stats, sizeof(*stats));999}1000 1001static int __mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,1002				    u16 vid_begin, u16 vid_end,1003				    bool is_member, bool untagged)1004{1005	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1006	char *spvm_pl;1007	int err;1008 1009	spvm_pl = kmalloc(MLXSW_REG_SPVM_LEN, GFP_KERNEL);1010	if (!spvm_pl)1011		return -ENOMEM;1012 1013	mlxsw_reg_spvm_pack(spvm_pl, mlxsw_sp_port->local_port,	vid_begin,1014			    vid_end, is_member, untagged);1015	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvm), spvm_pl);1016	kfree(spvm_pl);1017	return err;1018}1019 1020int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin,1021			   u16 vid_end, bool is_member, bool untagged)1022{1023	u16 vid, vid_e;1024	int err;1025 1026	for (vid = vid_begin; vid <= vid_end;1027	     vid += MLXSW_REG_SPVM_REC_MAX_COUNT) {1028		vid_e = min((u16) (vid + MLXSW_REG_SPVM_REC_MAX_COUNT - 1),1029			    vid_end);1030 1031		err = __mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid_e,1032					       is_member, untagged);1033		if (err)1034			return err;1035	}1036 1037	return 0;1038}1039 1040static void mlxsw_sp_port_vlan_flush(struct mlxsw_sp_port *mlxsw_sp_port,1041				     bool flush_default)1042{1043	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, *tmp;1044 1045	list_for_each_entry_safe(mlxsw_sp_port_vlan, tmp,1046				 &mlxsw_sp_port->vlans_list, list) {1047		if (!flush_default &&1048		    mlxsw_sp_port_vlan->vid == MLXSW_SP_DEFAULT_VID)1049			continue;1050		mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);1051	}1052}1053 1054static void1055mlxsw_sp_port_vlan_cleanup(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)1056{1057	if (mlxsw_sp_port_vlan->bridge_port)1058		mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);1059	else if (mlxsw_sp_port_vlan->fid)1060		mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan);1061}1062 1063struct mlxsw_sp_port_vlan *1064mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)1065{1066	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;1067	bool untagged = vid == MLXSW_SP_DEFAULT_VID;1068	int err;1069 1070	mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);1071	if (mlxsw_sp_port_vlan)1072		return ERR_PTR(-EEXIST);1073 1074	err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, true, untagged);1075	if (err)1076		return ERR_PTR(err);1077 1078	mlxsw_sp_port_vlan = kzalloc(sizeof(*mlxsw_sp_port_vlan), GFP_KERNEL);1079	if (!mlxsw_sp_port_vlan) {1080		err = -ENOMEM;1081		goto err_port_vlan_alloc;1082	}1083 1084	mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port;1085	mlxsw_sp_port_vlan->vid = vid;1086	list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list);1087 1088	return mlxsw_sp_port_vlan;1089 1090err_port_vlan_alloc:1091	mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);1092	return ERR_PTR(err);1093}1094 1095void mlxsw_sp_port_vlan_destroy(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)1096{1097	struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port;1098	u16 vid = mlxsw_sp_port_vlan->vid;1099 1100	mlxsw_sp_port_vlan_cleanup(mlxsw_sp_port_vlan);1101	list_del(&mlxsw_sp_port_vlan->list);1102	kfree(mlxsw_sp_port_vlan);1103	mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid, false, false);1104}1105 1106static int mlxsw_sp_port_add_vid(struct net_device *dev,1107				 __be16 __always_unused proto, u16 vid)1108{1109	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);1110 1111	/* VLAN 0 is added to HW filter when device goes up, but it is1112	 * reserved in our case, so simply return.1113	 */1114	if (!vid)1115		return 0;1116 1117	return PTR_ERR_OR_ZERO(mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid));1118}1119 1120int mlxsw_sp_port_kill_vid(struct net_device *dev,1121			   __be16 __always_unused proto, u16 vid)1122{1123	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);1124	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;1125 1126	/* VLAN 0 is removed from HW filter when device goes down, but1127	 * it is reserved in our case, so simply return.1128	 */1129	if (!vid)1130		return 0;1131 1132	mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);1133	if (!mlxsw_sp_port_vlan)1134		return 0;1135	mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);1136 1137	return 0;1138}1139 1140static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,1141				   struct flow_block_offload *f)1142{1143	switch (f->binder_type) {1144	case FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS:1145		return mlxsw_sp_setup_tc_block_clsact(mlxsw_sp_port, f, true);1146	case FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS:1147		return mlxsw_sp_setup_tc_block_clsact(mlxsw_sp_port, f, false);1148	case FLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP:1149		return mlxsw_sp_setup_tc_block_qevent_early_drop(mlxsw_sp_port, f);1150	case FLOW_BLOCK_BINDER_TYPE_RED_MARK:1151		return mlxsw_sp_setup_tc_block_qevent_mark(mlxsw_sp_port, f);1152	default:1153		return -EOPNOTSUPP;1154	}1155}1156 1157static int mlxsw_sp_setup_tc(struct net_device *dev, enum tc_setup_type type,1158			     void *type_data)1159{1160	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);1161 1162	switch (type) {1163	case TC_SETUP_BLOCK:1164		return mlxsw_sp_setup_tc_block(mlxsw_sp_port, type_data);1165	case TC_SETUP_QDISC_RED:1166		return mlxsw_sp_setup_tc_red(mlxsw_sp_port, type_data);1167	case TC_SETUP_QDISC_PRIO:1168		return mlxsw_sp_setup_tc_prio(mlxsw_sp_port, type_data);1169	case TC_SETUP_QDISC_ETS:1170		return mlxsw_sp_setup_tc_ets(mlxsw_sp_port, type_data);1171	case TC_SETUP_QDISC_TBF:1172		return mlxsw_sp_setup_tc_tbf(mlxsw_sp_port, type_data);1173	case TC_SETUP_QDISC_FIFO:1174		return mlxsw_sp_setup_tc_fifo(mlxsw_sp_port, type_data);1175	default:1176		return -EOPNOTSUPP;1177	}1178}1179 1180static int mlxsw_sp_feature_hw_tc(struct net_device *dev, bool enable)1181{1182	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);1183 1184	if (!enable) {1185		if (mlxsw_sp_flow_block_rule_count(mlxsw_sp_port->ing_flow_block) ||1186		    mlxsw_sp_flow_block_rule_count(mlxsw_sp_port->eg_flow_block)) {1187			netdev_err(dev, "Active offloaded tc filters, can't turn hw_tc_offload off\n");1188			return -EINVAL;1189		}1190		mlxsw_sp_flow_block_disable_inc(mlxsw_sp_port->ing_flow_block);1191		mlxsw_sp_flow_block_disable_inc(mlxsw_sp_port->eg_flow_block);1192	} else {1193		mlxsw_sp_flow_block_disable_dec(mlxsw_sp_port->ing_flow_block);1194		mlxsw_sp_flow_block_disable_dec(mlxsw_sp_port->eg_flow_block);1195	}1196	return 0;1197}1198 1199static int mlxsw_sp_feature_loopback(struct net_device *dev, bool enable)1200{1201	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);1202	char pplr_pl[MLXSW_REG_PPLR_LEN];1203	int err;1204 1205	if (netif_running(dev))1206		mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);1207 1208	mlxsw_reg_pplr_pack(pplr_pl, mlxsw_sp_port->local_port, enable);1209	err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(pplr),1210			      pplr_pl);1211 1212	if (netif_running(dev))1213		mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);1214 1215	return err;1216}1217 1218typedef int (*mlxsw_sp_feature_handler)(struct net_device *dev, bool enable);1219 1220static int mlxsw_sp_handle_feature(struct net_device *dev,1221				   netdev_features_t wanted_features,1222				   netdev_features_t feature,1223				   mlxsw_sp_feature_handler feature_handler)1224{1225	netdev_features_t changes = wanted_features ^ dev->features;1226	bool enable = !!(wanted_features & feature);1227	int err;1228 1229	if (!(changes & feature))1230		return 0;1231 1232	err = feature_handler(dev, enable);1233	if (err) {1234		netdev_err(dev, "%s feature %pNF failed, err %d\n",1235			   enable ? "Enable" : "Disable", &feature, err);1236		return err;1237	}1238 1239	if (enable)1240		dev->features |= feature;1241	else1242		dev->features &= ~feature;1243 1244	return 0;1245}1246static int mlxsw_sp_set_features(struct net_device *dev,1247				 netdev_features_t features)1248{1249	netdev_features_t oper_features = dev->features;1250	int err = 0;1251 1252	err |= mlxsw_sp_handle_feature(dev, features, NETIF_F_HW_TC,1253				       mlxsw_sp_feature_hw_tc);1254	err |= mlxsw_sp_handle_feature(dev, features, NETIF_F_LOOPBACK,1255				       mlxsw_sp_feature_loopback);1256 1257	if (err) {1258		dev->features = oper_features;1259		return -EINVAL;1260	}1261 1262	return 0;1263}1264 1265static int mlxsw_sp_port_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,1266				      struct ifreq *ifr)1267{1268	struct hwtstamp_config config;1269	int err;1270 1271	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))1272		return -EFAULT;1273 1274	err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port,1275							     &config);1276	if (err)1277		return err;1278 1279	if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))1280		return -EFAULT;1281 1282	return 0;1283}1284 1285static int mlxsw_sp_port_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,1286				      struct ifreq *ifr)1287{1288	struct hwtstamp_config config;1289	int err;1290 1291	err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_get(mlxsw_sp_port,1292							     &config);1293	if (err)1294		return err;1295 1296	if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))1297		return -EFAULT;1298 1299	return 0;1300}1301 1302static inline void mlxsw_sp_port_ptp_clear(struct mlxsw_sp_port *mlxsw_sp_port)1303{1304	struct hwtstamp_config config = {0};1305 1306	mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port, &config);1307}1308 1309static int1310mlxsw_sp_port_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)1311{1312	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);1313 1314	switch (cmd) {1315	case SIOCSHWTSTAMP:1316		return mlxsw_sp_port_hwtstamp_set(mlxsw_sp_port, ifr);1317	case SIOCGHWTSTAMP:1318		return mlxsw_sp_port_hwtstamp_get(mlxsw_sp_port, ifr);1319	default:1320		return -EOPNOTSUPP;1321	}1322}1323 1324static const struct net_device_ops mlxsw_sp_port_netdev_ops = {1325	.ndo_open		= mlxsw_sp_port_open,1326	.ndo_stop		= mlxsw_sp_port_stop,1327	.ndo_start_xmit		= mlxsw_sp_port_xmit,1328	.ndo_setup_tc           = mlxsw_sp_setup_tc,1329	.ndo_set_rx_mode	= mlxsw_sp_set_rx_mode,1330	.ndo_set_mac_address	= mlxsw_sp_port_set_mac_address,1331	.ndo_change_mtu		= mlxsw_sp_port_change_mtu,1332	.ndo_get_stats64	= mlxsw_sp_port_get_stats64,1333	.ndo_has_offload_stats	= mlxsw_sp_port_has_offload_stats,1334	.ndo_get_offload_stats	= mlxsw_sp_port_get_offload_stats,1335	.ndo_vlan_rx_add_vid	= mlxsw_sp_port_add_vid,1336	.ndo_vlan_rx_kill_vid	= mlxsw_sp_port_kill_vid,1337	.ndo_set_features	= mlxsw_sp_set_features,1338	.ndo_eth_ioctl		= mlxsw_sp_port_ioctl,1339};1340 1341static int1342mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port)1343{1344	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1345	u32 eth_proto_cap, eth_proto_admin, eth_proto_oper;1346	const struct mlxsw_sp_port_type_speed_ops *ops;1347	char ptys_pl[MLXSW_REG_PTYS_LEN];1348	u32 eth_proto_cap_masked;1349	int err;1350 1351	ops = mlxsw_sp->port_type_speed_ops;1352 1353	/* Set advertised speeds to speeds supported by both the driver1354	 * and the device.1355	 */1356	ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,1357			       0, false);1358	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);1359	if (err)1360		return err;1361 1362	ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, &eth_proto_cap,1363				 &eth_proto_admin, &eth_proto_oper);1364	eth_proto_cap_masked = ops->ptys_proto_cap_masked_get(eth_proto_cap);1365	ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port,1366			       eth_proto_cap_masked,1367			       mlxsw_sp_port->link.autoneg);1368	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);1369}1370 1371int mlxsw_sp_port_speed_get(struct mlxsw_sp_port *mlxsw_sp_port, u32 *speed)1372{1373	const struct mlxsw_sp_port_type_speed_ops *port_type_speed_ops;1374	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1375	char ptys_pl[MLXSW_REG_PTYS_LEN];1376	u32 eth_proto_oper;1377	int err;1378 1379	port_type_speed_ops = mlxsw_sp->port_type_speed_ops;1380	port_type_speed_ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl,1381					       mlxsw_sp_port->local_port, 0,1382					       false);1383	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);1384	if (err)1385		return err;1386	port_type_speed_ops->reg_ptys_eth_unpack(mlxsw_sp, ptys_pl, NULL, NULL,1387						 &eth_proto_oper);1388	*speed = port_type_speed_ops->from_ptys_speed(mlxsw_sp, eth_proto_oper);1389	return 0;1390}1391 1392int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,1393			  enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index,1394			  bool dwrr, u8 dwrr_weight)1395{1396	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1397	char qeec_pl[MLXSW_REG_QEEC_LEN];1398 1399	mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index,1400			    next_index);1401	mlxsw_reg_qeec_de_set(qeec_pl, true);1402	mlxsw_reg_qeec_dwrr_set(qeec_pl, dwrr);1403	mlxsw_reg_qeec_dwrr_weight_set(qeec_pl, dwrr_weight);1404	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);1405}1406 1407int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port,1408				  enum mlxsw_reg_qeec_hr hr, u8 index,1409				  u8 next_index, u32 maxrate, u8 burst_size)1410{1411	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1412	char qeec_pl[MLXSW_REG_QEEC_LEN];1413 1414	mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index,1415			    next_index);1416	mlxsw_reg_qeec_mase_set(qeec_pl, true);1417	mlxsw_reg_qeec_max_shaper_rate_set(qeec_pl, maxrate);1418	mlxsw_reg_qeec_max_shaper_bs_set(qeec_pl, burst_size);1419	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);1420}1421 1422static int mlxsw_sp_port_min_bw_set(struct mlxsw_sp_port *mlxsw_sp_port,1423				    enum mlxsw_reg_qeec_hr hr, u8 index,1424				    u8 next_index, u32 minrate)1425{1426	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1427	char qeec_pl[MLXSW_REG_QEEC_LEN];1428 1429	mlxsw_reg_qeec_pack(qeec_pl, mlxsw_sp_port->local_port, hr, index,1430			    next_index);1431	mlxsw_reg_qeec_mise_set(qeec_pl, true);1432	mlxsw_reg_qeec_min_shaper_rate_set(qeec_pl, minrate);1433 1434	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qeec), qeec_pl);1435}1436 1437int mlxsw_sp_port_prio_tc_set(struct mlxsw_sp_port *mlxsw_sp_port,1438			      u8 switch_prio, u8 tclass)1439{1440	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1441	char qtct_pl[MLXSW_REG_QTCT_LEN];1442 1443	mlxsw_reg_qtct_pack(qtct_pl, mlxsw_sp_port->local_port, switch_prio,1444			    tclass);1445	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qtct), qtct_pl);1446}1447 1448static int mlxsw_sp_port_ets_init(struct mlxsw_sp_port *mlxsw_sp_port)1449{1450	int err, i;1451 1452	/* Setup the elements hierarcy, so that each TC is linked to1453	 * one subgroup, which are all member in the same group.1454	 */1455	err = mlxsw_sp_port_ets_set(mlxsw_sp_port,1456				    MLXSW_REG_QEEC_HR_GROUP, 0, 0, false, 0);1457	if (err)1458		return err;1459	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {1460		err = mlxsw_sp_port_ets_set(mlxsw_sp_port,1461					    MLXSW_REG_QEEC_HR_SUBGROUP, i,1462					    0, false, 0);1463		if (err)1464			return err;1465	}1466	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {1467		err = mlxsw_sp_port_ets_set(mlxsw_sp_port,1468					    MLXSW_REG_QEEC_HR_TC, i, i,1469					    false, 0);1470		if (err)1471			return err;1472 1473		err = mlxsw_sp_port_ets_set(mlxsw_sp_port,1474					    MLXSW_REG_QEEC_HR_TC,1475					    i + 8, i,1476					    true, 100);1477		if (err)1478			return err;1479	}1480 1481	/* Make sure the max shaper is disabled in all hierarchies that support1482	 * it. Note that this disables ptps (PTP shaper), but that is intended1483	 * for the initial configuration.1484	 */1485	err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,1486					    MLXSW_REG_QEEC_HR_PORT, 0, 0,1487					    MLXSW_REG_QEEC_MAS_DIS, 0);1488	if (err)1489		return err;1490	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {1491		err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,1492						    MLXSW_REG_QEEC_HR_SUBGROUP,1493						    i, 0,1494						    MLXSW_REG_QEEC_MAS_DIS, 0);1495		if (err)1496			return err;1497	}1498	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {1499		err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,1500						    MLXSW_REG_QEEC_HR_TC,1501						    i, i,1502						    MLXSW_REG_QEEC_MAS_DIS, 0);1503		if (err)1504			return err;1505 1506		err = mlxsw_sp_port_ets_maxrate_set(mlxsw_sp_port,1507						    MLXSW_REG_QEEC_HR_TC,1508						    i + 8, i,1509						    MLXSW_REG_QEEC_MAS_DIS, 0);1510		if (err)1511			return err;1512	}1513 1514	/* Configure the min shaper for multicast TCs. */1515	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {1516		err = mlxsw_sp_port_min_bw_set(mlxsw_sp_port,1517					       MLXSW_REG_QEEC_HR_TC,1518					       i + 8, i,1519					       MLXSW_REG_QEEC_MIS_MIN);1520		if (err)1521			return err;1522	}1523 1524	/* Map all priorities to traffic class 0. */1525	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {1526		err = mlxsw_sp_port_prio_tc_set(mlxsw_sp_port, i, 0);1527		if (err)1528			return err;1529	}1530 1531	return 0;1532}1533 1534static int mlxsw_sp_port_tc_mc_mode_set(struct mlxsw_sp_port *mlxsw_sp_port,1535					bool enable)1536{1537	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1538	char qtctm_pl[MLXSW_REG_QTCTM_LEN];1539 1540	mlxsw_reg_qtctm_pack(qtctm_pl, mlxsw_sp_port->local_port, enable);1541	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qtctm), qtctm_pl);1542}1543 1544static int mlxsw_sp_port_overheat_init_val_set(struct mlxsw_sp_port *mlxsw_sp_port)1545{1546	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1547	u8 slot_index = mlxsw_sp_port->mapping.slot_index;1548	u8 module = mlxsw_sp_port->mapping.module;1549	u64 overheat_counter;1550	int err;1551 1552	err = mlxsw_env_module_overheat_counter_get(mlxsw_sp->core, slot_index,1553						    module, &overheat_counter);1554	if (err)1555		return err;1556 1557	mlxsw_sp_port->module_overheat_initial_val = overheat_counter;1558	return 0;1559}1560 1561int1562mlxsw_sp_port_vlan_classification_set(struct mlxsw_sp_port *mlxsw_sp_port,1563				      bool is_8021ad_tagged,1564				      bool is_8021q_tagged)1565{1566	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;1567	char spvc_pl[MLXSW_REG_SPVC_LEN];1568 1569	mlxsw_reg_spvc_pack(spvc_pl, mlxsw_sp_port->local_port,1570			    is_8021ad_tagged, is_8021q_tagged);1571	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvc), spvc_pl);1572}1573 1574static int mlxsw_sp_port_label_info_get(struct mlxsw_sp *mlxsw_sp,1575					u16 local_port, u8 *port_number,1576					u8 *split_port_subnumber,1577					u8 *slot_index)1578{1579	char pllp_pl[MLXSW_REG_PLLP_LEN];1580	int err;1581 1582	mlxsw_reg_pllp_pack(pllp_pl, local_port);1583	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pllp), pllp_pl);1584	if (err)1585		return err;1586	mlxsw_reg_pllp_unpack(pllp_pl, port_number,1587			      split_port_subnumber, slot_index);1588	return 0;1589}1590 1591static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u16 local_port,1592				bool split,1593				struct mlxsw_sp_port_mapping *port_mapping)1594{1595	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;1596	struct mlxsw_sp_port *mlxsw_sp_port;1597	u32 lanes = port_mapping->width;1598	u8 split_port_subnumber;1599	struct net_device *dev;1600	u8 port_number;1601	u8 slot_index;1602	bool splittable;1603	int err;1604 1605	err = mlxsw_sp_port_module_map(mlxsw_sp, local_port, port_mapping);1606	if (err) {1607		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to map module\n",1608			local_port);1609		return err;1610	}1611 1612	err = mlxsw_sp_port_swid_set(mlxsw_sp, local_port, 0);1613	if (err) {1614		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set SWID\n",1615			local_port);1616		goto err_port_swid_set;1617	}1618 1619	err = mlxsw_sp_port_label_info_get(mlxsw_sp, local_port, &port_number,1620					   &split_port_subnumber, &slot_index);1621	if (err) {1622		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get port label information\n",1623			local_port);1624		goto err_port_label_info_get;1625	}1626 1627	splittable = lanes > 1 && !split;1628	err = mlxsw_core_port_init(mlxsw_sp->core, local_port, slot_index,1629				   port_number, split, split_port_subnumber,1630				   splittable, lanes, mlxsw_sp->base_mac,1631				   sizeof(mlxsw_sp->base_mac));1632	if (err) {1633		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to init core port\n",1634			local_port);1635		goto err_core_port_init;1636	}1637 1638	dev = alloc_etherdev(sizeof(struct mlxsw_sp_port));1639	if (!dev) {1640		err = -ENOMEM;1641		goto err_alloc_etherdev;1642	}1643	SET_NETDEV_DEV(dev, mlxsw_sp->bus_info->dev);1644	dev_net_set(dev, mlxsw_sp_net(mlxsw_sp));1645	mlxsw_sp_port = netdev_priv(dev);1646	mlxsw_core_port_netdev_link(mlxsw_sp->core, local_port,1647				    mlxsw_sp_port, dev);1648	mlxsw_sp_port->dev = dev;1649	mlxsw_sp_port->mlxsw_sp = mlxsw_sp;1650	mlxsw_sp_port->local_port = local_port;1651	mlxsw_sp_port->pvid = MLXSW_SP_DEFAULT_VID;1652	mlxsw_sp_port->split = split;1653	mlxsw_sp_port->mapping = *port_mapping;1654	mlxsw_sp_port->link.autoneg = 1;1655	INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list);1656 1657	mlxsw_sp_port->pcpu_stats =1658		netdev_alloc_pcpu_stats(struct mlxsw_sp_port_pcpu_stats);1659	if (!mlxsw_sp_port->pcpu_stats) {1660		err = -ENOMEM;1661		goto err_alloc_stats;1662	}1663 1664	INIT_DELAYED_WORK(&mlxsw_sp_port->periodic_hw_stats.update_dw,1665			  &update_stats_cache);1666 1667	dev->netdev_ops = &mlxsw_sp_port_netdev_ops;1668	dev->ethtool_ops = &mlxsw_sp_port_ethtool_ops;1669 1670	err = mlxsw_sp_port_dev_addr_init(mlxsw_sp_port);1671	if (err) {1672		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unable to init port mac address\n",1673			mlxsw_sp_port->local_port);1674		goto err_dev_addr_init;1675	}1676 1677	netif_carrier_off(dev);1678 1679	dev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_CTAG_FILTER |1680			 NETIF_F_HW_TC;1681	dev->hw_features |= NETIF_F_HW_TC | NETIF_F_LOOPBACK;1682	dev->lltx = true;1683	dev->netns_local = true;1684 1685	dev->min_mtu = ETH_MIN_MTU;1686	dev->max_mtu = MLXSW_PORT_MAX_MTU - MLXSW_PORT_ETH_FRAME_HDR;1687 1688	/* Each packet needs to have a Tx header (metadata) on top all other1689	 * headers.1690	 */1691	dev->needed_headroom = MLXSW_TXHDR_LEN;1692 1693	err = mlxsw_sp_port_system_port_mapping_set(mlxsw_sp_port);1694	if (err) {1695		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set system port mapping\n",1696			mlxsw_sp_port->local_port);1697		goto err_port_system_port_mapping_set;1698	}1699 1700	err = mlxsw_sp_port_speed_by_width_set(mlxsw_sp_port);1701	if (err) {1702		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to enable speeds\n",1703			mlxsw_sp_port->local_port);1704		goto err_port_speed_by_width_set;1705	}1706 1707	err = mlxsw_sp->port_type_speed_ops->ptys_max_speed(mlxsw_sp_port,1708							    &mlxsw_sp_port->max_speed);1709	if (err) {1710		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to get maximum speed\n",1711			mlxsw_sp_port->local_port);1712		goto err_max_speed_get;1713	}1714 1715	err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, ETH_DATA_LEN);1716	if (err) {1717		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set MTU\n",1718			mlxsw_sp_port->local_port);1719		goto err_port_mtu_set;1720	}1721 1722	err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);1723	if (err)1724		goto err_port_admin_status_set;1725 1726	err = mlxsw_sp_port_buffers_init(mlxsw_sp_port);1727	if (err) {1728		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize buffers\n",1729			mlxsw_sp_port->local_port);1730		goto err_port_buffers_init;1731	}1732 1733	err = mlxsw_sp_port_ets_init(mlxsw_sp_port);1734	if (err) {1735		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize ETS\n",1736			mlxsw_sp_port->local_port);1737		goto err_port_ets_init;1738	}1739 1740	err = mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, true);1741	if (err) {1742		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize TC MC mode\n",1743			mlxsw_sp_port->local_port);1744		goto err_port_tc_mc_mode;1745	}1746 1747	/* ETS and buffers must be initialized before DCB. */1748	err = mlxsw_sp_port_dcb_init(mlxsw_sp_port);1749	if (err) {1750		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize DCB\n",1751			mlxsw_sp_port->local_port);1752		goto err_port_dcb_init;1753	}1754 1755	err = mlxsw_sp_port_fids_init(mlxsw_sp_port);1756	if (err) {1757		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize FIDs\n",1758			mlxsw_sp_port->local_port);1759		goto err_port_fids_init;1760	}1761 1762	err = mlxsw_sp_tc_qdisc_init(mlxsw_sp_port);1763	if (err) {1764		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize TC qdiscs\n",1765			mlxsw_sp_port->local_port);1766		goto err_port_qdiscs_init;1767	}1768 1769	err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 0, VLAN_N_VID - 1, false,1770				     false);1771	if (err) {1772		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to clear VLAN filter\n",1773			mlxsw_sp_port->local_port);1774		goto err_port_vlan_clear;1775	}1776 1777	err = mlxsw_sp_port_nve_init(mlxsw_sp_port);1778	if (err) {1779		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize NVE\n",1780			mlxsw_sp_port->local_port);1781		goto err_port_nve_init;1782	}1783 1784	err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID,1785				     ETH_P_8021Q);1786	if (err) {1787		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set PVID\n",1788			mlxsw_sp_port->local_port);1789		goto err_port_pvid_set;1790	}1791 1792	mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_create(mlxsw_sp_port,1793						       MLXSW_SP_DEFAULT_VID);1794	if (IS_ERR(mlxsw_sp_port_vlan)) {1795		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to create VID 1\n",1796			mlxsw_sp_port->local_port);1797		err = PTR_ERR(mlxsw_sp_port_vlan);1798		goto err_port_vlan_create;1799	}1800	mlxsw_sp_port->default_vlan = mlxsw_sp_port_vlan;1801 1802	/* Set SPVC.et0=true and SPVC.et1=false to make the local port to treat1803	 * only packets with 802.1q header as tagged packets.1804	 */1805	err = mlxsw_sp_port_vlan_classification_set(mlxsw_sp_port, false, true);1806	if (err) {1807		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set default VLAN classification\n",1808			local_port);1809		goto err_port_vlan_classification_set;1810	}1811 1812	INIT_DELAYED_WORK(&mlxsw_sp_port->ptp.shaper_dw,1813			  mlxsw_sp->ptp_ops->shaper_work);1814 1815	mlxsw_sp->ports[local_port] = mlxsw_sp_port;1816 1817	err = mlxsw_sp_port_overheat_init_val_set(mlxsw_sp_port);1818	if (err) {1819		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set overheat initial value\n",1820			mlxsw_sp_port->local_port);1821		goto err_port_overheat_init_val_set;1822	}1823 1824	err = register_netdev(dev);1825	if (err) {1826		dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to register netdev\n",1827			mlxsw_sp_port->local_port);1828		goto err_register_netdev;1829	}1830 1831	mlxsw_core_schedule_dw(&mlxsw_sp_port->periodic_hw_stats.update_dw, 0);1832	return 0;1833 1834err_register_netdev:1835err_port_overheat_init_val_set:1836	mlxsw_sp_port_vlan_classification_set(mlxsw_sp_port, true, true);1837err_port_vlan_classification_set:1838	mlxsw_sp->ports[local_port] = NULL;1839	mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan);1840err_port_vlan_create:1841err_port_pvid_set:1842	mlxsw_sp_port_nve_fini(mlxsw_sp_port);1843err_port_nve_init:1844err_port_vlan_clear:1845	mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port);1846err_port_qdiscs_init:1847	mlxsw_sp_port_fids_fini(mlxsw_sp_port);1848err_port_fids_init:1849	mlxsw_sp_port_dcb_fini(mlxsw_sp_port);1850err_port_dcb_init:1851	mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false);1852err_port_tc_mc_mode:1853err_port_ets_init:1854	mlxsw_sp_port_buffers_fini(mlxsw_sp_port);1855err_port_buffers_init:1856err_port_admin_status_set:1857err_port_mtu_set:1858err_max_speed_get:1859err_port_speed_by_width_set:1860err_port_system_port_mapping_set:1861err_dev_addr_init:1862	free_percpu(mlxsw_sp_port->pcpu_stats);1863err_alloc_stats:1864	free_netdev(dev);1865err_alloc_etherdev:1866	mlxsw_core_port_fini(mlxsw_sp->core, local_port);1867err_core_port_init:1868err_port_label_info_get:1869	mlxsw_sp_port_swid_set(mlxsw_sp, local_port,1870			       MLXSW_PORT_SWID_DISABLED_PORT);1871err_port_swid_set:1872	mlxsw_sp_port_module_unmap(mlxsw_sp, local_port,1873				   port_mapping->slot_index,1874				   port_mapping->module);1875	return err;1876}1877 1878static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u16 local_port)1879{1880	struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];1881	u8 slot_index = mlxsw_sp_port->mapping.slot_index;1882	u8 module = mlxsw_sp_port->mapping.module;1883 1884	cancel_delayed_work_sync(&mlxsw_sp_port->periodic_hw_stats.update_dw);1885	cancel_delayed_work_sync(&mlxsw_sp_port->ptp.shaper_dw);1886	unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */1887	mlxsw_sp_port_ptp_clear(mlxsw_sp_port);1888	mlxsw_sp_port_vlan_classification_set(mlxsw_sp_port, true, true);1889	mlxsw_sp->ports[local_port] = NULL;1890	mlxsw_sp_port_vlan_flush(mlxsw_sp_port, true);1891	mlxsw_sp_port_nve_fini(mlxsw_sp_port);1892	mlxsw_sp_tc_qdisc_fini(mlxsw_sp_port);1893	mlxsw_sp_port_fids_fini(mlxsw_sp_port);1894	mlxsw_sp_port_dcb_fini(mlxsw_sp_port);1895	mlxsw_sp_port_tc_mc_mode_set(mlxsw_sp_port, false);1896	mlxsw_sp_port_buffers_fini(mlxsw_sp_port);1897	free_percpu(mlxsw_sp_port->pcpu_stats);1898	WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vlans_list));1899	free_netdev(mlxsw_sp_port->dev);1900	mlxsw_core_port_fini(mlxsw_sp->core, local_port);1901	mlxsw_sp_port_swid_set(mlxsw_sp, local_port,1902			       MLXSW_PORT_SWID_DISABLED_PORT);1903	mlxsw_sp_port_module_unmap(mlxsw_sp, local_port, slot_index, module);1904}1905 1906static int mlxsw_sp_cpu_port_create(struct mlxsw_sp *mlxsw_sp)1907{1908	struct mlxsw_sp_port *mlxsw_sp_port;1909	int err;1910 1911	mlxsw_sp_port = kzalloc(sizeof(*mlxsw_sp_port), GFP_KERNEL);1912	if (!mlxsw_sp_port)1913		return -ENOMEM;1914 1915	mlxsw_sp_port->mlxsw_sp = mlxsw_sp;1916	mlxsw_sp_port->local_port = MLXSW_PORT_CPU_PORT;1917 1918	err = mlxsw_core_cpu_port_init(mlxsw_sp->core,1919				       mlxsw_sp_port,1920				       mlxsw_sp->base_mac,1921				       sizeof(mlxsw_sp->base_mac));1922	if (err) {1923		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize core CPU port\n");1924		goto err_core_cpu_port_init;1925	}1926 1927	mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = mlxsw_sp_port;1928	return 0;1929 1930err_core_cpu_port_init:1931	kfree(mlxsw_sp_port);1932	return err;1933}1934 1935static void mlxsw_sp_cpu_port_remove(struct mlxsw_sp *mlxsw_sp)1936{1937	struct mlxsw_sp_port *mlxsw_sp_port =1938				mlxsw_sp->ports[MLXSW_PORT_CPU_PORT];1939 1940	mlxsw_core_cpu_port_fini(mlxsw_sp->core);1941	mlxsw_sp->ports[MLXSW_PORT_CPU_PORT] = NULL;1942	kfree(mlxsw_sp_port);1943}1944 1945static bool mlxsw_sp_local_port_valid(u16 local_port)1946{1947	return local_port != MLXSW_PORT_CPU_PORT;1948}1949 1950static bool mlxsw_sp_port_created(struct mlxsw_sp *mlxsw_sp, u16 local_port)1951{1952	if (!mlxsw_sp_local_port_valid(local_port))1953		return false;1954	return mlxsw_sp->ports[local_port] != NULL;1955}1956 1957static int mlxsw_sp_port_mapping_event_set(struct mlxsw_sp *mlxsw_sp,1958					   u16 local_port, bool enable)1959{1960	char pmecr_pl[MLXSW_REG_PMECR_LEN];1961 1962	mlxsw_reg_pmecr_pack(pmecr_pl, local_port,1963			     enable ? MLXSW_REG_PMECR_E_GENERATE_EVENT :1964				      MLXSW_REG_PMECR_E_DO_NOT_GENERATE_EVENT);1965	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmecr), pmecr_pl);1966}1967 1968struct mlxsw_sp_port_mapping_event {1969	struct list_head list;1970	char pmlp_pl[MLXSW_REG_PMLP_LEN];1971};1972 1973static void mlxsw_sp_port_mapping_events_work(struct work_struct *work)1974{1975	struct mlxsw_sp_port_mapping_event *event, *next_event;1976	struct mlxsw_sp_port_mapping_events *events;1977	struct mlxsw_sp_port_mapping port_mapping;1978	struct mlxsw_sp *mlxsw_sp;1979	struct devlink *devlink;1980	LIST_HEAD(event_queue);1981	u16 local_port;1982	int err;1983 1984	events = container_of(work, struct mlxsw_sp_port_mapping_events, work);1985	mlxsw_sp = container_of(events, struct mlxsw_sp, port_mapping_events);1986	devlink = priv_to_devlink(mlxsw_sp->core);1987 1988	spin_lock_bh(&events->queue_lock);1989	list_splice_init(&events->queue, &event_queue);1990	spin_unlock_bh(&events->queue_lock);1991 1992	list_for_each_entry_safe(event, next_event, &event_queue, list) {1993		local_port = mlxsw_reg_pmlp_local_port_get(event->pmlp_pl);1994		err = mlxsw_sp_port_module_info_parse(mlxsw_sp, local_port,1995						      event->pmlp_pl, &port_mapping);1996		if (err)1997			goto out;1998 1999		if (WARN_ON_ONCE(!port_mapping.width))2000			goto out;2001 2002		devl_lock(devlink);2003 2004		if (!mlxsw_sp_port_created(mlxsw_sp, local_port))2005			mlxsw_sp_port_create(mlxsw_sp, local_port,2006					     false, &port_mapping);2007		else2008			WARN_ON_ONCE(1);2009 2010		devl_unlock(devlink);2011 2012		mlxsw_sp->port_mapping[local_port] = port_mapping;2013 2014out:2015		kfree(event);2016	}2017}2018 2019static void2020mlxsw_sp_port_mapping_listener_func(const struct mlxsw_reg_info *reg,2021				    char *pmlp_pl, void *priv)2022{2023	struct mlxsw_sp_port_mapping_events *events;2024	struct mlxsw_sp_port_mapping_event *event;2025	struct mlxsw_sp *mlxsw_sp = priv;2026	u16 local_port;2027 2028	local_port = mlxsw_reg_pmlp_local_port_get(pmlp_pl);2029	if (WARN_ON_ONCE(!mlxsw_sp_local_port_is_valid(mlxsw_sp, local_port)))2030		return;2031 2032	events = &mlxsw_sp->port_mapping_events;2033	event = kmalloc(sizeof(*event), GFP_ATOMIC);2034	if (!event)2035		return;2036	memcpy(event->pmlp_pl, pmlp_pl, sizeof(event->pmlp_pl));2037	spin_lock(&events->queue_lock);2038	list_add_tail(&event->list, &events->queue);2039	spin_unlock(&events->queue_lock);2040	mlxsw_core_schedule_work(&events->work);2041}2042 2043static void2044__mlxsw_sp_port_mapping_events_cancel(struct mlxsw_sp *mlxsw_sp)2045{2046	struct mlxsw_sp_port_mapping_event *event, *next_event;2047	struct mlxsw_sp_port_mapping_events *events;2048 2049	events = &mlxsw_sp->port_mapping_events;2050 2051	/* Caller needs to make sure that no new event is going to appear. */2052	cancel_work_sync(&events->work);2053	list_for_each_entry_safe(event, next_event, &events->queue, list) {2054		list_del(&event->list);2055		kfree(event);2056	}2057}2058 2059static void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp)2060{2061	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);2062	int i;2063 2064	for (i = 1; i < max_ports; i++)2065		mlxsw_sp_port_mapping_event_set(mlxsw_sp, i, false);2066	/* Make sure all scheduled events are processed */2067	__mlxsw_sp_port_mapping_events_cancel(mlxsw_sp);2068 2069	for (i = 1; i < max_ports; i++)2070		if (mlxsw_sp_port_created(mlxsw_sp, i))2071			mlxsw_sp_port_remove(mlxsw_sp, i);2072	mlxsw_sp_cpu_port_remove(mlxsw_sp);2073	kfree(mlxsw_sp->ports);2074	mlxsw_sp->ports = NULL;2075}2076 2077static void2078mlxsw_sp_ports_remove_selected(struct mlxsw_core *mlxsw_core,2079			       bool (*selector)(void *priv, u16 local_port),2080			       void *priv)2081{2082	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);2083	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_core);2084	int i;2085 2086	for (i = 1; i < max_ports; i++)2087		if (mlxsw_sp_port_created(mlxsw_sp, i) && selector(priv, i))2088			mlxsw_sp_port_remove(mlxsw_sp, i);2089}2090 2091static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)2092{2093	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);2094	struct mlxsw_sp_port_mapping_events *events;2095	struct mlxsw_sp_port_mapping *port_mapping;2096	size_t alloc_size;2097	int i;2098	int err;2099 2100	alloc_size = sizeof(struct mlxsw_sp_port *) * max_ports;2101	mlxsw_sp->ports = kzalloc(alloc_size, GFP_KERNEL);2102	if (!mlxsw_sp->ports)2103		return -ENOMEM;2104 2105	events = &mlxsw_sp->port_mapping_events;2106	INIT_LIST_HEAD(&events->queue);2107	spin_lock_init(&events->queue_lock);2108	INIT_WORK(&events->work, mlxsw_sp_port_mapping_events_work);2109 2110	for (i = 1; i < max_ports; i++) {2111		err = mlxsw_sp_port_mapping_event_set(mlxsw_sp, i, true);2112		if (err)2113			goto err_event_enable;2114	}2115 2116	err = mlxsw_sp_cpu_port_create(mlxsw_sp);2117	if (err)2118		goto err_cpu_port_create;2119 2120	for (i = 1; i < max_ports; i++) {2121		port_mapping = &mlxsw_sp->port_mapping[i];2122		if (!port_mapping->width)2123			continue;2124		err = mlxsw_sp_port_create(mlxsw_sp, i, false, port_mapping);2125		if (err)2126			goto err_port_create;2127	}2128	return 0;2129 2130err_port_create:2131	for (i--; i >= 1; i--)2132		if (mlxsw_sp_port_created(mlxsw_sp, i))2133			mlxsw_sp_port_remove(mlxsw_sp, i);2134	i = max_ports;2135	mlxsw_sp_cpu_port_remove(mlxsw_sp);2136err_cpu_port_create:2137err_event_enable:2138	for (i--; i >= 1; i--)2139		mlxsw_sp_port_mapping_event_set(mlxsw_sp, i, false);2140	/* Make sure all scheduled events are processed */2141	__mlxsw_sp_port_mapping_events_cancel(mlxsw_sp);2142	kfree(mlxsw_sp->ports);2143	mlxsw_sp->ports = NULL;2144	return err;2145}2146 2147static int mlxsw_sp_port_module_info_init(struct mlxsw_sp *mlxsw_sp)2148{2149	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);2150	struct mlxsw_sp_port_mapping *port_mapping;2151	int i;2152	int err;2153 2154	mlxsw_sp->port_mapping = kcalloc(max_ports,2155					 sizeof(struct mlxsw_sp_port_mapping),2156					 GFP_KERNEL);2157	if (!mlxsw_sp->port_mapping)2158		return -ENOMEM;2159 2160	for (i = 1; i < max_ports; i++) {2161		port_mapping = &mlxsw_sp->port_mapping[i];2162		err = mlxsw_sp_port_module_info_get(mlxsw_sp, i, port_mapping);2163		if (err)2164			goto err_port_module_info_get;2165	}2166	return 0;2167 2168err_port_module_info_get:2169	kfree(mlxsw_sp->port_mapping);2170	return err;2171}2172 2173static void mlxsw_sp_port_module_info_fini(struct mlxsw_sp *mlxsw_sp)2174{2175	kfree(mlxsw_sp->port_mapping);2176}2177 2178static int2179mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp,2180			   struct mlxsw_sp_port_mapping *port_mapping,2181			   unsigned int count, const char *pmtdb_pl)2182{2183	struct mlxsw_sp_port_mapping split_port_mapping;2184	int err, i;2185 2186	split_port_mapping = *port_mapping;2187	split_port_mapping.width /= count;2188	for (i = 0; i < count; i++) {2189		u16 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);2190 2191		if (!mlxsw_sp_local_port_valid(s_local_port))2192			continue;2193 2194		err = mlxsw_sp_port_create(mlxsw_sp, s_local_port,2195					   true, &split_port_mapping);2196		if (err)2197			goto err_port_create;2198		split_port_mapping.lane += split_port_mapping.width;2199	}2200 2201	return 0;2202 2203err_port_create:2204	for (i--; i >= 0; i--) {2205		u16 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);2206 2207		if (mlxsw_sp_port_created(mlxsw_sp, s_local_port))2208			mlxsw_sp_port_remove(mlxsw_sp, s_local_port);2209	}2210	return err;2211}2212 2213static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp,2214					 unsigned int count,2215					 const char *pmtdb_pl)2216{2217	struct mlxsw_sp_port_mapping *port_mapping;2218	int i;2219 2220	/* Go over original unsplit ports in the gap and recreate them. */2221	for (i = 0; i < count; i++) {2222		u16 local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);2223 2224		port_mapping = &mlxsw_sp->port_mapping[local_port];2225		if (!port_mapping->width || !mlxsw_sp_local_port_valid(local_port))2226			continue;2227		mlxsw_sp_port_create(mlxsw_sp, local_port,2228				     false, port_mapping);2229	}2230}2231 2232static struct mlxsw_sp_port *2233mlxsw_sp_port_get_by_local_port(struct mlxsw_sp *mlxsw_sp, u16 local_port)2234{2235	if (mlxsw_sp->ports && mlxsw_sp->ports[local_port])2236		return mlxsw_sp->ports[local_port];2237	return NULL;2238}2239 2240static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u16 local_port,2241			       unsigned int count,2242			       struct netlink_ext_ack *extack)2243{2244	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);2245	struct mlxsw_sp_port_mapping port_mapping;2246	struct mlxsw_sp_port *mlxsw_sp_port;2247	enum mlxsw_reg_pmtdb_status status;2248	char pmtdb_pl[MLXSW_REG_PMTDB_LEN];2249	int i;2250	int err;2251 2252	mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port);2253	if (!mlxsw_sp_port) {2254		dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n",2255			local_port);2256		NL_SET_ERR_MSG_MOD(extack, "Port number does not exist");2257		return -EINVAL;2258	}2259 2260	if (mlxsw_sp_port->split) {2261		NL_SET_ERR_MSG_MOD(extack, "Port is already split");2262		return -EINVAL;2263	}2264 2265	mlxsw_reg_pmtdb_pack(pmtdb_pl, mlxsw_sp_port->mapping.slot_index,2266			     mlxsw_sp_port->mapping.module,2267			     mlxsw_sp_port->mapping.module_width / count,2268			     count);2269	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtdb), pmtdb_pl);2270	if (err) {2271		NL_SET_ERR_MSG_MOD(extack, "Failed to query split info");2272		return err;2273	}2274 2275	status = mlxsw_reg_pmtdb_status_get(pmtdb_pl);2276	if (status != MLXSW_REG_PMTDB_STATUS_SUCCESS) {2277		NL_SET_ERR_MSG_MOD(extack, "Unsupported split configuration");2278		return -EINVAL;2279	}2280 2281	port_mapping = mlxsw_sp_port->mapping;2282 2283	for (i = 0; i < count; i++) {2284		u16 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);2285 2286		if (mlxsw_sp_port_created(mlxsw_sp, s_local_port))2287			mlxsw_sp_port_remove(mlxsw_sp, s_local_port);2288	}2289 2290	err = mlxsw_sp_port_split_create(mlxsw_sp, &port_mapping,2291					 count, pmtdb_pl);2292	if (err) {2293		dev_err(mlxsw_sp->bus_info->dev, "Failed to create split ports\n");2294		goto err_port_split_create;2295	}2296 2297	return 0;2298 2299err_port_split_create:2300	mlxsw_sp_port_unsplit_create(mlxsw_sp, count, pmtdb_pl);2301 2302	return err;2303}2304 2305static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u16 local_port,2306				 struct netlink_ext_ack *extack)2307{2308	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);2309	struct mlxsw_sp_port *mlxsw_sp_port;2310	char pmtdb_pl[MLXSW_REG_PMTDB_LEN];2311	unsigned int count;2312	int i;2313	int err;2314 2315	mlxsw_sp_port = mlxsw_sp_port_get_by_local_port(mlxsw_sp, local_port);2316	if (!mlxsw_sp_port) {2317		dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n",2318			local_port);2319		NL_SET_ERR_MSG_MOD(extack, "Port number does not exist");2320		return -EINVAL;2321	}2322 2323	if (!mlxsw_sp_port->split) {2324		NL_SET_ERR_MSG_MOD(extack, "Port was not split");2325		return -EINVAL;2326	}2327 2328	count = mlxsw_sp_port->mapping.module_width /2329		mlxsw_sp_port->mapping.width;2330 2331	mlxsw_reg_pmtdb_pack(pmtdb_pl, mlxsw_sp_port->mapping.slot_index,2332			     mlxsw_sp_port->mapping.module,2333			     mlxsw_sp_port->mapping.module_width / count,2334			     count);2335	err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtdb), pmtdb_pl);2336	if (err) {2337		NL_SET_ERR_MSG_MOD(extack, "Failed to query split info");2338		return err;2339	}2340 2341	for (i = 0; i < count; i++) {2342		u16 s_local_port = mlxsw_reg_pmtdb_port_num_get(pmtdb_pl, i);2343 2344		if (mlxsw_sp_port_created(mlxsw_sp, s_local_port))2345			mlxsw_sp_port_remove(mlxsw_sp, s_local_port);2346	}2347 2348	mlxsw_sp_port_unsplit_create(mlxsw_sp, count, pmtdb_pl);2349 2350	return 0;2351}2352 2353static void2354mlxsw_sp_port_down_wipe_counters(struct mlxsw_sp_port *mlxsw_sp_port)2355{2356	int i;2357 2358	for (i = 0; i < TC_MAX_QUEUE; i++)2359		mlxsw_sp_port->periodic_hw_stats.xstats.backlog[i] = 0;2360}2361 2362static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,2363				     char *pude_pl, void *priv)2364{2365	struct mlxsw_sp *mlxsw_sp = priv;2366	struct mlxsw_sp_port *mlxsw_sp_port;2367	enum mlxsw_reg_pude_oper_status status;2368	u16 local_port;2369 2370	local_port = mlxsw_reg_pude_local_port_get(pude_pl);2371 2372	if (WARN_ON_ONCE(!mlxsw_sp_local_port_is_valid(mlxsw_sp, local_port)))2373		return;2374	mlxsw_sp_port = mlxsw_sp->ports[local_port];2375	if (!mlxsw_sp_port)2376		return;2377 2378	status = mlxsw_reg_pude_oper_status_get(pude_pl);2379	if (status == MLXSW_PORT_OPER_STATUS_UP) {2380		netdev_info(mlxsw_sp_port->dev, "link up\n");2381		netif_carrier_on(mlxsw_sp_port->dev);2382		mlxsw_core_schedule_dw(&mlxsw_sp_port->ptp.shaper_dw, 0);2383	} else {2384		netdev_info(mlxsw_sp_port->dev, "link down\n");2385		netif_carrier_off(mlxsw_sp_port->dev);2386		mlxsw_sp_port_down_wipe_counters(mlxsw_sp_port);2387	}2388}2389 2390static void mlxsw_sp1_ptp_fifo_event_func(struct mlxsw_sp *mlxsw_sp,2391					  char *mtpptr_pl, bool ingress)2392{2393	u16 local_port;2394	u8 num_rec;2395	int i;2396 2397	local_port = mlxsw_reg_mtpptr_local_port_get(mtpptr_pl);2398	num_rec = mlxsw_reg_mtpptr_num_rec_get(mtpptr_pl);2399	for (i = 0; i < num_rec; i++) {2400		u8 domain_number;2401		u8 message_type;2402		u16 sequence_id;2403		u64 timestamp;2404 2405		mlxsw_reg_mtpptr_unpack(mtpptr_pl, i, &message_type,2406					&domain_number, &sequence_id,2407					&timestamp);2408		mlxsw_sp1_ptp_got_timestamp(mlxsw_sp, ingress, local_port,2409					    message_type, domain_number,2410					    sequence_id, timestamp);2411	}2412}2413 2414static void mlxsw_sp1_ptp_ing_fifo_event_func(const struct mlxsw_reg_info *reg,2415					      char *mtpptr_pl, void *priv)2416{2417	struct mlxsw_sp *mlxsw_sp = priv;2418 2419	mlxsw_sp1_ptp_fifo_event_func(mlxsw_sp, mtpptr_pl, true);2420}2421 2422static void mlxsw_sp1_ptp_egr_fifo_event_func(const struct mlxsw_reg_info *reg,2423					      char *mtpptr_pl, void *priv)2424{2425	struct mlxsw_sp *mlxsw_sp = priv;2426 2427	mlxsw_sp1_ptp_fifo_event_func(mlxsw_sp, mtpptr_pl, false);2428}2429 2430void mlxsw_sp_rx_listener_no_mark_func(struct sk_buff *skb,2431				       u16 local_port, void *priv)2432{2433	struct mlxsw_sp *mlxsw_sp = priv;2434	struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];2435	struct mlxsw_sp_port_pcpu_stats *pcpu_stats;2436 2437	if (unlikely(!mlxsw_sp_port)) {2438		dev_warn_ratelimited(mlxsw_sp->bus_info->dev, "Port %d: skb received for non-existent port\n",2439				     local_port);2440		return;2441	}2442 2443	skb->dev = mlxsw_sp_port->dev;2444 2445	pcpu_stats = this_cpu_ptr(mlxsw_sp_port->pcpu_stats);2446	u64_stats_update_begin(&pcpu_stats->syncp);2447	pcpu_stats->rx_packets++;2448	pcpu_stats->rx_bytes += skb->len;2449	u64_stats_update_end(&pcpu_stats->syncp);2450 2451	skb->protocol = eth_type_trans(skb, skb->dev);2452	netif_receive_skb(skb);2453}2454 2455static void mlxsw_sp_rx_listener_mark_func(struct sk_buff *skb, u16 local_port,2456					   void *priv)2457{2458	skb->offload_fwd_mark = 1;2459	return mlxsw_sp_rx_listener_no_mark_func(skb, local_port, priv);2460}2461 2462static void mlxsw_sp_rx_listener_l3_mark_func(struct sk_buff *skb,2463					      u16 local_port, void *priv)2464{2465	skb->offload_l3_fwd_mark = 1;2466	skb->offload_fwd_mark = 1;2467	return mlxsw_sp_rx_listener_no_mark_func(skb, local_port, priv);2468}2469 2470void mlxsw_sp_ptp_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,2471			  u16 local_port)2472{2473	mlxsw_sp->ptp_ops->receive(mlxsw_sp, skb, local_port);2474}2475 2476#define MLXSW_SP_RXL_NO_MARK(_trap_id, _action, _trap_group, _is_ctrl)	\2477	MLXSW_RXL(mlxsw_sp_rx_listener_no_mark_func, _trap_id, _action,	\2478		  _is_ctrl, SP_##_trap_group, DISCARD)2479 2480#define MLXSW_SP_RXL_MARK(_trap_id, _action, _trap_group, _is_ctrl)	\2481	MLXSW_RXL(mlxsw_sp_rx_listener_mark_func, _trap_id, _action,	\2482		_is_ctrl, SP_##_trap_group, DISCARD)2483 2484#define MLXSW_SP_RXL_L3_MARK(_trap_id, _action, _trap_group, _is_ctrl)	\2485	MLXSW_RXL(mlxsw_sp_rx_listener_l3_mark_func, _trap_id, _action,	\2486		_is_ctrl, SP_##_trap_group, DISCARD)2487 2488#define MLXSW_SP_EVENTL(_func, _trap_id)		\2489	MLXSW_EVENTL(_func, _trap_id, SP_EVENT)2490 2491static const struct mlxsw_listener mlxsw_sp_listener[] = {2492	/* Events */2493	MLXSW_SP_EVENTL(mlxsw_sp_pude_event_func, PUDE),2494	/* L2 traps */2495	MLXSW_SP_RXL_NO_MARK(FID_MISS, TRAP_TO_CPU, FID_MISS, false),2496	/* L3 traps */2497	MLXSW_SP_RXL_MARK(IPV6_UNSPECIFIED_ADDRESS, TRAP_TO_CPU, ROUTER_EXP,2498			  false),2499	MLXSW_SP_RXL_MARK(IPV6_LINK_LOCAL_SRC, TRAP_TO_CPU, ROUTER_EXP, false),2500	MLXSW_SP_RXL_MARK(IPV6_MC_LINK_LOCAL_DEST, TRAP_TO_CPU, ROUTER_EXP,2501			  false),2502	MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_SIP_CLASS_E, FORWARD,2503			     ROUTER_EXP, false),2504	MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_MC_DMAC, FORWARD,2505			     ROUTER_EXP, false),2506	MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_SIP_DIP, FORWARD,2507			     ROUTER_EXP, false),2508	MLXSW_SP_RXL_NO_MARK(DISCARD_ING_ROUTER_DIP_LINK_LOCAL, FORWARD,2509			     ROUTER_EXP, false),2510	/* Multicast Router Traps */2511	MLXSW_SP_RXL_MARK(ACL1, TRAP_TO_CPU, MULTICAST, false),2512	MLXSW_SP_RXL_L3_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false),2513	/* NVE traps */2514	MLXSW_SP_RXL_MARK(NVE_ENCAP_ARP, TRAP_TO_CPU, NEIGH_DISCOVERY, false),2515};2516 2517static const struct mlxsw_listener mlxsw_sp1_listener[] = {2518	/* Events */2519	MLXSW_EVENTL(mlxsw_sp1_ptp_egr_fifo_event_func, PTP_EGR_FIFO, SP_PTP0),2520	MLXSW_EVENTL(mlxsw_sp1_ptp_ing_fifo_event_func, PTP_ING_FIFO, SP_PTP0),2521};2522 2523static const struct mlxsw_listener mlxsw_sp2_listener[] = {2524	/* Events */2525	MLXSW_SP_EVENTL(mlxsw_sp_port_mapping_listener_func, PMLPE),2526};2527 2528static int mlxsw_sp_cpu_policers_set(struct mlxsw_core *mlxsw_core)2529{2530	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);2531	char qpcr_pl[MLXSW_REG_QPCR_LEN];2532	enum mlxsw_reg_qpcr_ir_units ir_units;2533	int max_cpu_policers;2534	bool is_bytes;2535	u8 burst_size;2536	u32 rate;2537	int i, err;2538 2539	if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_CPU_POLICERS))2540		return -EIO;2541 2542	max_cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS);2543 2544	ir_units = MLXSW_REG_QPCR_IR_UNITS_M;2545	for (i = 0; i < max_cpu_policers; i++) {2546		is_bytes = false;2547		switch (i) {2548		case MLXSW_REG_HTGT_TRAP_GROUP_SP_ROUTER_EXP:2549		case MLXSW_REG_HTGT_TRAP_GROUP_SP_MULTICAST:2550		case MLXSW_REG_HTGT_TRAP_GROUP_SP_FID_MISS:2551			rate = 1024;2552			burst_size = 7;2553			break;2554		default:2555			continue;2556		}2557 2558		__set_bit(i, mlxsw_sp->trap->policers_usage);2559		mlxsw_reg_qpcr_pack(qpcr_pl, i, ir_units, is_bytes, rate,2560				    burst_size);2561		err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(qpcr), qpcr_pl);2562		if (err)2563			return err;2564	}2565 2566	return 0;2567}2568 2569static int mlxsw_sp_trap_groups_set(struct mlxsw_core *mlxsw_core)2570{2571	char htgt_pl[MLXSW_REG_HTGT_LEN];2572	enum mlxsw_reg_htgt_trap_group i;2573	int max_cpu_policers;2574	int max_trap_groups;2575	u8 priority, tc;2576	u16 policer_id;2577	int err;2578 2579	if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_TRAP_GROUPS))2580		return -EIO;2581 2582	max_trap_groups = MLXSW_CORE_RES_GET(mlxsw_core, MAX_TRAP_GROUPS);2583	max_cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS);2584 2585	for (i = 0; i < max_trap_groups; i++) {2586		policer_id = i;2587		switch (i) {2588		case MLXSW_REG_HTGT_TRAP_GROUP_SP_ROUTER_EXP:2589		case MLXSW_REG_HTGT_TRAP_GROUP_SP_MULTICAST:2590		case MLXSW_REG_HTGT_TRAP_GROUP_SP_FID_MISS:2591			priority = 1;2592			tc = 1;2593			break;2594		case MLXSW_REG_HTGT_TRAP_GROUP_SP_EVENT:2595			priority = MLXSW_REG_HTGT_DEFAULT_PRIORITY;2596			tc = MLXSW_REG_HTGT_DEFAULT_TC;2597			policer_id = MLXSW_REG_HTGT_INVALID_POLICER;2598			break;2599		default:2600			continue;2601		}2602 2603		if (max_cpu_policers <= policer_id &&2604		    policer_id != MLXSW_REG_HTGT_INVALID_POLICER)2605			return -EIO;2606 2607		mlxsw_reg_htgt_pack(htgt_pl, i, policer_id, priority, tc);2608		err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl);2609		if (err)2610			return err;2611	}2612 2613	return 0;2614}2615 2616static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)2617{2618	struct mlxsw_sp_trap *trap;2619	u64 max_policers;2620	int err;2621 2622	if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_CPU_POLICERS))2623		return -EIO;2624	max_policers = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_CPU_POLICERS);2625	trap = kzalloc(struct_size(trap, policers_usage,2626				   BITS_TO_LONGS(max_policers)), GFP_KERNEL);2627	if (!trap)2628		return -ENOMEM;2629	trap->max_policers = max_policers;2630	mlxsw_sp->trap = trap;2631 2632	err = mlxsw_sp_cpu_policers_set(mlxsw_sp->core);2633	if (err)2634		goto err_cpu_policers_set;2635 2636	err = mlxsw_sp_trap_groups_set(mlxsw_sp->core);2637	if (err)2638		goto err_trap_groups_set;2639 2640	err = mlxsw_core_traps_register(mlxsw_sp->core, mlxsw_sp_listener,2641					ARRAY_SIZE(mlxsw_sp_listener),2642					mlxsw_sp);2643	if (err)2644		goto err_traps_register;2645 2646	err = mlxsw_core_traps_register(mlxsw_sp->core, mlxsw_sp->listeners,2647					mlxsw_sp->listeners_count, mlxsw_sp);2648	if (err)2649		goto err_extra_traps_init;2650 2651	return 0;2652 2653err_extra_traps_init:2654	mlxsw_core_traps_unregister(mlxsw_sp->core, mlxsw_sp_listener,2655				    ARRAY_SIZE(mlxsw_sp_listener),2656				    mlxsw_sp);2657err_traps_register:2658err_trap_groups_set:2659err_cpu_policers_set:2660	kfree(trap);2661	return err;2662}2663 2664static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp)2665{2666	mlxsw_core_traps_unregister(mlxsw_sp->core, mlxsw_sp->listeners,2667				    mlxsw_sp->listeners_count,2668				    mlxsw_sp);2669	mlxsw_core_traps_unregister(mlxsw_sp->core, mlxsw_sp_listener,2670				    ARRAY_SIZE(mlxsw_sp_listener), mlxsw_sp);2671	kfree(mlxsw_sp->trap);2672}2673 2674static int mlxsw_sp_lag_pgt_init(struct mlxsw_sp *mlxsw_sp)2675{2676	char sgcr_pl[MLXSW_REG_SGCR_LEN];2677	int err;2678 2679	if (mlxsw_core_lag_mode(mlxsw_sp->core) !=2680	    MLXSW_CMD_MBOX_CONFIG_PROFILE_LAG_MODE_SW)2681		return 0;2682 2683	/* In DDD mode, which we by default use, each LAG entry is 8 PGT2684	 * entries. The LAG table address needs to be 8-aligned, but that ought2685	 * to be the case, since the LAG table is allocated first.2686	 */2687	err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, &mlxsw_sp->lag_pgt_base,2688					   mlxsw_sp->max_lag * 8);2689	if (err)2690		return err;2691	if (WARN_ON_ONCE(mlxsw_sp->lag_pgt_base % 8)) {2692		err = -EINVAL;2693		goto err_mid_alloc_range;2694	}2695 2696	mlxsw_reg_sgcr_pack(sgcr_pl, mlxsw_sp->lag_pgt_base);2697	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sgcr), sgcr_pl);2698	if (err)2699		goto err_mid_alloc_range;2700 2701	return 0;2702 2703err_mid_alloc_range:2704	mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mlxsw_sp->lag_pgt_base,2705				    mlxsw_sp->max_lag * 8);2706	return err;2707}2708 2709static void mlxsw_sp_lag_pgt_fini(struct mlxsw_sp *mlxsw_sp)2710{2711	if (mlxsw_core_lag_mode(mlxsw_sp->core) !=2712	    MLXSW_CMD_MBOX_CONFIG_PROFILE_LAG_MODE_SW)2713		return;2714 2715	mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mlxsw_sp->lag_pgt_base,2716				    mlxsw_sp->max_lag * 8);2717}2718 2719#define MLXSW_SP_LAG_SEED_INIT 0xcafecafe2720 2721struct mlxsw_sp_lag {2722	struct net_device *dev;2723	refcount_t ref_count;2724	u16 lag_id;2725};2726 2727static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp)2728{2729	char slcr_pl[MLXSW_REG_SLCR_LEN];2730	u32 seed;2731	int err;2732 2733	seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac),2734		     MLXSW_SP_LAG_SEED_INIT);2735	mlxsw_reg_slcr_pack(slcr_pl, MLXSW_REG_SLCR_LAG_HASH_SMAC |2736				     MLXSW_REG_SLCR_LAG_HASH_DMAC |2737				     MLXSW_REG_SLCR_LAG_HASH_ETHERTYPE |2738				     MLXSW_REG_SLCR_LAG_HASH_VLANID |2739				     MLXSW_REG_SLCR_LAG_HASH_SIP |2740				     MLXSW_REG_SLCR_LAG_HASH_DIP |2741				     MLXSW_REG_SLCR_LAG_HASH_SPORT |2742				     MLXSW_REG_SLCR_LAG_HASH_DPORT |2743				     MLXSW_REG_SLCR_LAG_HASH_IPPROTO, seed);2744	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcr), slcr_pl);2745	if (err)2746		return err;2747 2748	err = mlxsw_core_max_lag(mlxsw_sp->core, &mlxsw_sp->max_lag);2749	if (err)2750		return err;2751 2752	if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_LAG_MEMBERS))2753		return -EIO;2754 2755	err = mlxsw_sp_lag_pgt_init(mlxsw_sp);2756	if (err)2757		return err;2758 2759	mlxsw_sp->lags = kcalloc(mlxsw_sp->max_lag, sizeof(struct mlxsw_sp_lag),2760				 GFP_KERNEL);2761	if (!mlxsw_sp->lags) {2762		err = -ENOMEM;2763		goto err_kcalloc;2764	}2765 2766	return 0;2767 2768err_kcalloc:2769	mlxsw_sp_lag_pgt_fini(mlxsw_sp);2770	return err;2771}2772 2773static void mlxsw_sp_lag_fini(struct mlxsw_sp *mlxsw_sp)2774{2775	mlxsw_sp_lag_pgt_fini(mlxsw_sp);2776	kfree(mlxsw_sp->lags);2777}2778 2779static const struct mlxsw_sp_ptp_ops mlxsw_sp1_ptp_ops = {2780	.clock_init	= mlxsw_sp1_ptp_clock_init,2781	.clock_fini	= mlxsw_sp1_ptp_clock_fini,2782	.init		= mlxsw_sp1_ptp_init,2783	.fini		= mlxsw_sp1_ptp_fini,2784	.receive	= mlxsw_sp1_ptp_receive,2785	.transmitted	= mlxsw_sp1_ptp_transmitted,2786	.hwtstamp_get	= mlxsw_sp1_ptp_hwtstamp_get,2787	.hwtstamp_set	= mlxsw_sp1_ptp_hwtstamp_set,2788	.shaper_work	= mlxsw_sp1_ptp_shaper_work,2789#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)2790	.get_ts_info	= mlxsw_sp1_ptp_get_ts_info,2791#endif2792	.get_stats_count = mlxsw_sp1_get_stats_count,2793	.get_stats_strings = mlxsw_sp1_get_stats_strings,2794	.get_stats	= mlxsw_sp1_get_stats,2795	.txhdr_construct = mlxsw_sp_ptp_txhdr_construct,2796};2797 2798static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = {2799	.clock_init	= mlxsw_sp2_ptp_clock_init,2800	.clock_fini	= mlxsw_sp2_ptp_clock_fini,2801	.init		= mlxsw_sp2_ptp_init,2802	.fini		= mlxsw_sp2_ptp_fini,2803	.receive	= mlxsw_sp2_ptp_receive,2804	.transmitted	= mlxsw_sp2_ptp_transmitted,2805	.hwtstamp_get	= mlxsw_sp2_ptp_hwtstamp_get,2806	.hwtstamp_set	= mlxsw_sp2_ptp_hwtstamp_set,2807	.shaper_work	= mlxsw_sp2_ptp_shaper_work,2808#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)2809	.get_ts_info	= mlxsw_sp2_ptp_get_ts_info,2810#endif2811	.get_stats_count = mlxsw_sp2_get_stats_count,2812	.get_stats_strings = mlxsw_sp2_get_stats_strings,2813	.get_stats	= mlxsw_sp2_get_stats,2814	.txhdr_construct = mlxsw_sp2_ptp_txhdr_construct,2815};2816 2817static const struct mlxsw_sp_ptp_ops mlxsw_sp4_ptp_ops = {2818	.clock_init	= mlxsw_sp2_ptp_clock_init,2819	.clock_fini	= mlxsw_sp2_ptp_clock_fini,2820	.init		= mlxsw_sp2_ptp_init,2821	.fini		= mlxsw_sp2_ptp_fini,2822	.receive	= mlxsw_sp2_ptp_receive,2823	.transmitted	= mlxsw_sp2_ptp_transmitted,2824	.hwtstamp_get	= mlxsw_sp2_ptp_hwtstamp_get,2825	.hwtstamp_set	= mlxsw_sp2_ptp_hwtstamp_set,2826	.shaper_work	= mlxsw_sp2_ptp_shaper_work,2827#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)2828	.get_ts_info	= mlxsw_sp2_ptp_get_ts_info,2829#endif2830	.get_stats_count = mlxsw_sp2_get_stats_count,2831	.get_stats_strings = mlxsw_sp2_get_stats_strings,2832	.get_stats	= mlxsw_sp2_get_stats,2833	.txhdr_construct = mlxsw_sp_ptp_txhdr_construct,2834};2835 2836struct mlxsw_sp_sample_trigger_node {2837	struct mlxsw_sp_sample_trigger trigger;2838	struct mlxsw_sp_sample_params params;2839	struct rhash_head ht_node;2840	struct rcu_head rcu;2841	refcount_t refcount;2842};2843 2844static const struct rhashtable_params mlxsw_sp_sample_trigger_ht_params = {2845	.key_offset = offsetof(struct mlxsw_sp_sample_trigger_node, trigger),2846	.head_offset = offsetof(struct mlxsw_sp_sample_trigger_node, ht_node),2847	.key_len = sizeof(struct mlxsw_sp_sample_trigger),2848	.automatic_shrinking = true,2849};2850 2851static void2852mlxsw_sp_sample_trigger_key_init(struct mlxsw_sp_sample_trigger *key,2853				 const struct mlxsw_sp_sample_trigger *trigger)2854{2855	memset(key, 0, sizeof(*key));2856	key->type = trigger->type;2857	key->local_port = trigger->local_port;2858}2859 2860/* RCU read lock must be held */2861struct mlxsw_sp_sample_params *2862mlxsw_sp_sample_trigger_params_lookup(struct mlxsw_sp *mlxsw_sp,2863				      const struct mlxsw_sp_sample_trigger *trigger)2864{2865	struct mlxsw_sp_sample_trigger_node *trigger_node;2866	struct mlxsw_sp_sample_trigger key;2867 2868	mlxsw_sp_sample_trigger_key_init(&key, trigger);2869	trigger_node = rhashtable_lookup(&mlxsw_sp->sample_trigger_ht, &key,2870					 mlxsw_sp_sample_trigger_ht_params);2871	if (!trigger_node)2872		return NULL;2873 2874	return &trigger_node->params;2875}2876 2877static int2878mlxsw_sp_sample_trigger_node_init(struct mlxsw_sp *mlxsw_sp,2879				  const struct mlxsw_sp_sample_trigger *trigger,2880				  const struct mlxsw_sp_sample_params *params)2881{2882	struct mlxsw_sp_sample_trigger_node *trigger_node;2883	int err;2884 2885	trigger_node = kzalloc(sizeof(*trigger_node), GFP_KERNEL);2886	if (!trigger_node)2887		return -ENOMEM;2888 2889	trigger_node->trigger = *trigger;2890	trigger_node->params = *params;2891	refcount_set(&trigger_node->refcount, 1);2892 2893	err = rhashtable_insert_fast(&mlxsw_sp->sample_trigger_ht,2894				     &trigger_node->ht_node,2895				     mlxsw_sp_sample_trigger_ht_params);2896	if (err)2897		goto err_rhashtable_insert;2898 2899	return 0;2900 2901err_rhashtable_insert:2902	kfree(trigger_node);2903	return err;2904}2905 2906static void2907mlxsw_sp_sample_trigger_node_fini(struct mlxsw_sp *mlxsw_sp,2908				  struct mlxsw_sp_sample_trigger_node *trigger_node)2909{2910	rhashtable_remove_fast(&mlxsw_sp->sample_trigger_ht,2911			       &trigger_node->ht_node,2912			       mlxsw_sp_sample_trigger_ht_params);2913	kfree_rcu(trigger_node, rcu);2914}2915 2916int2917mlxsw_sp_sample_trigger_params_set(struct mlxsw_sp *mlxsw_sp,2918				   const struct mlxsw_sp_sample_trigger *trigger,2919				   const struct mlxsw_sp_sample_params *params,2920				   struct netlink_ext_ack *extack)2921{2922	struct mlxsw_sp_sample_trigger_node *trigger_node;2923	struct mlxsw_sp_sample_trigger key;2924 2925	ASSERT_RTNL();2926 2927	mlxsw_sp_sample_trigger_key_init(&key, trigger);2928 2929	trigger_node = rhashtable_lookup_fast(&mlxsw_sp->sample_trigger_ht,2930					      &key,2931					      mlxsw_sp_sample_trigger_ht_params);2932	if (!trigger_node)2933		return mlxsw_sp_sample_trigger_node_init(mlxsw_sp, &key,2934							 params);2935 2936	if (trigger_node->trigger.local_port) {2937		NL_SET_ERR_MSG_MOD(extack, "Sampling already enabled on port");2938		return -EINVAL;2939	}2940 2941	if (trigger_node->params.psample_group != params->psample_group ||2942	    trigger_node->params.truncate != params->truncate ||2943	    trigger_node->params.rate != params->rate ||2944	    trigger_node->params.trunc_size != params->trunc_size) {2945		NL_SET_ERR_MSG_MOD(extack, "Sampling parameters do not match for an existing sampling trigger");2946		return -EINVAL;2947	}2948 2949	refcount_inc(&trigger_node->refcount);2950 2951	return 0;2952}2953 2954void2955mlxsw_sp_sample_trigger_params_unset(struct mlxsw_sp *mlxsw_sp,2956				     const struct mlxsw_sp_sample_trigger *trigger)2957{2958	struct mlxsw_sp_sample_trigger_node *trigger_node;2959	struct mlxsw_sp_sample_trigger key;2960 2961	ASSERT_RTNL();2962 2963	mlxsw_sp_sample_trigger_key_init(&key, trigger);2964 2965	trigger_node = rhashtable_lookup_fast(&mlxsw_sp->sample_trigger_ht,2966					      &key,2967					      mlxsw_sp_sample_trigger_ht_params);2968	if (!trigger_node)2969		return;2970 2971	if (!refcount_dec_and_test(&trigger_node->refcount))2972		return;2973 2974	mlxsw_sp_sample_trigger_node_fini(mlxsw_sp, trigger_node);2975}2976 2977static int mlxsw_sp_netdevice_event(struct notifier_block *unused,2978				    unsigned long event, void *ptr);2979 2980#define MLXSW_SP_DEFAULT_PARSING_DEPTH 962981#define MLXSW_SP_INCREASED_PARSING_DEPTH 1282982#define MLXSW_SP_DEFAULT_VXLAN_UDP_DPORT 47892983 2984static void mlxsw_sp_parsing_init(struct mlxsw_sp *mlxsw_sp)2985{2986	refcount_set(&mlxsw_sp->parsing.parsing_depth_ref, 0);2987	mlxsw_sp->parsing.parsing_depth = MLXSW_SP_DEFAULT_PARSING_DEPTH;2988	mlxsw_sp->parsing.vxlan_udp_dport = MLXSW_SP_DEFAULT_VXLAN_UDP_DPORT;2989	mutex_init(&mlxsw_sp->parsing.lock);2990}2991 2992static void mlxsw_sp_parsing_fini(struct mlxsw_sp *mlxsw_sp)2993{2994	mutex_destroy(&mlxsw_sp->parsing.lock);2995	WARN_ON_ONCE(refcount_read(&mlxsw_sp->parsing.parsing_depth_ref));2996}2997 2998struct mlxsw_sp_ipv6_addr_node {2999	struct in6_addr key;3000	struct rhash_head ht_node;3001	u32 kvdl_index;3002	refcount_t refcount;3003};3004 3005static const struct rhashtable_params mlxsw_sp_ipv6_addr_ht_params = {3006	.key_offset = offsetof(struct mlxsw_sp_ipv6_addr_node, key),3007	.head_offset = offsetof(struct mlxsw_sp_ipv6_addr_node, ht_node),3008	.key_len = sizeof(struct in6_addr),3009	.automatic_shrinking = true,3010};3011 3012static int3013mlxsw_sp_ipv6_addr_init(struct mlxsw_sp *mlxsw_sp, const struct in6_addr *addr6,3014			u32 *p_kvdl_index)3015{3016	struct mlxsw_sp_ipv6_addr_node *node;3017	char rips_pl[MLXSW_REG_RIPS_LEN];3018	int err;3019 3020	err = mlxsw_sp_kvdl_alloc(mlxsw_sp,3021				  MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,3022				  p_kvdl_index);3023	if (err)3024		return err;3025 3026	mlxsw_reg_rips_pack(rips_pl, *p_kvdl_index, addr6);3027	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rips), rips_pl);3028	if (err)3029		goto err_rips_write;3030 3031	node = kzalloc(sizeof(*node), GFP_KERNEL);3032	if (!node) {3033		err = -ENOMEM;3034		goto err_node_alloc;3035	}3036 3037	node->key = *addr6;3038	node->kvdl_index = *p_kvdl_index;3039	refcount_set(&node->refcount, 1);3040 3041	err = rhashtable_insert_fast(&mlxsw_sp->ipv6_addr_ht,3042				     &node->ht_node,3043				     mlxsw_sp_ipv6_addr_ht_params);3044	if (err)3045		goto err_rhashtable_insert;3046 3047	return 0;3048 3049err_rhashtable_insert:3050	kfree(node);3051err_node_alloc:3052err_rips_write:3053	mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,3054			   *p_kvdl_index);3055	return err;3056}3057 3058static void mlxsw_sp_ipv6_addr_fini(struct mlxsw_sp *mlxsw_sp,3059				    struct mlxsw_sp_ipv6_addr_node *node)3060{3061	u32 kvdl_index = node->kvdl_index;3062 3063	rhashtable_remove_fast(&mlxsw_sp->ipv6_addr_ht, &node->ht_node,3064			       mlxsw_sp_ipv6_addr_ht_params);3065	kfree(node);3066	mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_IPV6_ADDRESS, 1,3067			   kvdl_index);3068}3069 3070int mlxsw_sp_ipv6_addr_kvdl_index_get(struct mlxsw_sp *mlxsw_sp,3071				      const struct in6_addr *addr6,3072				      u32 *p_kvdl_index)3073{3074	struct mlxsw_sp_ipv6_addr_node *node;3075	int err = 0;3076 3077	mutex_lock(&mlxsw_sp->ipv6_addr_ht_lock);3078	node = rhashtable_lookup_fast(&mlxsw_sp->ipv6_addr_ht, addr6,3079				      mlxsw_sp_ipv6_addr_ht_params);3080	if (node) {3081		refcount_inc(&node->refcount);3082		*p_kvdl_index = node->kvdl_index;3083		goto out_unlock;3084	}3085 3086	err = mlxsw_sp_ipv6_addr_init(mlxsw_sp, addr6, p_kvdl_index);3087 3088out_unlock:3089	mutex_unlock(&mlxsw_sp->ipv6_addr_ht_lock);3090	return err;3091}3092 3093void3094mlxsw_sp_ipv6_addr_put(struct mlxsw_sp *mlxsw_sp, const struct in6_addr *addr6)3095{3096	struct mlxsw_sp_ipv6_addr_node *node;3097 3098	mutex_lock(&mlxsw_sp->ipv6_addr_ht_lock);3099	node = rhashtable_lookup_fast(&mlxsw_sp->ipv6_addr_ht, addr6,3100				      mlxsw_sp_ipv6_addr_ht_params);3101	if (WARN_ON(!node))3102		goto out_unlock;3103 3104	if (!refcount_dec_and_test(&node->refcount))3105		goto out_unlock;3106 3107	mlxsw_sp_ipv6_addr_fini(mlxsw_sp, node);3108 3109out_unlock:3110	mutex_unlock(&mlxsw_sp->ipv6_addr_ht_lock);3111}3112 3113static int mlxsw_sp_ipv6_addr_ht_init(struct mlxsw_sp *mlxsw_sp)3114{3115	int err;3116 3117	err = rhashtable_init(&mlxsw_sp->ipv6_addr_ht,3118			      &mlxsw_sp_ipv6_addr_ht_params);3119	if (err)3120		return err;3121 3122	mutex_init(&mlxsw_sp->ipv6_addr_ht_lock);3123	return 0;3124}3125 3126static void mlxsw_sp_ipv6_addr_ht_fini(struct mlxsw_sp *mlxsw_sp)3127{3128	mutex_destroy(&mlxsw_sp->ipv6_addr_ht_lock);3129	rhashtable_destroy(&mlxsw_sp->ipv6_addr_ht);3130}3131 3132static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,3133			 const struct mlxsw_bus_info *mlxsw_bus_info,3134			 struct netlink_ext_ack *extack)3135{3136	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);3137	int err;3138 3139	mlxsw_sp->core = mlxsw_core;3140	mlxsw_sp->bus_info = mlxsw_bus_info;3141 3142	mlxsw_sp_parsing_init(mlxsw_sp);3143 3144	err = mlxsw_sp_base_mac_get(mlxsw_sp);3145	if (err) {3146		dev_err(mlxsw_sp->bus_info->dev, "Failed to get base mac\n");3147		return err;3148	}3149 3150	err = mlxsw_sp_kvdl_init(mlxsw_sp);3151	if (err) {3152		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize KVDL\n");3153		return err;3154	}3155 3156	err = mlxsw_sp_pgt_init(mlxsw_sp);3157	if (err) {3158		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize PGT\n");3159		goto err_pgt_init;3160	}3161 3162	/* Initialize before FIDs so that the LAG table is at the start of PGT3163	 * and 8-aligned without overallocation.3164	 */3165	err = mlxsw_sp_lag_init(mlxsw_sp);3166	if (err) {3167		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize LAG\n");3168		goto err_lag_init;3169	}3170 3171	err = mlxsw_sp->fid_core_ops->init(mlxsw_sp);3172	if (err) {3173		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n");3174		goto err_fid_core_init;3175	}3176 3177	err = mlxsw_sp_policers_init(mlxsw_sp);3178	if (err) {3179		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize policers\n");3180		goto err_policers_init;3181	}3182 3183	err = mlxsw_sp_traps_init(mlxsw_sp);3184	if (err) {3185		dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n");3186		goto err_traps_init;3187	}3188 3189	err = mlxsw_sp_devlink_traps_init(mlxsw_sp);3190	if (err) {3191		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize devlink traps\n");3192		goto err_devlink_traps_init;3193	}3194 3195	err = mlxsw_sp_buffers_init(mlxsw_sp);3196	if (err) {3197		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize buffers\n");3198		goto err_buffers_init;3199	}3200 3201	/* Initialize SPAN before router and switchdev, so that those components3202	 * can call mlxsw_sp_span_respin().3203	 */3204	err = mlxsw_sp_span_init(mlxsw_sp);3205	if (err) {3206		dev_err(mlxsw_sp->bus_info->dev, "Failed to init span system\n");3207		goto err_span_init;3208	}3209 3210	err = mlxsw_sp_switchdev_init(mlxsw_sp);3211	if (err) {3212		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize switchdev\n");3213		goto err_switchdev_init;3214	}3215 3216	err = mlxsw_sp_counter_pool_init(mlxsw_sp);3217	if (err) {3218		dev_err(mlxsw_sp->bus_info->dev, "Failed to init counter pool\n");3219		goto err_counter_pool_init;3220	}3221 3222	err = mlxsw_sp_afa_init(mlxsw_sp);3223	if (err) {3224		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL actions\n");3225		goto err_afa_init;3226	}3227 3228	err = mlxsw_sp_ipv6_addr_ht_init(mlxsw_sp);3229	if (err) {3230		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize hash table for IPv6 addresses\n");3231		goto err_ipv6_addr_ht_init;3232	}3233 3234	err = mlxsw_sp_nve_init(mlxsw_sp);3235	if (err) {3236		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize NVE\n");3237		goto err_nve_init;3238	}3239 3240	err = mlxsw_sp_port_range_init(mlxsw_sp);3241	if (err) {3242		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize port ranges\n");3243		goto err_port_range_init;3244	}3245 3246	err = mlxsw_sp_acl_init(mlxsw_sp);3247	if (err) {3248		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL\n");3249		goto err_acl_init;3250	}3251 3252	err = mlxsw_sp_router_init(mlxsw_sp, extack);3253	if (err) {3254		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n");3255		goto err_router_init;3256	}3257 3258	if (mlxsw_sp->bus_info->read_clock_capable) {3259		/* NULL is a valid return value from clock_init */3260		mlxsw_sp->clock =3261			mlxsw_sp->ptp_ops->clock_init(mlxsw_sp,3262						      mlxsw_sp->bus_info->dev);3263		if (IS_ERR(mlxsw_sp->clock)) {3264			err = PTR_ERR(mlxsw_sp->clock);3265			dev_err(mlxsw_sp->bus_info->dev, "Failed to init ptp clock\n");3266			goto err_ptp_clock_init;3267		}3268	}3269 3270	if (mlxsw_sp->clock) {3271		/* NULL is a valid return value from ptp_ops->init */3272		mlxsw_sp->ptp_state = mlxsw_sp->ptp_ops->init(mlxsw_sp);3273		if (IS_ERR(mlxsw_sp->ptp_state)) {3274			err = PTR_ERR(mlxsw_sp->ptp_state);3275			dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize PTP\n");3276			goto err_ptp_init;3277		}3278	}3279 3280	/* Initialize netdevice notifier after SPAN is initialized, so that the3281	 * event handler can call SPAN respin.3282	 */3283	mlxsw_sp->netdevice_nb.notifier_call = mlxsw_sp_netdevice_event;3284	err = register_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),3285					      &mlxsw_sp->netdevice_nb);3286	if (err) {3287		dev_err(mlxsw_sp->bus_info->dev, "Failed to register netdev notifier\n");3288		goto err_netdev_notifier;3289	}3290 3291	err = mlxsw_sp_dpipe_init(mlxsw_sp);3292	if (err) {3293		dev_err(mlxsw_sp->bus_info->dev, "Failed to init pipeline debug\n");3294		goto err_dpipe_init;3295	}3296 3297	err = mlxsw_sp_port_module_info_init(mlxsw_sp);3298	if (err) {3299		dev_err(mlxsw_sp->bus_info->dev, "Failed to init port module info\n");3300		goto err_port_module_info_init;3301	}3302 3303	err = rhashtable_init(&mlxsw_sp->sample_trigger_ht,3304			      &mlxsw_sp_sample_trigger_ht_params);3305	if (err) {3306		dev_err(mlxsw_sp->bus_info->dev, "Failed to init sampling trigger hashtable\n");3307		goto err_sample_trigger_init;3308	}3309 3310	err = mlxsw_sp_ports_create(mlxsw_sp);3311	if (err) {3312		dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n");3313		goto err_ports_create;3314	}3315 3316	return 0;3317 3318err_ports_create:3319	rhashtable_destroy(&mlxsw_sp->sample_trigger_ht);3320err_sample_trigger_init:3321	mlxsw_sp_port_module_info_fini(mlxsw_sp);3322err_port_module_info_init:3323	mlxsw_sp_dpipe_fini(mlxsw_sp);3324err_dpipe_init:3325	unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),3326					  &mlxsw_sp->netdevice_nb);3327err_netdev_notifier:3328	if (mlxsw_sp->clock)3329		mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state);3330err_ptp_init:3331	if (mlxsw_sp->clock)3332		mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock);3333err_ptp_clock_init:3334	mlxsw_sp_router_fini(mlxsw_sp);3335err_router_init:3336	mlxsw_sp_acl_fini(mlxsw_sp);3337err_acl_init:3338	mlxsw_sp_port_range_fini(mlxsw_sp);3339err_port_range_init:3340	mlxsw_sp_nve_fini(mlxsw_sp);3341err_nve_init:3342	mlxsw_sp_ipv6_addr_ht_fini(mlxsw_sp);3343err_ipv6_addr_ht_init:3344	mlxsw_sp_afa_fini(mlxsw_sp);3345err_afa_init:3346	mlxsw_sp_counter_pool_fini(mlxsw_sp);3347err_counter_pool_init:3348	mlxsw_sp_switchdev_fini(mlxsw_sp);3349err_switchdev_init:3350	mlxsw_sp_span_fini(mlxsw_sp);3351err_span_init:3352	mlxsw_sp_buffers_fini(mlxsw_sp);3353err_buffers_init:3354	mlxsw_sp_devlink_traps_fini(mlxsw_sp);3355err_devlink_traps_init:3356	mlxsw_sp_traps_fini(mlxsw_sp);3357err_traps_init:3358	mlxsw_sp_policers_fini(mlxsw_sp);3359err_policers_init:3360	mlxsw_sp->fid_core_ops->fini(mlxsw_sp);3361err_fid_core_init:3362	mlxsw_sp_lag_fini(mlxsw_sp);3363err_lag_init:3364	mlxsw_sp_pgt_fini(mlxsw_sp);3365err_pgt_init:3366	mlxsw_sp_kvdl_fini(mlxsw_sp);3367	mlxsw_sp_parsing_fini(mlxsw_sp);3368	return err;3369}3370 3371static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core,3372			  const struct mlxsw_bus_info *mlxsw_bus_info,3373			  struct netlink_ext_ack *extack)3374{3375	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);3376 3377	mlxsw_sp->switchdev_ops = &mlxsw_sp1_switchdev_ops;3378	mlxsw_sp->kvdl_ops = &mlxsw_sp1_kvdl_ops;3379	mlxsw_sp->afa_ops = &mlxsw_sp1_act_afa_ops;3380	mlxsw_sp->afk_ops = &mlxsw_sp1_afk_ops;3381	mlxsw_sp->mr_tcam_ops = &mlxsw_sp1_mr_tcam_ops;3382	mlxsw_sp->acl_rulei_ops = &mlxsw_sp1_acl_rulei_ops;3383	mlxsw_sp->acl_tcam_ops = &mlxsw_sp1_acl_tcam_ops;3384	mlxsw_sp->nve_ops_arr = mlxsw_sp1_nve_ops_arr;3385	mlxsw_sp->mac_mask = mlxsw_sp1_mac_mask;3386	mlxsw_sp->sb_vals = &mlxsw_sp1_sb_vals;3387	mlxsw_sp->sb_ops = &mlxsw_sp1_sb_ops;3388	mlxsw_sp->port_type_speed_ops = &mlxsw_sp1_port_type_speed_ops;3389	mlxsw_sp->ptp_ops = &mlxsw_sp1_ptp_ops;3390	mlxsw_sp->span_ops = &mlxsw_sp1_span_ops;3391	mlxsw_sp->policer_core_ops = &mlxsw_sp1_policer_core_ops;3392	mlxsw_sp->trap_ops = &mlxsw_sp1_trap_ops;3393	mlxsw_sp->mall_ops = &mlxsw_sp1_mall_ops;3394	mlxsw_sp->router_ops = &mlxsw_sp1_router_ops;3395	mlxsw_sp->listeners = mlxsw_sp1_listener;3396	mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener);3397	mlxsw_sp->fid_core_ops = &mlxsw_sp1_fid_core_ops;3398	mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP1;3399	mlxsw_sp->pgt_smpe_index_valid = true;3400 3401	return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);3402}3403 3404static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core,3405			  const struct mlxsw_bus_info *mlxsw_bus_info,3406			  struct netlink_ext_ack *extack)3407{3408	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);3409 3410	mlxsw_sp->switchdev_ops = &mlxsw_sp2_switchdev_ops;3411	mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops;3412	mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops;3413	mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops;3414	mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops;3415	mlxsw_sp->acl_rulei_ops = &mlxsw_sp2_acl_rulei_ops;3416	mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops;3417	mlxsw_sp->acl_bf_ops = &mlxsw_sp2_acl_bf_ops;3418	mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr;3419	mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask;3420	mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;3421	mlxsw_sp->sb_ops = &mlxsw_sp2_sb_ops;3422	mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;3423	mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops;3424	mlxsw_sp->span_ops = &mlxsw_sp2_span_ops;3425	mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops;3426	mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops;3427	mlxsw_sp->mall_ops = &mlxsw_sp2_mall_ops;3428	mlxsw_sp->router_ops = &mlxsw_sp2_router_ops;3429	mlxsw_sp->listeners = mlxsw_sp2_listener;3430	mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener);3431	mlxsw_sp->fid_core_ops = &mlxsw_sp2_fid_core_ops;3432	mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP2;3433	mlxsw_sp->pgt_smpe_index_valid = false;3434 3435	return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);3436}3437 3438static int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core,3439			  const struct mlxsw_bus_info *mlxsw_bus_info,3440			  struct netlink_ext_ack *extack)3441{3442	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);3443 3444	mlxsw_sp->switchdev_ops = &mlxsw_sp2_switchdev_ops;3445	mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops;3446	mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops;3447	mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops;3448	mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops;3449	mlxsw_sp->acl_rulei_ops = &mlxsw_sp2_acl_rulei_ops;3450	mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops;3451	mlxsw_sp->acl_bf_ops = &mlxsw_sp2_acl_bf_ops;3452	mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr;3453	mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask;3454	mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;3455	mlxsw_sp->sb_ops = &mlxsw_sp3_sb_ops;3456	mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;3457	mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops;3458	mlxsw_sp->span_ops = &mlxsw_sp3_span_ops;3459	mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops;3460	mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops;3461	mlxsw_sp->mall_ops = &mlxsw_sp2_mall_ops;3462	mlxsw_sp->router_ops = &mlxsw_sp2_router_ops;3463	mlxsw_sp->listeners = mlxsw_sp2_listener;3464	mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener);3465	mlxsw_sp->fid_core_ops = &mlxsw_sp2_fid_core_ops;3466	mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3;3467	mlxsw_sp->pgt_smpe_index_valid = false;3468 3469	return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);3470}3471 3472static int mlxsw_sp4_init(struct mlxsw_core *mlxsw_core,3473			  const struct mlxsw_bus_info *mlxsw_bus_info,3474			  struct netlink_ext_ack *extack)3475{3476	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);3477 3478	mlxsw_sp->switchdev_ops = &mlxsw_sp2_switchdev_ops;3479	mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops;3480	mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops;3481	mlxsw_sp->afk_ops = &mlxsw_sp4_afk_ops;3482	mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops;3483	mlxsw_sp->acl_rulei_ops = &mlxsw_sp2_acl_rulei_ops;3484	mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops;3485	mlxsw_sp->acl_bf_ops = &mlxsw_sp4_acl_bf_ops;3486	mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr;3487	mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask;3488	mlxsw_sp->sb_vals = &mlxsw_sp2_sb_vals;3489	mlxsw_sp->sb_ops = &mlxsw_sp3_sb_ops;3490	mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops;3491	mlxsw_sp->ptp_ops = &mlxsw_sp4_ptp_ops;3492	mlxsw_sp->span_ops = &mlxsw_sp3_span_ops;3493	mlxsw_sp->policer_core_ops = &mlxsw_sp2_policer_core_ops;3494	mlxsw_sp->trap_ops = &mlxsw_sp2_trap_ops;3495	mlxsw_sp->mall_ops = &mlxsw_sp2_mall_ops;3496	mlxsw_sp->router_ops = &mlxsw_sp2_router_ops;3497	mlxsw_sp->listeners = mlxsw_sp2_listener;3498	mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener);3499	mlxsw_sp->fid_core_ops = &mlxsw_sp2_fid_core_ops;3500	mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP4;3501	mlxsw_sp->pgt_smpe_index_valid = false;3502 3503	return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);3504}3505 3506static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)3507{3508	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);3509 3510	mlxsw_sp_ports_remove(mlxsw_sp);3511	rhashtable_destroy(&mlxsw_sp->sample_trigger_ht);3512	mlxsw_sp_port_module_info_fini(mlxsw_sp);3513	mlxsw_sp_dpipe_fini(mlxsw_sp);3514	unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),3515					  &mlxsw_sp->netdevice_nb);3516	if (mlxsw_sp->clock) {3517		mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state);3518		mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock);3519	}3520	mlxsw_sp_router_fini(mlxsw_sp);3521	mlxsw_sp_acl_fini(mlxsw_sp);3522	mlxsw_sp_port_range_fini(mlxsw_sp);3523	mlxsw_sp_nve_fini(mlxsw_sp);3524	mlxsw_sp_ipv6_addr_ht_fini(mlxsw_sp);3525	mlxsw_sp_afa_fini(mlxsw_sp);3526	mlxsw_sp_counter_pool_fini(mlxsw_sp);3527	mlxsw_sp_switchdev_fini(mlxsw_sp);3528	mlxsw_sp_span_fini(mlxsw_sp);3529	mlxsw_sp_buffers_fini(mlxsw_sp);3530	mlxsw_sp_devlink_traps_fini(mlxsw_sp);3531	mlxsw_sp_traps_fini(mlxsw_sp);3532	mlxsw_sp_policers_fini(mlxsw_sp);3533	mlxsw_sp->fid_core_ops->fini(mlxsw_sp);3534	mlxsw_sp_lag_fini(mlxsw_sp);3535	mlxsw_sp_pgt_fini(mlxsw_sp);3536	mlxsw_sp_kvdl_fini(mlxsw_sp);3537	mlxsw_sp_parsing_fini(mlxsw_sp);3538}3539 3540static const struct mlxsw_config_profile mlxsw_sp1_config_profile = {3541	.used_flood_mode                = 1,3542	.flood_mode                     = MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED,3543	.used_max_ib_mc			= 1,3544	.max_ib_mc			= 0,3545	.used_max_pkey			= 1,3546	.max_pkey			= 0,3547	.used_ubridge			= 1,3548	.ubridge			= 1,3549	.used_kvd_sizes			= 1,3550	.kvd_hash_single_parts		= 59,3551	.kvd_hash_double_parts		= 41,3552	.kvd_linear_size		= MLXSW_SP_KVD_LINEAR_SIZE,3553	.swid_config			= {3554		{3555			.used_type	= 1,3556			.type		= MLXSW_PORT_SWID_TYPE_ETH,3557		}3558	},3559};3560 3561static const struct mlxsw_config_profile mlxsw_sp2_config_profile = {3562	.used_flood_mode                = 1,3563	.flood_mode                     = MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED,3564	.used_max_ib_mc			= 1,3565	.max_ib_mc			= 0,3566	.used_max_pkey			= 1,3567	.max_pkey			= 0,3568	.used_ubridge			= 1,3569	.ubridge			= 1,3570	.swid_config			= {3571		{3572			.used_type	= 1,3573			.type		= MLXSW_PORT_SWID_TYPE_ETH,3574		}3575	},3576	.used_cqe_time_stamp_type	= 1,3577	.cqe_time_stamp_type		= MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC,3578	.lag_mode_prefer_sw		= true,3579	.flood_mode_prefer_cff		= true,3580};3581 3582/* Reduce number of LAGs from full capacity (256) to the maximum supported LAGs3583 * in Spectrum-2/3, to avoid regression in number of free entries in the PGT3584 * table.3585 */3586#define MLXSW_SP4_CONFIG_PROFILE_MAX_LAG 1283587 3588static const struct mlxsw_config_profile mlxsw_sp4_config_profile = {3589	.used_max_lag			= 1,3590	.max_lag			= MLXSW_SP4_CONFIG_PROFILE_MAX_LAG,3591	.used_flood_mode                = 1,3592	.flood_mode                     = MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED,3593	.used_max_ib_mc			= 1,3594	.max_ib_mc			= 0,3595	.used_max_pkey			= 1,3596	.max_pkey			= 0,3597	.used_ubridge			= 1,3598	.ubridge			= 1,3599	.swid_config			= {3600		{3601			.used_type	= 1,3602			.type		= MLXSW_PORT_SWID_TYPE_ETH,3603		}3604	},3605	.used_cqe_time_stamp_type	= 1,3606	.cqe_time_stamp_type		= MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC,3607	.lag_mode_prefer_sw		= true,3608	.flood_mode_prefer_cff		= true,3609};3610 3611static void3612mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core,3613				      struct devlink_resource_size_params *kvd_size_params,3614				      struct devlink_resource_size_params *linear_size_params,3615				      struct devlink_resource_size_params *hash_double_size_params,3616				      struct devlink_resource_size_params *hash_single_size_params)3617{3618	u32 single_size_min = MLXSW_CORE_RES_GET(mlxsw_core,3619						 KVD_SINGLE_MIN_SIZE);3620	u32 double_size_min = MLXSW_CORE_RES_GET(mlxsw_core,3621						 KVD_DOUBLE_MIN_SIZE);3622	u32 kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE);3623	u32 linear_size_min = 0;3624 3625	devlink_resource_size_params_init(kvd_size_params, kvd_size, kvd_size,3626					  MLXSW_SP_KVD_GRANULARITY,3627					  DEVLINK_RESOURCE_UNIT_ENTRY);3628	devlink_resource_size_params_init(linear_size_params, linear_size_min,3629					  kvd_size - single_size_min -3630					  double_size_min,3631					  MLXSW_SP_KVD_GRANULARITY,3632					  DEVLINK_RESOURCE_UNIT_ENTRY);3633	devlink_resource_size_params_init(hash_double_size_params,3634					  double_size_min,3635					  kvd_size - single_size_min -3636					  linear_size_min,3637					  MLXSW_SP_KVD_GRANULARITY,3638					  DEVLINK_RESOURCE_UNIT_ENTRY);3639	devlink_resource_size_params_init(hash_single_size_params,3640					  single_size_min,3641					  kvd_size - double_size_min -3642					  linear_size_min,3643					  MLXSW_SP_KVD_GRANULARITY,3644					  DEVLINK_RESOURCE_UNIT_ENTRY);3645}3646 3647static int mlxsw_sp1_resources_kvd_register(struct mlxsw_core *mlxsw_core)3648{3649	struct devlink *devlink = priv_to_devlink(mlxsw_core);3650	struct devlink_resource_size_params hash_single_size_params;3651	struct devlink_resource_size_params hash_double_size_params;3652	struct devlink_resource_size_params linear_size_params;3653	struct devlink_resource_size_params kvd_size_params;3654	u32 kvd_size, single_size, double_size, linear_size;3655	const struct mlxsw_config_profile *profile;3656	int err;3657 3658	profile = &mlxsw_sp1_config_profile;3659	if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE))3660		return -EIO;3661 3662	mlxsw_sp_resource_size_params_prepare(mlxsw_core, &kvd_size_params,3663					      &linear_size_params,3664					      &hash_double_size_params,3665					      &hash_single_size_params);3666 3667	kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE);3668	err = devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD,3669				     kvd_size, MLXSW_SP_RESOURCE_KVD,3670				     DEVLINK_RESOURCE_ID_PARENT_TOP,3671				     &kvd_size_params);3672	if (err)3673		return err;3674 3675	linear_size = profile->kvd_linear_size;3676	err = devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR,3677				     linear_size,3678				     MLXSW_SP_RESOURCE_KVD_LINEAR,3679				     MLXSW_SP_RESOURCE_KVD,3680				     &linear_size_params);3681	if (err)3682		return err;3683 3684	err = mlxsw_sp1_kvdl_resources_register(mlxsw_core);3685	if  (err)3686		return err;3687 3688	double_size = kvd_size - linear_size;3689	double_size *= profile->kvd_hash_double_parts;3690	double_size /= profile->kvd_hash_double_parts +3691		       profile->kvd_hash_single_parts;3692	double_size = rounddown(double_size, MLXSW_SP_KVD_GRANULARITY);3693	err = devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_HASH_DOUBLE,3694				     double_size,3695				     MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,3696				     MLXSW_SP_RESOURCE_KVD,3697				     &hash_double_size_params);3698	if (err)3699		return err;3700 3701	single_size = kvd_size - double_size - linear_size;3702	err = devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_HASH_SINGLE,3703				     single_size,3704				     MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,3705				     MLXSW_SP_RESOURCE_KVD,3706				     &hash_single_size_params);3707	if (err)3708		return err;3709 3710	return 0;3711}3712 3713static int mlxsw_sp2_resources_kvd_register(struct mlxsw_core *mlxsw_core)3714{3715	struct devlink *devlink = priv_to_devlink(mlxsw_core);3716	struct devlink_resource_size_params kvd_size_params;3717	u32 kvd_size;3718 3719	if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE))3720		return -EIO;3721 3722	kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE);3723	devlink_resource_size_params_init(&kvd_size_params, kvd_size, kvd_size,3724					  MLXSW_SP_KVD_GRANULARITY,3725					  DEVLINK_RESOURCE_UNIT_ENTRY);3726 3727	return devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD,3728				      kvd_size, MLXSW_SP_RESOURCE_KVD,3729				      DEVLINK_RESOURCE_ID_PARENT_TOP,3730				      &kvd_size_params);3731}3732 3733static int mlxsw_sp_resources_span_register(struct mlxsw_core *mlxsw_core)3734{3735	struct devlink *devlink = priv_to_devlink(mlxsw_core);3736	struct devlink_resource_size_params span_size_params;3737	u32 max_span;3738 3739	if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SPAN))3740		return -EIO;3741 3742	max_span = MLXSW_CORE_RES_GET(mlxsw_core, MAX_SPAN);3743	devlink_resource_size_params_init(&span_size_params, max_span, max_span,3744					  1, DEVLINK_RESOURCE_UNIT_ENTRY);3745 3746	return devl_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_SPAN,3747				      max_span, MLXSW_SP_RESOURCE_SPAN,3748				      DEVLINK_RESOURCE_ID_PARENT_TOP,3749				      &span_size_params);3750}3751 3752static int3753mlxsw_sp_resources_rif_mac_profile_register(struct mlxsw_core *mlxsw_core)3754{3755	struct devlink *devlink = priv_to_devlink(mlxsw_core);3756	struct devlink_resource_size_params size_params;3757	u8 max_rif_mac_profiles;3758 3759	if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_RIF_MAC_PROFILES))3760		max_rif_mac_profiles = 1;3761	else3762		max_rif_mac_profiles = MLXSW_CORE_RES_GET(mlxsw_core,3763							  MAX_RIF_MAC_PROFILES);3764	devlink_resource_size_params_init(&size_params, max_rif_mac_profiles,3765					  max_rif_mac_profiles, 1,3766					  DEVLINK_RESOURCE_UNIT_ENTRY);3767 3768	return devl_resource_register(devlink,3769				      "rif_mac_profiles",3770				      max_rif_mac_profiles,3771				      MLXSW_SP_RESOURCE_RIF_MAC_PROFILES,3772				      DEVLINK_RESOURCE_ID_PARENT_TOP,3773				      &size_params);3774}3775 3776static int mlxsw_sp_resources_rifs_register(struct mlxsw_core *mlxsw_core)3777{3778	struct devlink *devlink = priv_to_devlink(mlxsw_core);3779	struct devlink_resource_size_params size_params;3780	u64 max_rifs;3781 3782	if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_RIFS))3783		return -EIO;3784 3785	max_rifs = MLXSW_CORE_RES_GET(mlxsw_core, MAX_RIFS);3786	devlink_resource_size_params_init(&size_params, max_rifs, max_rifs,3787					  1, DEVLINK_RESOURCE_UNIT_ENTRY);3788 3789	return devl_resource_register(devlink, "rifs", max_rifs,3790				      MLXSW_SP_RESOURCE_RIFS,3791				      DEVLINK_RESOURCE_ID_PARENT_TOP,3792				      &size_params);3793}3794 3795static int3796mlxsw_sp_resources_port_range_register(struct mlxsw_core *mlxsw_core)3797{3798	struct devlink *devlink = priv_to_devlink(mlxsw_core);3799	struct devlink_resource_size_params size_params;3800	u64 max;3801 3802	if (!MLXSW_CORE_RES_VALID(mlxsw_core, ACL_MAX_L4_PORT_RANGE))3803		return -EIO;3804 3805	max = MLXSW_CORE_RES_GET(mlxsw_core, ACL_MAX_L4_PORT_RANGE);3806	devlink_resource_size_params_init(&size_params, max, max, 1,3807					  DEVLINK_RESOURCE_UNIT_ENTRY);3808 3809	return devl_resource_register(devlink, "port_range_registers", max,3810				      MLXSW_SP_RESOURCE_PORT_RANGE_REGISTERS,3811				      DEVLINK_RESOURCE_ID_PARENT_TOP,3812				      &size_params);3813}3814 3815static int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core)3816{3817	int err;3818 3819	err = mlxsw_sp1_resources_kvd_register(mlxsw_core);3820	if (err)3821		return err;3822 3823	err = mlxsw_sp_resources_span_register(mlxsw_core);3824	if (err)3825		goto err_resources_span_register;3826 3827	err = mlxsw_sp_counter_resources_register(mlxsw_core);3828	if (err)3829		goto err_resources_counter_register;3830 3831	err = mlxsw_sp_policer_resources_register(mlxsw_core);3832	if (err)3833		goto err_policer_resources_register;3834 3835	err = mlxsw_sp_resources_rif_mac_profile_register(mlxsw_core);3836	if (err)3837		goto err_resources_rif_mac_profile_register;3838 3839	err = mlxsw_sp_resources_rifs_register(mlxsw_core);3840	if (err)3841		goto err_resources_rifs_register;3842 3843	err = mlxsw_sp_resources_port_range_register(mlxsw_core);3844	if (err)3845		goto err_resources_port_range_register;3846 3847	return 0;3848 3849err_resources_port_range_register:3850err_resources_rifs_register:3851err_resources_rif_mac_profile_register:3852err_policer_resources_register:3853err_resources_counter_register:3854err_resources_span_register:3855	devl_resources_unregister(priv_to_devlink(mlxsw_core));3856	return err;3857}3858 3859static int mlxsw_sp2_resources_register(struct mlxsw_core *mlxsw_core)3860{3861	int err;3862 3863	err = mlxsw_sp2_resources_kvd_register(mlxsw_core);3864	if (err)3865		return err;3866 3867	err = mlxsw_sp_resources_span_register(mlxsw_core);3868	if (err)3869		goto err_resources_span_register;3870 3871	err = mlxsw_sp_counter_resources_register(mlxsw_core);3872	if (err)3873		goto err_resources_counter_register;3874 3875	err = mlxsw_sp_policer_resources_register(mlxsw_core);3876	if (err)3877		goto err_policer_resources_register;3878 3879	err = mlxsw_sp_resources_rif_mac_profile_register(mlxsw_core);3880	if (err)3881		goto err_resources_rif_mac_profile_register;3882 3883	err = mlxsw_sp_resources_rifs_register(mlxsw_core);3884	if (err)3885		goto err_resources_rifs_register;3886 3887	err = mlxsw_sp_resources_port_range_register(mlxsw_core);3888	if (err)3889		goto err_resources_port_range_register;3890 3891	return 0;3892 3893err_resources_port_range_register:3894err_resources_rifs_register:3895err_resources_rif_mac_profile_register:3896err_policer_resources_register:3897err_resources_counter_register:3898err_resources_span_register:3899	devl_resources_unregister(priv_to_devlink(mlxsw_core));3900	return err;3901}3902 3903static int mlxsw_sp_kvd_sizes_get(struct mlxsw_core *mlxsw_core,3904				  const struct mlxsw_config_profile *profile,3905				  u64 *p_single_size, u64 *p_double_size,3906				  u64 *p_linear_size)3907{3908	struct devlink *devlink = priv_to_devlink(mlxsw_core);3909	u32 double_size;3910	int err;3911 3912	if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SINGLE_MIN_SIZE) ||3913	    !MLXSW_CORE_RES_VALID(mlxsw_core, KVD_DOUBLE_MIN_SIZE))3914		return -EIO;3915 3916	/* The hash part is what left of the kvd without the3917	 * linear part. It is split to the single size and3918	 * double size by the parts ratio from the profile.3919	 * Both sizes must be a multiplications of the3920	 * granularity from the profile. In case the user3921	 * provided the sizes they are obtained via devlink.3922	 */3923	err = devl_resource_size_get(devlink,3924				     MLXSW_SP_RESOURCE_KVD_LINEAR,3925				     p_linear_size);3926	if (err)3927		*p_linear_size = profile->kvd_linear_size;3928 3929	err = devl_resource_size_get(devlink,3930				     MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,3931				     p_double_size);3932	if (err) {3933		double_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) -3934			      *p_linear_size;3935		double_size *= profile->kvd_hash_double_parts;3936		double_size /= profile->kvd_hash_double_parts +3937			       profile->kvd_hash_single_parts;3938		*p_double_size = rounddown(double_size,3939					   MLXSW_SP_KVD_GRANULARITY);3940	}3941 3942	err = devl_resource_size_get(devlink,3943				     MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,3944				     p_single_size);3945	if (err)3946		*p_single_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) -3947				 *p_double_size - *p_linear_size;3948 3949	/* Check results are legal. */3950	if (*p_single_size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE) ||3951	    *p_double_size < MLXSW_CORE_RES_GET(mlxsw_core, KVD_DOUBLE_MIN_SIZE) ||3952	    MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) < *p_linear_size)3953		return -EIO;3954 3955	return 0;3956}3957 3958static void mlxsw_sp_ptp_transmitted(struct mlxsw_core *mlxsw_core,3959				     struct sk_buff *skb, u16 local_port)3960{3961	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core);3962 3963	skb_pull(skb, MLXSW_TXHDR_LEN);3964	mlxsw_sp->ptp_ops->transmitted(mlxsw_sp, skb, local_port);3965}3966 3967static struct mlxsw_driver mlxsw_sp1_driver = {3968	.kind				= mlxsw_sp1_driver_name,3969	.priv_size			= sizeof(struct mlxsw_sp),3970	.fw_req_rev			= &mlxsw_sp1_fw_rev,3971	.fw_filename			= MLXSW_SP1_FW_FILENAME,3972	.init				= mlxsw_sp1_init,3973	.fini				= mlxsw_sp_fini,3974	.port_split			= mlxsw_sp_port_split,3975	.port_unsplit			= mlxsw_sp_port_unsplit,3976	.sb_pool_get			= mlxsw_sp_sb_pool_get,3977	.sb_pool_set			= mlxsw_sp_sb_pool_set,3978	.sb_port_pool_get		= mlxsw_sp_sb_port_pool_get,3979	.sb_port_pool_set		= mlxsw_sp_sb_port_pool_set,3980	.sb_tc_pool_bind_get		= mlxsw_sp_sb_tc_pool_bind_get,3981	.sb_tc_pool_bind_set		= mlxsw_sp_sb_tc_pool_bind_set,3982	.sb_occ_snapshot		= mlxsw_sp_sb_occ_snapshot,3983	.sb_occ_max_clear		= mlxsw_sp_sb_occ_max_clear,3984	.sb_occ_port_pool_get		= mlxsw_sp_sb_occ_port_pool_get,3985	.sb_occ_tc_port_bind_get	= mlxsw_sp_sb_occ_tc_port_bind_get,3986	.trap_init			= mlxsw_sp_trap_init,3987	.trap_fini			= mlxsw_sp_trap_fini,3988	.trap_action_set		= mlxsw_sp_trap_action_set,3989	.trap_group_init		= mlxsw_sp_trap_group_init,3990	.trap_group_set			= mlxsw_sp_trap_group_set,3991	.trap_policer_init		= mlxsw_sp_trap_policer_init,3992	.trap_policer_fini		= mlxsw_sp_trap_policer_fini,3993	.trap_policer_set		= mlxsw_sp_trap_policer_set,3994	.trap_policer_counter_get	= mlxsw_sp_trap_policer_counter_get,3995	.txhdr_construct		= mlxsw_sp_txhdr_construct,3996	.resources_register		= mlxsw_sp1_resources_register,3997	.kvd_sizes_get			= mlxsw_sp_kvd_sizes_get,3998	.ptp_transmitted		= mlxsw_sp_ptp_transmitted,3999	.txhdr_len			= MLXSW_TXHDR_LEN,4000	.profile			= &mlxsw_sp1_config_profile,4001	.sdq_supports_cqe_v2		= false,4002};4003 4004static struct mlxsw_driver mlxsw_sp2_driver = {4005	.kind				= mlxsw_sp2_driver_name,4006	.priv_size			= sizeof(struct mlxsw_sp),4007	.fw_req_rev			= &mlxsw_sp2_fw_rev,4008	.fw_filename			= MLXSW_SP2_FW_FILENAME,4009	.init				= mlxsw_sp2_init,4010	.fini				= mlxsw_sp_fini,4011	.port_split			= mlxsw_sp_port_split,4012	.port_unsplit			= mlxsw_sp_port_unsplit,4013	.ports_remove_selected		= mlxsw_sp_ports_remove_selected,4014	.sb_pool_get			= mlxsw_sp_sb_pool_get,4015	.sb_pool_set			= mlxsw_sp_sb_pool_set,4016	.sb_port_pool_get		= mlxsw_sp_sb_port_pool_get,4017	.sb_port_pool_set		= mlxsw_sp_sb_port_pool_set,4018	.sb_tc_pool_bind_get		= mlxsw_sp_sb_tc_pool_bind_get,4019	.sb_tc_pool_bind_set		= mlxsw_sp_sb_tc_pool_bind_set,4020	.sb_occ_snapshot		= mlxsw_sp_sb_occ_snapshot,4021	.sb_occ_max_clear		= mlxsw_sp_sb_occ_max_clear,4022	.sb_occ_port_pool_get		= mlxsw_sp_sb_occ_port_pool_get,4023	.sb_occ_tc_port_bind_get	= mlxsw_sp_sb_occ_tc_port_bind_get,4024	.trap_init			= mlxsw_sp_trap_init,4025	.trap_fini			= mlxsw_sp_trap_fini,4026	.trap_action_set		= mlxsw_sp_trap_action_set,4027	.trap_group_init		= mlxsw_sp_trap_group_init,4028	.trap_group_set			= mlxsw_sp_trap_group_set,4029	.trap_policer_init		= mlxsw_sp_trap_policer_init,4030	.trap_policer_fini		= mlxsw_sp_trap_policer_fini,4031	.trap_policer_set		= mlxsw_sp_trap_policer_set,4032	.trap_policer_counter_get	= mlxsw_sp_trap_policer_counter_get,4033	.txhdr_construct		= mlxsw_sp_txhdr_construct,4034	.resources_register		= mlxsw_sp2_resources_register,4035	.ptp_transmitted		= mlxsw_sp_ptp_transmitted,4036	.txhdr_len			= MLXSW_TXHDR_LEN,4037	.profile			= &mlxsw_sp2_config_profile,4038	.sdq_supports_cqe_v2		= true,4039};4040 4041static struct mlxsw_driver mlxsw_sp3_driver = {4042	.kind				= mlxsw_sp3_driver_name,4043	.priv_size			= sizeof(struct mlxsw_sp),4044	.fw_req_rev			= &mlxsw_sp3_fw_rev,4045	.fw_filename			= MLXSW_SP3_FW_FILENAME,4046	.init				= mlxsw_sp3_init,4047	.fini				= mlxsw_sp_fini,4048	.port_split			= mlxsw_sp_port_split,4049	.port_unsplit			= mlxsw_sp_port_unsplit,4050	.ports_remove_selected		= mlxsw_sp_ports_remove_selected,4051	.sb_pool_get			= mlxsw_sp_sb_pool_get,4052	.sb_pool_set			= mlxsw_sp_sb_pool_set,4053	.sb_port_pool_get		= mlxsw_sp_sb_port_pool_get,4054	.sb_port_pool_set		= mlxsw_sp_sb_port_pool_set,4055	.sb_tc_pool_bind_get		= mlxsw_sp_sb_tc_pool_bind_get,4056	.sb_tc_pool_bind_set		= mlxsw_sp_sb_tc_pool_bind_set,4057	.sb_occ_snapshot		= mlxsw_sp_sb_occ_snapshot,4058	.sb_occ_max_clear		= mlxsw_sp_sb_occ_max_clear,4059	.sb_occ_port_pool_get		= mlxsw_sp_sb_occ_port_pool_get,4060	.sb_occ_tc_port_bind_get	= mlxsw_sp_sb_occ_tc_port_bind_get,4061	.trap_init			= mlxsw_sp_trap_init,4062	.trap_fini			= mlxsw_sp_trap_fini,4063	.trap_action_set		= mlxsw_sp_trap_action_set,4064	.trap_group_init		= mlxsw_sp_trap_group_init,4065	.trap_group_set			= mlxsw_sp_trap_group_set,4066	.trap_policer_init		= mlxsw_sp_trap_policer_init,4067	.trap_policer_fini		= mlxsw_sp_trap_policer_fini,4068	.trap_policer_set		= mlxsw_sp_trap_policer_set,4069	.trap_policer_counter_get	= mlxsw_sp_trap_policer_counter_get,4070	.txhdr_construct		= mlxsw_sp_txhdr_construct,4071	.resources_register		= mlxsw_sp2_resources_register,4072	.ptp_transmitted		= mlxsw_sp_ptp_transmitted,4073	.txhdr_len			= MLXSW_TXHDR_LEN,4074	.profile			= &mlxsw_sp2_config_profile,4075	.sdq_supports_cqe_v2		= true,4076};4077 4078static struct mlxsw_driver mlxsw_sp4_driver = {4079	.kind				= mlxsw_sp4_driver_name,4080	.priv_size			= sizeof(struct mlxsw_sp),4081	.init				= mlxsw_sp4_init,4082	.fini				= mlxsw_sp_fini,4083	.port_split			= mlxsw_sp_port_split,4084	.port_unsplit			= mlxsw_sp_port_unsplit,4085	.ports_remove_selected		= mlxsw_sp_ports_remove_selected,4086	.sb_pool_get			= mlxsw_sp_sb_pool_get,4087	.sb_pool_set			= mlxsw_sp_sb_pool_set,4088	.sb_port_pool_get		= mlxsw_sp_sb_port_pool_get,4089	.sb_port_pool_set		= mlxsw_sp_sb_port_pool_set,4090	.sb_tc_pool_bind_get		= mlxsw_sp_sb_tc_pool_bind_get,4091	.sb_tc_pool_bind_set		= mlxsw_sp_sb_tc_pool_bind_set,4092	.sb_occ_snapshot		= mlxsw_sp_sb_occ_snapshot,4093	.sb_occ_max_clear		= mlxsw_sp_sb_occ_max_clear,4094	.sb_occ_port_pool_get		= mlxsw_sp_sb_occ_port_pool_get,4095	.sb_occ_tc_port_bind_get	= mlxsw_sp_sb_occ_tc_port_bind_get,4096	.trap_init			= mlxsw_sp_trap_init,4097	.trap_fini			= mlxsw_sp_trap_fini,4098	.trap_action_set		= mlxsw_sp_trap_action_set,4099	.trap_group_init		= mlxsw_sp_trap_group_init,4100	.trap_group_set			= mlxsw_sp_trap_group_set,4101	.trap_policer_init		= mlxsw_sp_trap_policer_init,4102	.trap_policer_fini		= mlxsw_sp_trap_policer_fini,4103	.trap_policer_set		= mlxsw_sp_trap_policer_set,4104	.trap_policer_counter_get	= mlxsw_sp_trap_policer_counter_get,4105	.txhdr_construct		= mlxsw_sp_txhdr_construct,4106	.resources_register		= mlxsw_sp2_resources_register,4107	.ptp_transmitted		= mlxsw_sp_ptp_transmitted,4108	.txhdr_len			= MLXSW_TXHDR_LEN,4109	.profile			= &mlxsw_sp4_config_profile,4110	.sdq_supports_cqe_v2		= true,4111};4112 4113bool mlxsw_sp_port_dev_check(const struct net_device *dev)4114{4115	return dev->netdev_ops == &mlxsw_sp_port_netdev_ops;4116}4117 4118static int mlxsw_sp_lower_dev_walk(struct net_device *lower_dev,4119				   struct netdev_nested_priv *priv)4120{4121	int ret = 0;4122 4123	if (mlxsw_sp_port_dev_check(lower_dev)) {4124		priv->data = (void *)netdev_priv(lower_dev);4125		ret = 1;4126	}4127 4128	return ret;4129}4130 4131struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev)4132{4133	struct netdev_nested_priv priv = {4134		.data = NULL,4135	};4136 4137	if (mlxsw_sp_port_dev_check(dev))4138		return netdev_priv(dev);4139 4140	netdev_walk_all_lower_dev(dev, mlxsw_sp_lower_dev_walk, &priv);4141 4142	return (struct mlxsw_sp_port *)priv.data;4143}4144 4145struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev)4146{4147	struct mlxsw_sp_port *mlxsw_sp_port;4148 4149	mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev);4150	return mlxsw_sp_port ? mlxsw_sp_port->mlxsw_sp : NULL;4151}4152 4153struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev)4154{4155	struct netdev_nested_priv priv = {4156		.data = NULL,4157	};4158 4159	if (mlxsw_sp_port_dev_check(dev))4160		return netdev_priv(dev);4161 4162	netdev_walk_all_lower_dev_rcu(dev, mlxsw_sp_lower_dev_walk,4163				      &priv);4164 4165	return (struct mlxsw_sp_port *)priv.data;4166}4167 4168int mlxsw_sp_parsing_depth_inc(struct mlxsw_sp *mlxsw_sp)4169{4170	char mprs_pl[MLXSW_REG_MPRS_LEN];4171	int err = 0;4172 4173	mutex_lock(&mlxsw_sp->parsing.lock);4174 4175	if (refcount_inc_not_zero(&mlxsw_sp->parsing.parsing_depth_ref))4176		goto out_unlock;4177 4178	mlxsw_reg_mprs_pack(mprs_pl, MLXSW_SP_INCREASED_PARSING_DEPTH,4179			    mlxsw_sp->parsing.vxlan_udp_dport);4180	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl);4181	if (err)4182		goto out_unlock;4183 4184	mlxsw_sp->parsing.parsing_depth = MLXSW_SP_INCREASED_PARSING_DEPTH;4185	refcount_set(&mlxsw_sp->parsing.parsing_depth_ref, 1);4186 4187out_unlock:4188	mutex_unlock(&mlxsw_sp->parsing.lock);4189	return err;4190}4191 4192void mlxsw_sp_parsing_depth_dec(struct mlxsw_sp *mlxsw_sp)4193{4194	char mprs_pl[MLXSW_REG_MPRS_LEN];4195 4196	mutex_lock(&mlxsw_sp->parsing.lock);4197 4198	if (!refcount_dec_and_test(&mlxsw_sp->parsing.parsing_depth_ref))4199		goto out_unlock;4200 4201	mlxsw_reg_mprs_pack(mprs_pl, MLXSW_SP_DEFAULT_PARSING_DEPTH,4202			    mlxsw_sp->parsing.vxlan_udp_dport);4203	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl);4204	mlxsw_sp->parsing.parsing_depth = MLXSW_SP_DEFAULT_PARSING_DEPTH;4205 4206out_unlock:4207	mutex_unlock(&mlxsw_sp->parsing.lock);4208}4209 4210int mlxsw_sp_parsing_vxlan_udp_dport_set(struct mlxsw_sp *mlxsw_sp,4211					 __be16 udp_dport)4212{4213	char mprs_pl[MLXSW_REG_MPRS_LEN];4214	int err;4215 4216	mutex_lock(&mlxsw_sp->parsing.lock);4217 4218	mlxsw_reg_mprs_pack(mprs_pl, mlxsw_sp->parsing.parsing_depth,4219			    be16_to_cpu(udp_dport));4220	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl);4221	if (err)4222		goto out_unlock;4223 4224	mlxsw_sp->parsing.vxlan_udp_dport = be16_to_cpu(udp_dport);4225 4226out_unlock:4227	mutex_unlock(&mlxsw_sp->parsing.lock);4228	return err;4229}4230 4231static void4232mlxsw_sp_port_lag_uppers_cleanup(struct mlxsw_sp_port *mlxsw_sp_port,4233				 struct net_device *lag_dev)4234{4235	struct net_device *br_dev = netdev_master_upper_dev_get(lag_dev);4236	struct net_device *upper_dev;4237	struct list_head *iter;4238 4239	if (netif_is_bridge_port(lag_dev))4240		mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, br_dev);4241 4242	netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {4243		if (!netif_is_bridge_port(upper_dev))4244			continue;4245		br_dev = netdev_master_upper_dev_get(upper_dev);4246		mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, br_dev);4247	}4248}4249 4250static struct mlxsw_sp_lag *4251mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev,4252		    struct netlink_ext_ack *extack)4253{4254	char sldr_pl[MLXSW_REG_SLDR_LEN];4255	struct mlxsw_sp_lag *lag;4256	u16 lag_id;4257	int i, err;4258 4259	for (i = 0; i < mlxsw_sp->max_lag; i++) {4260		if (!mlxsw_sp->lags[i].dev)4261			break;4262	}4263 4264	if (i == mlxsw_sp->max_lag) {4265		NL_SET_ERR_MSG_MOD(extack,4266				   "Exceeded number of supported LAG devices");4267		return ERR_PTR(-EBUSY);4268	}4269 4270	lag_id = i;4271	mlxsw_reg_sldr_lag_create_pack(sldr_pl, lag_id);4272	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);4273	if (err)4274		return ERR_PTR(err);4275 4276	lag = &mlxsw_sp->lags[lag_id];4277	lag->lag_id = lag_id;4278	lag->dev = lag_dev;4279	refcount_set(&lag->ref_count, 1);4280 4281	return lag;4282}4283 4284static int4285mlxsw_sp_lag_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_lag *lag)4286{4287	char sldr_pl[MLXSW_REG_SLDR_LEN];4288 4289	lag->dev = NULL;4290 4291	mlxsw_reg_sldr_lag_destroy_pack(sldr_pl, lag->lag_id);4292	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);4293}4294 4295static int mlxsw_sp_lag_col_port_add(struct mlxsw_sp_port *mlxsw_sp_port,4296				     u16 lag_id, u8 port_index)4297{4298	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;4299	char slcor_pl[MLXSW_REG_SLCOR_LEN];4300 4301	mlxsw_reg_slcor_port_add_pack(slcor_pl, mlxsw_sp_port->local_port,4302				      lag_id, port_index);4303	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl);4304}4305 4306static int mlxsw_sp_lag_col_port_remove(struct mlxsw_sp_port *mlxsw_sp_port,4307					u16 lag_id)4308{4309	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;4310	char slcor_pl[MLXSW_REG_SLCOR_LEN];4311 4312	mlxsw_reg_slcor_port_remove_pack(slcor_pl, mlxsw_sp_port->local_port,4313					 lag_id);4314	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl);4315}4316 4317static int mlxsw_sp_lag_col_port_enable(struct mlxsw_sp_port *mlxsw_sp_port,4318					u16 lag_id)4319{4320	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;4321	char slcor_pl[MLXSW_REG_SLCOR_LEN];4322 4323	mlxsw_reg_slcor_col_enable_pack(slcor_pl, mlxsw_sp_port->local_port,4324					lag_id);4325	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl);4326}4327 4328static int mlxsw_sp_lag_col_port_disable(struct mlxsw_sp_port *mlxsw_sp_port,4329					 u16 lag_id)4330{4331	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;4332	char slcor_pl[MLXSW_REG_SLCOR_LEN];4333 4334	mlxsw_reg_slcor_col_disable_pack(slcor_pl, mlxsw_sp_port->local_port,4335					 lag_id);4336	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl);4337}4338 4339static struct mlxsw_sp_lag *4340mlxsw_sp_lag_find(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev)4341{4342	int i;4343 4344	for (i = 0; i < mlxsw_sp->max_lag; i++) {4345		if (!mlxsw_sp->lags[i].dev)4346			continue;4347 4348		if (mlxsw_sp->lags[i].dev == lag_dev)4349			return &mlxsw_sp->lags[i];4350	}4351 4352	return NULL;4353}4354 4355static struct mlxsw_sp_lag *4356mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev,4357		 struct netlink_ext_ack *extack)4358{4359	struct mlxsw_sp_lag *lag;4360 4361	lag = mlxsw_sp_lag_find(mlxsw_sp, lag_dev);4362	if (lag) {4363		refcount_inc(&lag->ref_count);4364		return lag;4365	}4366 4367	return mlxsw_sp_lag_create(mlxsw_sp, lag_dev, extack);4368}4369 4370static void4371mlxsw_sp_lag_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_lag *lag)4372{4373	if (!refcount_dec_and_test(&lag->ref_count))4374		return;4375 4376	mlxsw_sp_lag_destroy(mlxsw_sp, lag);4377}4378 4379static bool4380mlxsw_sp_master_lag_check(struct mlxsw_sp *mlxsw_sp,4381			  struct net_device *lag_dev,4382			  struct netdev_lag_upper_info *lag_upper_info,4383			  struct netlink_ext_ack *extack)4384{4385	if (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) {4386		NL_SET_ERR_MSG_MOD(extack, "LAG device using unsupported Tx type");4387		return false;4388	}4389	return true;4390}4391 4392static int mlxsw_sp_port_lag_index_get(struct mlxsw_sp *mlxsw_sp,4393				       u16 lag_id, u8 *p_port_index)4394{4395	u64 max_lag_members;4396	int i;4397 4398	max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core,4399					     MAX_LAG_MEMBERS);4400	for (i = 0; i < max_lag_members; i++) {4401		if (!mlxsw_sp_port_lagged_get(mlxsw_sp, lag_id, i)) {4402			*p_port_index = i;4403			return 0;4404		}4405	}4406	return -EBUSY;4407}4408 4409static int mlxsw_sp_lag_uppers_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port,4410					   struct net_device *lag_dev,4411					   struct netlink_ext_ack *extack)4412{4413	struct net_device *upper_dev;4414	struct net_device *master;4415	struct list_head *iter;4416	int done = 0;4417	int err;4418 4419	master = netdev_master_upper_dev_get(lag_dev);4420	if (master && netif_is_bridge_master(master)) {4421		err = mlxsw_sp_port_bridge_join(mlxsw_sp_port, lag_dev, master,4422						extack);4423		if (err)4424			return err;4425	}4426 4427	netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {4428		if (!is_vlan_dev(upper_dev))4429			continue;4430 4431		master = netdev_master_upper_dev_get(upper_dev);4432		if (master && netif_is_bridge_master(master)) {4433			err = mlxsw_sp_port_bridge_join(mlxsw_sp_port,4434							upper_dev, master,4435							extack);4436			if (err)4437				goto err_port_bridge_join;4438		}4439 4440		++done;4441	}4442 4443	return 0;4444 4445err_port_bridge_join:4446	netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {4447		if (!is_vlan_dev(upper_dev))4448			continue;4449 4450		master = netdev_master_upper_dev_get(upper_dev);4451		if (!master || !netif_is_bridge_master(master))4452			continue;4453 4454		if (!done--)4455			break;4456 4457		mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, master);4458	}4459 4460	master = netdev_master_upper_dev_get(lag_dev);4461	if (master && netif_is_bridge_master(master))4462		mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, master);4463 4464	return err;4465}4466 4467static void4468mlxsw_sp_lag_uppers_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port,4469				 struct net_device *lag_dev)4470{4471	struct net_device *upper_dev;4472	struct net_device *master;4473	struct list_head *iter;4474 4475	netdev_for_each_upper_dev_rcu(lag_dev, upper_dev, iter) {4476		if (!is_vlan_dev(upper_dev))4477			continue;4478 4479		master = netdev_master_upper_dev_get(upper_dev);4480		if (!master)4481			continue;4482 4483		mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev, master);4484	}4485 4486	master = netdev_master_upper_dev_get(lag_dev);4487	if (master)4488		mlxsw_sp_port_bridge_leave(mlxsw_sp_port, lag_dev, master);4489}4490 4491static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,4492				  struct net_device *lag_dev,4493				  struct netlink_ext_ack *extack)4494{4495	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;4496	struct mlxsw_sp_lag *lag;4497	u16 lag_id;4498	u8 port_index;4499	int err;4500 4501	lag = mlxsw_sp_lag_get(mlxsw_sp, lag_dev, extack);4502	if (IS_ERR(lag))4503		return PTR_ERR(lag);4504 4505	lag_id = lag->lag_id;4506	err = mlxsw_sp_port_lag_index_get(mlxsw_sp, lag_id, &port_index);4507	if (err)4508		return err;4509 4510	err = mlxsw_sp_lag_uppers_bridge_join(mlxsw_sp_port, lag_dev,4511					      extack);4512	if (err)4513		goto err_lag_uppers_bridge_join;4514 4515	err = mlxsw_sp_lag_col_port_add(mlxsw_sp_port, lag_id, port_index);4516	if (err)4517		goto err_col_port_add;4518 4519	mlxsw_core_lag_mapping_set(mlxsw_sp->core, lag_id, port_index,4520				   mlxsw_sp_port->local_port);4521	mlxsw_sp_port->lag_id = lag_id;4522	mlxsw_sp_port->lagged = 1;4523 4524	err = mlxsw_sp_fid_port_join_lag(mlxsw_sp_port);4525	if (err)4526		goto err_fid_port_join_lag;4527 4528	/* Port is no longer usable as a router interface */4529	if (mlxsw_sp_port->default_vlan->fid)4530		mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port->default_vlan);4531 4532	/* Join a router interface configured on the LAG, if exists */4533	err = mlxsw_sp_router_port_join_lag(mlxsw_sp_port, lag_dev,4534					    extack);4535	if (err)4536		goto err_router_join;4537 4538	err = mlxsw_sp_netdevice_enslavement_replay(mlxsw_sp, lag_dev, extack);4539	if (err)4540		goto err_replay;4541 4542	return 0;4543 4544err_replay:4545	mlxsw_sp_router_port_leave_lag(mlxsw_sp_port, lag_dev);4546err_router_join:4547	mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port);4548err_fid_port_join_lag:4549	mlxsw_sp_port->lagged = 0;4550	mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id,4551				     mlxsw_sp_port->local_port);4552	mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id);4553err_col_port_add:4554	mlxsw_sp_lag_uppers_bridge_leave(mlxsw_sp_port, lag_dev);4555err_lag_uppers_bridge_join:4556	mlxsw_sp_lag_put(mlxsw_sp, lag);4557	return err;4558}4559 4560static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,4561				    struct net_device *lag_dev)4562{4563	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;4564	u16 lag_id = mlxsw_sp_port->lag_id;4565	struct mlxsw_sp_lag *lag;4566 4567	if (!mlxsw_sp_port->lagged)4568		return;4569	lag = &mlxsw_sp->lags[lag_id];4570 4571	mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id);4572 4573	/* Any VLANs configured on the port are no longer valid */4574	mlxsw_sp_port_vlan_flush(mlxsw_sp_port, false);4575	mlxsw_sp_port_vlan_cleanup(mlxsw_sp_port->default_vlan);4576	/* Make the LAG and its directly linked uppers leave bridges they4577	 * are memeber in4578	 */4579	mlxsw_sp_port_lag_uppers_cleanup(mlxsw_sp_port, lag_dev);4580 4581	mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port);4582 4583	mlxsw_sp_lag_put(mlxsw_sp, lag);4584 4585	mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id,4586				     mlxsw_sp_port->local_port);4587	mlxsw_sp_port->lagged = 0;4588 4589	/* Make sure untagged frames are allowed to ingress */4590	mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID,4591			       ETH_P_8021Q);4592}4593 4594static int mlxsw_sp_lag_dist_port_add(struct mlxsw_sp_port *mlxsw_sp_port,4595				      u16 lag_id)4596{4597	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;4598	char sldr_pl[MLXSW_REG_SLDR_LEN];4599 4600	mlxsw_reg_sldr_lag_add_port_pack(sldr_pl, lag_id,4601					 mlxsw_sp_port->local_port);4602	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);4603}4604 4605static int mlxsw_sp_lag_dist_port_remove(struct mlxsw_sp_port *mlxsw_sp_port,4606					 u16 lag_id)4607{4608	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;4609	char sldr_pl[MLXSW_REG_SLDR_LEN];4610 4611	mlxsw_reg_sldr_lag_remove_port_pack(sldr_pl, lag_id,4612					    mlxsw_sp_port->local_port);4613	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl);4614}4615 4616static int4617mlxsw_sp_port_lag_col_dist_enable(struct mlxsw_sp_port *mlxsw_sp_port)4618{4619	int err;4620 4621	err = mlxsw_sp_lag_col_port_enable(mlxsw_sp_port,4622					   mlxsw_sp_port->lag_id);4623	if (err)4624		return err;4625 4626	err = mlxsw_sp_lag_dist_port_add(mlxsw_sp_port, mlxsw_sp_port->lag_id);4627	if (err)4628		goto err_dist_port_add;4629 4630	return 0;4631 4632err_dist_port_add:4633	mlxsw_sp_lag_col_port_disable(mlxsw_sp_port, mlxsw_sp_port->lag_id);4634	return err;4635}4636 4637static int4638mlxsw_sp_port_lag_col_dist_disable(struct mlxsw_sp_port *mlxsw_sp_port)4639{4640	int err;4641 4642	err = mlxsw_sp_lag_dist_port_remove(mlxsw_sp_port,4643					    mlxsw_sp_port->lag_id);4644	if (err)4645		return err;4646 4647	err = mlxsw_sp_lag_col_port_disable(mlxsw_sp_port,4648					    mlxsw_sp_port->lag_id);4649	if (err)4650		goto err_col_port_disable;4651 4652	return 0;4653 4654err_col_port_disable:4655	mlxsw_sp_lag_dist_port_add(mlxsw_sp_port, mlxsw_sp_port->lag_id);4656	return err;4657}4658 4659static int mlxsw_sp_port_lag_changed(struct mlxsw_sp_port *mlxsw_sp_port,4660				     struct netdev_lag_lower_state_info *info)4661{4662	if (info->tx_enabled)4663		return mlxsw_sp_port_lag_col_dist_enable(mlxsw_sp_port);4664	else4665		return mlxsw_sp_port_lag_col_dist_disable(mlxsw_sp_port);4666}4667 4668static int mlxsw_sp_port_stp_set(struct mlxsw_sp_port *mlxsw_sp_port,4669				 bool enable)4670{4671	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;4672	enum mlxsw_reg_spms_state spms_state;4673	char *spms_pl;4674	u16 vid;4675	int err;4676 4677	spms_state = enable ? MLXSW_REG_SPMS_STATE_FORWARDING :4678			      MLXSW_REG_SPMS_STATE_DISCARDING;4679 4680	spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL);4681	if (!spms_pl)4682		return -ENOMEM;4683	mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port);4684 4685	for (vid = 0; vid < VLAN_N_VID; vid++)4686		mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state);4687 4688	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl);4689	kfree(spms_pl);4690	return err;4691}4692 4693static int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port)4694{4695	u16 vid = 1;4696	int err;4697 4698	err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);4699	if (err)4700		return err;4701	err = mlxsw_sp_port_stp_set(mlxsw_sp_port, true);4702	if (err)4703		goto err_port_stp_set;4704	err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 1, VLAN_N_VID - 2,4705				     true, false);4706	if (err)4707		goto err_port_vlan_set;4708 4709	for (; vid <= VLAN_N_VID - 1; vid++) {4710		err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port,4711						     vid, false);4712		if (err)4713			goto err_vid_learning_set;4714	}4715 4716	return 0;4717 4718err_vid_learning_set:4719	for (vid--; vid >= 1; vid--)4720		mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true);4721err_port_vlan_set:4722	mlxsw_sp_port_stp_set(mlxsw_sp_port, false);4723err_port_stp_set:4724	mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);4725	return err;4726}4727 4728static void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port)4729{4730	u16 vid;4731 4732	for (vid = VLAN_N_VID - 1; vid >= 1; vid--)4733		mlxsw_sp_port_vid_learning_set(mlxsw_sp_port,4734					       vid, true);4735 4736	mlxsw_sp_port_vlan_set(mlxsw_sp_port, 1, VLAN_N_VID - 2,4737			       false, false);4738	mlxsw_sp_port_stp_set(mlxsw_sp_port, false);4739	mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);4740}4741 4742static bool mlxsw_sp_bridge_has_multiple_vxlans(struct net_device *br_dev)4743{4744	unsigned int num_vxlans = 0;4745	struct net_device *dev;4746	struct list_head *iter;4747 4748	netdev_for_each_lower_dev(br_dev, dev, iter) {4749		if (netif_is_vxlan(dev))4750			num_vxlans++;4751	}4752 4753	return num_vxlans > 1;4754}4755 4756static bool mlxsw_sp_bridge_vxlan_vlan_is_valid(struct net_device *br_dev)4757{4758	DECLARE_BITMAP(vlans, VLAN_N_VID) = {0};4759	struct net_device *dev;4760	struct list_head *iter;4761 4762	netdev_for_each_lower_dev(br_dev, dev, iter) {4763		u16 pvid;4764		int err;4765 4766		if (!netif_is_vxlan(dev))4767			continue;4768 4769		err = mlxsw_sp_vxlan_mapped_vid(dev, &pvid);4770		if (err || !pvid)4771			continue;4772 4773		if (test_and_set_bit(pvid, vlans))4774			return false;4775	}4776 4777	return true;4778}4779 4780static bool mlxsw_sp_bridge_vxlan_is_valid(struct net_device *br_dev,4781					   struct netlink_ext_ack *extack)4782{4783	if (br_multicast_enabled(br_dev)) {4784		NL_SET_ERR_MSG_MOD(extack, "Multicast can not be enabled on a bridge with a VxLAN device");4785		return false;4786	}4787 4788	if (!br_vlan_enabled(br_dev) &&4789	    mlxsw_sp_bridge_has_multiple_vxlans(br_dev)) {4790		NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices are not supported in a VLAN-unaware bridge");4791		return false;4792	}4793 4794	if (br_vlan_enabled(br_dev) &&4795	    !mlxsw_sp_bridge_vxlan_vlan_is_valid(br_dev)) {4796		NL_SET_ERR_MSG_MOD(extack, "Multiple VxLAN devices cannot have the same VLAN as PVID and egress untagged");4797		return false;4798	}4799 4800	return true;4801}4802 4803static bool mlxsw_sp_netdev_is_master(struct net_device *upper_dev,4804				      struct net_device *dev)4805{4806	return upper_dev == netdev_master_upper_dev_get(dev);4807}4808 4809static int __mlxsw_sp_netdevice_event(struct mlxsw_sp *mlxsw_sp,4810				      unsigned long event, void *ptr,4811				      bool process_foreign);4812 4813static int mlxsw_sp_netdevice_validate_uppers(struct mlxsw_sp *mlxsw_sp,4814					      struct net_device *dev,4815					      struct netlink_ext_ack *extack)4816{4817	struct net_device *upper_dev;4818	struct list_head *iter;4819	int err;4820 4821	netdev_for_each_upper_dev_rcu(dev, upper_dev, iter) {4822		struct netdev_notifier_changeupper_info info = {4823			.info = {4824				.dev = dev,4825				.extack = extack,4826			},4827			.master = mlxsw_sp_netdev_is_master(upper_dev, dev),4828			.upper_dev = upper_dev,4829			.linking = true,4830 4831			/* upper_info is relevant for LAG devices. But we would4832			 * only need this if LAG were a valid upper above4833			 * another upper (e.g. a bridge that is a member of a4834			 * LAG), and that is never a valid configuration. So we4835			 * can keep this as NULL.4836			 */4837			.upper_info = NULL,4838		};4839 4840		err = __mlxsw_sp_netdevice_event(mlxsw_sp,4841						 NETDEV_PRECHANGEUPPER,4842						 &info, true);4843		if (err)4844			return err;4845 4846		err = mlxsw_sp_netdevice_validate_uppers(mlxsw_sp, upper_dev,4847							 extack);4848		if (err)4849			return err;4850	}4851 4852	return 0;4853}4854 4855static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev,4856					       struct net_device *dev,4857					       unsigned long event, void *ptr,4858					       bool replay_deslavement)4859{4860	struct netdev_notifier_changeupper_info *info;4861	struct mlxsw_sp_port *mlxsw_sp_port;4862	struct netlink_ext_ack *extack;4863	struct net_device *upper_dev;4864	struct mlxsw_sp *mlxsw_sp;4865	int err = 0;4866	u16 proto;4867 4868	mlxsw_sp_port = netdev_priv(dev);4869	mlxsw_sp = mlxsw_sp_port->mlxsw_sp;4870	info = ptr;4871	extack = netdev_notifier_info_to_extack(&info->info);4872 4873	switch (event) {4874	case NETDEV_PRECHANGEUPPER:4875		upper_dev = info->upper_dev;4876		if (!is_vlan_dev(upper_dev) &&4877		    !netif_is_lag_master(upper_dev) &&4878		    !netif_is_bridge_master(upper_dev) &&4879		    !netif_is_ovs_master(upper_dev) &&4880		    !netif_is_macvlan(upper_dev) &&4881		    !netif_is_l3_master(upper_dev)) {4882			NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");4883			return -EINVAL;4884		}4885		if (!info->linking)4886			break;4887		if (netif_is_bridge_master(upper_dev) &&4888		    !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) &&4889		    mlxsw_sp_bridge_has_vxlan(upper_dev) &&4890		    !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack))4891			return -EOPNOTSUPP;4892		if (netdev_has_any_upper_dev(upper_dev) &&4893		    (!netif_is_bridge_master(upper_dev) ||4894		     !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,4895							  upper_dev))) {4896			err = mlxsw_sp_netdevice_validate_uppers(mlxsw_sp,4897								 upper_dev,4898								 extack);4899			if (err)4900				return err;4901		}4902		if (netif_is_lag_master(upper_dev) &&4903		    !mlxsw_sp_master_lag_check(mlxsw_sp, upper_dev,4904					       info->upper_info, extack))4905			return -EINVAL;4906		if (netif_is_lag_master(upper_dev) && vlan_uses_dev(dev)) {4907			NL_SET_ERR_MSG_MOD(extack, "Master device is a LAG master and this device has a VLAN");4908			return -EINVAL;4909		}4910		if (netif_is_lag_port(dev) && is_vlan_dev(upper_dev) &&4911		    !netif_is_lag_master(vlan_dev_real_dev(upper_dev))) {4912			NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on a LAG port");4913			return -EINVAL;4914		}4915		if (netif_is_ovs_master(upper_dev) && vlan_uses_dev(dev)) {4916			NL_SET_ERR_MSG_MOD(extack, "Master device is an OVS master and this device has a VLAN");4917			return -EINVAL;4918		}4919		if (netif_is_ovs_port(dev) && is_vlan_dev(upper_dev)) {4920			NL_SET_ERR_MSG_MOD(extack, "Can not put a VLAN on an OVS port");4921			return -EINVAL;4922		}4923		if (netif_is_bridge_master(upper_dev)) {4924			br_vlan_get_proto(upper_dev, &proto);4925			if (br_vlan_enabled(upper_dev) &&4926			    proto != ETH_P_8021Q && proto != ETH_P_8021AD) {4927				NL_SET_ERR_MSG_MOD(extack, "Enslaving a port to a bridge with unknown VLAN protocol is not supported");4928				return -EOPNOTSUPP;4929			}4930			if (vlan_uses_dev(lower_dev) &&4931			    br_vlan_enabled(upper_dev) &&4932			    proto == ETH_P_8021AD) {4933				NL_SET_ERR_MSG_MOD(extack, "Enslaving a port that already has a VLAN upper to an 802.1ad bridge is not supported");4934				return -EOPNOTSUPP;4935			}4936		}4937		if (netif_is_bridge_port(lower_dev) && is_vlan_dev(upper_dev)) {4938			struct net_device *br_dev = netdev_master_upper_dev_get(lower_dev);4939 4940			if (br_vlan_enabled(br_dev)) {4941				br_vlan_get_proto(br_dev, &proto);4942				if (proto == ETH_P_8021AD) {4943					NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are not supported on a port enslaved to an 802.1ad bridge");4944					return -EOPNOTSUPP;4945				}4946			}4947		}4948		if (is_vlan_dev(upper_dev) &&4949		    ntohs(vlan_dev_vlan_proto(upper_dev)) != ETH_P_8021Q) {4950			NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are only supported with 802.1q VLAN protocol");4951			return -EOPNOTSUPP;4952		}4953		if (is_vlan_dev(upper_dev) && mlxsw_sp_port->security) {4954			NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are not supported on a locked port");4955			return -EOPNOTSUPP;4956		}4957		break;4958	case NETDEV_CHANGEUPPER:4959		upper_dev = info->upper_dev;4960		if (netif_is_bridge_master(upper_dev)) {4961			if (info->linking) {4962				err = mlxsw_sp_port_bridge_join(mlxsw_sp_port,4963								lower_dev,4964								upper_dev,4965								extack);4966			} else {4967				mlxsw_sp_port_bridge_leave(mlxsw_sp_port,4968							   lower_dev,4969							   upper_dev);4970				if (!replay_deslavement)4971					break;4972				mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp,4973								      lower_dev);4974			}4975		} else if (netif_is_lag_master(upper_dev)) {4976			if (info->linking) {4977				err = mlxsw_sp_port_lag_join(mlxsw_sp_port,4978							     upper_dev, extack);4979			} else {4980				mlxsw_sp_port_lag_col_dist_disable(mlxsw_sp_port);4981				mlxsw_sp_port_lag_leave(mlxsw_sp_port,4982							upper_dev);4983				mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp,4984								      dev);4985			}4986		} else if (netif_is_ovs_master(upper_dev)) {4987			if (info->linking)4988				err = mlxsw_sp_port_ovs_join(mlxsw_sp_port);4989			else4990				mlxsw_sp_port_ovs_leave(mlxsw_sp_port);4991		} else if (netif_is_macvlan(upper_dev)) {4992			if (!info->linking)4993				mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);4994		} else if (is_vlan_dev(upper_dev)) {4995			struct net_device *br_dev;4996 4997			if (!netif_is_bridge_port(upper_dev))4998				break;4999			if (info->linking)5000				break;5001			br_dev = netdev_master_upper_dev_get(upper_dev);5002			mlxsw_sp_port_bridge_leave(mlxsw_sp_port, upper_dev,5003						   br_dev);5004		}5005		break;5006	}5007 5008	return err;5009}5010 5011static int mlxsw_sp_netdevice_port_lower_event(struct net_device *dev,5012					       unsigned long event, void *ptr)5013{5014	struct netdev_notifier_changelowerstate_info *info;5015	struct mlxsw_sp_port *mlxsw_sp_port;5016	int err;5017 5018	mlxsw_sp_port = netdev_priv(dev);5019	info = ptr;5020 5021	switch (event) {5022	case NETDEV_CHANGELOWERSTATE:5023		if (netif_is_lag_port(dev) && mlxsw_sp_port->lagged) {5024			err = mlxsw_sp_port_lag_changed(mlxsw_sp_port,5025							info->lower_state_info);5026			if (err)5027				netdev_err(dev, "Failed to reflect link aggregation lower state change\n");5028		}5029		break;5030	}5031 5032	return 0;5033}5034 5035static int mlxsw_sp_netdevice_port_event(struct net_device *lower_dev,5036					 struct net_device *port_dev,5037					 unsigned long event, void *ptr,5038					 bool replay_deslavement)5039{5040	switch (event) {5041	case NETDEV_PRECHANGEUPPER:5042	case NETDEV_CHANGEUPPER:5043		return mlxsw_sp_netdevice_port_upper_event(lower_dev, port_dev,5044							   event, ptr,5045							   replay_deslavement);5046	case NETDEV_CHANGELOWERSTATE:5047		return mlxsw_sp_netdevice_port_lower_event(port_dev, event,5048							   ptr);5049	}5050 5051	return 0;5052}5053 5054/* Called for LAG or its upper VLAN after the per-LAG-lower processing was done,5055 * to do any per-LAG / per-LAG-upper processing.5056 */5057static int mlxsw_sp_netdevice_post_lag_event(struct net_device *dev,5058					     unsigned long event,5059					     void *ptr)5060{5061	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(dev);5062	struct netdev_notifier_changeupper_info *info = ptr;5063 5064	if (!mlxsw_sp)5065		return 0;5066 5067	switch (event) {5068	case NETDEV_CHANGEUPPER:5069		if (info->linking)5070			break;5071		if (netif_is_bridge_master(info->upper_dev))5072			mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp, dev);5073		break;5074	}5075	return 0;5076}5077 5078static int mlxsw_sp_netdevice_lag_event(struct net_device *lag_dev,5079					unsigned long event, void *ptr)5080{5081	struct net_device *dev;5082	struct list_head *iter;5083	int ret;5084 5085	netdev_for_each_lower_dev(lag_dev, dev, iter) {5086		if (mlxsw_sp_port_dev_check(dev)) {5087			ret = mlxsw_sp_netdevice_port_event(lag_dev, dev, event,5088							    ptr, false);5089			if (ret)5090				return ret;5091		}5092	}5093 5094	return mlxsw_sp_netdevice_post_lag_event(lag_dev, event, ptr);5095}5096 5097static int mlxsw_sp_netdevice_port_vlan_event(struct net_device *vlan_dev,5098					      struct net_device *dev,5099					      unsigned long event, void *ptr,5100					      u16 vid, bool replay_deslavement)5101{5102	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);5103	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;5104	struct netdev_notifier_changeupper_info *info = ptr;5105	struct netlink_ext_ack *extack;5106	struct net_device *upper_dev;5107	int err = 0;5108 5109	extack = netdev_notifier_info_to_extack(&info->info);5110 5111	switch (event) {5112	case NETDEV_PRECHANGEUPPER:5113		upper_dev = info->upper_dev;5114		if (!netif_is_bridge_master(upper_dev) &&5115		    !netif_is_macvlan(upper_dev) &&5116		    !netif_is_l3_master(upper_dev)) {5117			NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");5118			return -EINVAL;5119		}5120		if (!info->linking)5121			break;5122		if (netif_is_bridge_master(upper_dev) &&5123		    !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp, upper_dev) &&5124		    mlxsw_sp_bridge_has_vxlan(upper_dev) &&5125		    !mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack))5126			return -EOPNOTSUPP;5127		if (netdev_has_any_upper_dev(upper_dev) &&5128		    (!netif_is_bridge_master(upper_dev) ||5129		     !mlxsw_sp_bridge_device_is_offloaded(mlxsw_sp,5130							  upper_dev))) {5131			err = mlxsw_sp_netdevice_validate_uppers(mlxsw_sp,5132								 upper_dev,5133								 extack);5134			if (err)5135				return err;5136		}5137		break;5138	case NETDEV_CHANGEUPPER:5139		upper_dev = info->upper_dev;5140		if (netif_is_bridge_master(upper_dev)) {5141			if (info->linking) {5142				err = mlxsw_sp_port_bridge_join(mlxsw_sp_port,5143								vlan_dev,5144								upper_dev,5145								extack);5146			} else {5147				mlxsw_sp_port_bridge_leave(mlxsw_sp_port,5148							   vlan_dev,5149							   upper_dev);5150				if (!replay_deslavement)5151					break;5152				mlxsw_sp_netdevice_deslavement_replay(mlxsw_sp,5153								      vlan_dev);5154			}5155		} else if (netif_is_macvlan(upper_dev)) {5156			if (!info->linking)5157				mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);5158		}5159		break;5160	}5161 5162	return err;5163}5164 5165static int mlxsw_sp_netdevice_lag_port_vlan_event(struct net_device *vlan_dev,5166						  struct net_device *lag_dev,5167						  unsigned long event,5168						  void *ptr, u16 vid)5169{5170	struct net_device *dev;5171	struct list_head *iter;5172	int ret;5173 5174	netdev_for_each_lower_dev(lag_dev, dev, iter) {5175		if (mlxsw_sp_port_dev_check(dev)) {5176			ret = mlxsw_sp_netdevice_port_vlan_event(vlan_dev, dev,5177								 event, ptr,5178								 vid, false);5179			if (ret)5180				return ret;5181		}5182	}5183 5184	return mlxsw_sp_netdevice_post_lag_event(vlan_dev, event, ptr);5185}5186 5187static int mlxsw_sp_netdevice_bridge_vlan_event(struct mlxsw_sp *mlxsw_sp,5188						struct net_device *vlan_dev,5189						struct net_device *br_dev,5190						unsigned long event, void *ptr,5191						u16 vid, bool process_foreign)5192{5193	struct netdev_notifier_changeupper_info *info = ptr;5194	struct netlink_ext_ack *extack;5195	struct net_device *upper_dev;5196 5197	if (!process_foreign && !mlxsw_sp_lower_get(vlan_dev))5198		return 0;5199 5200	extack = netdev_notifier_info_to_extack(&info->info);5201 5202	switch (event) {5203	case NETDEV_PRECHANGEUPPER:5204		upper_dev = info->upper_dev;5205		if (!netif_is_macvlan(upper_dev) &&5206		    !netif_is_l3_master(upper_dev)) {5207			NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");5208			return -EOPNOTSUPP;5209		}5210		break;5211	case NETDEV_CHANGEUPPER:5212		upper_dev = info->upper_dev;5213		if (info->linking)5214			break;5215		if (netif_is_macvlan(upper_dev))5216			mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);5217		break;5218	}5219 5220	return 0;5221}5222 5223static int mlxsw_sp_netdevice_vlan_event(struct mlxsw_sp *mlxsw_sp,5224					 struct net_device *vlan_dev,5225					 unsigned long event, void *ptr,5226					 bool process_foreign)5227{5228	struct net_device *real_dev = vlan_dev_real_dev(vlan_dev);5229	u16 vid = vlan_dev_vlan_id(vlan_dev);5230 5231	if (mlxsw_sp_port_dev_check(real_dev))5232		return mlxsw_sp_netdevice_port_vlan_event(vlan_dev, real_dev,5233							  event, ptr, vid,5234							  true);5235	else if (netif_is_lag_master(real_dev))5236		return mlxsw_sp_netdevice_lag_port_vlan_event(vlan_dev,5237							      real_dev, event,5238							      ptr, vid);5239	else if (netif_is_bridge_master(real_dev))5240		return mlxsw_sp_netdevice_bridge_vlan_event(mlxsw_sp, vlan_dev,5241							    real_dev, event,5242							    ptr, vid,5243							    process_foreign);5244 5245	return 0;5246}5247 5248static int mlxsw_sp_netdevice_bridge_event(struct mlxsw_sp *mlxsw_sp,5249					   struct net_device *br_dev,5250					   unsigned long event, void *ptr,5251					   bool process_foreign)5252{5253	struct netdev_notifier_changeupper_info *info = ptr;5254	struct netlink_ext_ack *extack;5255	struct net_device *upper_dev;5256	u16 proto;5257 5258	if (!process_foreign && !mlxsw_sp_lower_get(br_dev))5259		return 0;5260 5261	extack = netdev_notifier_info_to_extack(&info->info);5262 5263	switch (event) {5264	case NETDEV_PRECHANGEUPPER:5265		upper_dev = info->upper_dev;5266		if (!is_vlan_dev(upper_dev) &&5267		    !netif_is_macvlan(upper_dev) &&5268		    !netif_is_l3_master(upper_dev)) {5269			NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");5270			return -EOPNOTSUPP;5271		}5272		if (!info->linking)5273			break;5274		if (br_vlan_enabled(br_dev)) {5275			br_vlan_get_proto(br_dev, &proto);5276			if (proto == ETH_P_8021AD) {5277				NL_SET_ERR_MSG_MOD(extack, "Upper devices are not supported on top of an 802.1ad bridge");5278				return -EOPNOTSUPP;5279			}5280		}5281		if (is_vlan_dev(upper_dev) &&5282		    ntohs(vlan_dev_vlan_proto(upper_dev)) != ETH_P_8021Q) {5283			NL_SET_ERR_MSG_MOD(extack, "VLAN uppers are only supported with 802.1q VLAN protocol");5284			return -EOPNOTSUPP;5285		}5286		break;5287	case NETDEV_CHANGEUPPER:5288		upper_dev = info->upper_dev;5289		if (info->linking)5290			break;5291		if (is_vlan_dev(upper_dev))5292			mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, upper_dev);5293		if (netif_is_macvlan(upper_dev))5294			mlxsw_sp_rif_macvlan_del(mlxsw_sp, upper_dev);5295		break;5296	}5297 5298	return 0;5299}5300 5301static int mlxsw_sp_netdevice_macvlan_event(struct net_device *macvlan_dev,5302					    unsigned long event, void *ptr)5303{5304	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(macvlan_dev);5305	struct netdev_notifier_changeupper_info *info = ptr;5306	struct netlink_ext_ack *extack;5307	struct net_device *upper_dev;5308 5309	if (!mlxsw_sp || event != NETDEV_PRECHANGEUPPER)5310		return 0;5311 5312	extack = netdev_notifier_info_to_extack(&info->info);5313	upper_dev = info->upper_dev;5314 5315	if (!netif_is_l3_master(upper_dev)) {5316		NL_SET_ERR_MSG_MOD(extack, "Unknown upper device type");5317		return -EOPNOTSUPP;5318	}5319 5320	return 0;5321}5322 5323static int mlxsw_sp_netdevice_vxlan_event(struct mlxsw_sp *mlxsw_sp,5324					  struct net_device *dev,5325					  unsigned long event, void *ptr)5326{5327	struct netdev_notifier_changeupper_info *cu_info;5328	struct netdev_notifier_info *info = ptr;5329	struct netlink_ext_ack *extack;5330	struct net_device *upper_dev;5331 5332	extack = netdev_notifier_info_to_extack(info);5333 5334	switch (event) {5335	case NETDEV_CHANGEUPPER:5336		cu_info = container_of(info,5337				       struct netdev_notifier_changeupper_info,5338				       info);5339		upper_dev = cu_info->upper_dev;5340		if (!netif_is_bridge_master(upper_dev))5341			return 0;5342		if (!mlxsw_sp_lower_get(upper_dev))5343			return 0;5344		if (!mlxsw_sp_bridge_vxlan_is_valid(upper_dev, extack))5345			return -EOPNOTSUPP;5346		if (cu_info->linking) {5347			if (!netif_running(dev))5348				return 0;5349			/* When the bridge is VLAN-aware, the VNI of the VxLAN5350			 * device needs to be mapped to a VLAN, but at this5351			 * point no VLANs are configured on the VxLAN device5352			 */5353			if (br_vlan_enabled(upper_dev))5354				return 0;5355			return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev,5356							  dev, 0, extack);5357		} else {5358			/* VLANs were already flushed, which triggered the5359			 * necessary cleanup5360			 */5361			if (br_vlan_enabled(upper_dev))5362				return 0;5363			mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev);5364		}5365		break;5366	case NETDEV_PRE_UP:5367		upper_dev = netdev_master_upper_dev_get(dev);5368		if (!upper_dev)5369			return 0;5370		if (!netif_is_bridge_master(upper_dev))5371			return 0;5372		if (!mlxsw_sp_lower_get(upper_dev))5373			return 0;5374		return mlxsw_sp_bridge_vxlan_join(mlxsw_sp, upper_dev, dev, 0,5375						  extack);5376	case NETDEV_DOWN:5377		upper_dev = netdev_master_upper_dev_get(dev);5378		if (!upper_dev)5379			return 0;5380		if (!netif_is_bridge_master(upper_dev))5381			return 0;5382		if (!mlxsw_sp_lower_get(upper_dev))5383			return 0;5384		mlxsw_sp_bridge_vxlan_leave(mlxsw_sp, dev);5385		break;5386	}5387 5388	return 0;5389}5390 5391static int __mlxsw_sp_netdevice_event(struct mlxsw_sp *mlxsw_sp,5392				      unsigned long event, void *ptr,5393				      bool process_foreign)5394{5395	struct net_device *dev = netdev_notifier_info_to_dev(ptr);5396	struct mlxsw_sp_span_entry *span_entry;5397	int err = 0;5398 5399	if (event == NETDEV_UNREGISTER) {5400		span_entry = mlxsw_sp_span_entry_find_by_port(mlxsw_sp, dev);5401		if (span_entry)5402			mlxsw_sp_span_entry_invalidate(mlxsw_sp, span_entry);5403	}5404 5405	if (netif_is_vxlan(dev))5406		err = mlxsw_sp_netdevice_vxlan_event(mlxsw_sp, dev, event, ptr);5407	else if (mlxsw_sp_port_dev_check(dev))5408		err = mlxsw_sp_netdevice_port_event(dev, dev, event, ptr, true);5409	else if (netif_is_lag_master(dev))5410		err = mlxsw_sp_netdevice_lag_event(dev, event, ptr);5411	else if (is_vlan_dev(dev))5412		err = mlxsw_sp_netdevice_vlan_event(mlxsw_sp, dev, event, ptr,5413						    process_foreign);5414	else if (netif_is_bridge_master(dev))5415		err = mlxsw_sp_netdevice_bridge_event(mlxsw_sp, dev, event, ptr,5416						      process_foreign);5417	else if (netif_is_macvlan(dev))5418		err = mlxsw_sp_netdevice_macvlan_event(dev, event, ptr);5419 5420	return err;5421}5422 5423static int mlxsw_sp_netdevice_event(struct notifier_block *nb,5424				    unsigned long event, void *ptr)5425{5426	struct mlxsw_sp *mlxsw_sp;5427	int err;5428 5429	mlxsw_sp = container_of(nb, struct mlxsw_sp, netdevice_nb);5430	mlxsw_sp_span_respin(mlxsw_sp);5431	err = __mlxsw_sp_netdevice_event(mlxsw_sp, event, ptr, false);5432 5433	return notifier_from_errno(err);5434}5435 5436static const struct pci_device_id mlxsw_sp1_pci_id_table[] = {5437	{PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM), 0},5438	{0, },5439};5440 5441static struct pci_driver mlxsw_sp1_pci_driver = {5442	.name = mlxsw_sp1_driver_name,5443	.id_table = mlxsw_sp1_pci_id_table,5444};5445 5446static const struct pci_device_id mlxsw_sp2_pci_id_table[] = {5447	{PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM2), 0},5448	{0, },5449};5450 5451static struct pci_driver mlxsw_sp2_pci_driver = {5452	.name = mlxsw_sp2_driver_name,5453	.id_table = mlxsw_sp2_pci_id_table,5454};5455 5456static const struct pci_device_id mlxsw_sp3_pci_id_table[] = {5457	{PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM3), 0},5458	{0, },5459};5460 5461static struct pci_driver mlxsw_sp3_pci_driver = {5462	.name = mlxsw_sp3_driver_name,5463	.id_table = mlxsw_sp3_pci_id_table,5464};5465 5466static const struct pci_device_id mlxsw_sp4_pci_id_table[] = {5467	{PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM4), 0},5468	{0, },5469};5470 5471static struct pci_driver mlxsw_sp4_pci_driver = {5472	.name = mlxsw_sp4_driver_name,5473	.id_table = mlxsw_sp4_pci_id_table,5474};5475 5476static int __init mlxsw_sp_module_init(void)5477{5478	int err;5479 5480	err = mlxsw_core_driver_register(&mlxsw_sp1_driver);5481	if (err)5482		return err;5483 5484	err = mlxsw_core_driver_register(&mlxsw_sp2_driver);5485	if (err)5486		goto err_sp2_core_driver_register;5487 5488	err = mlxsw_core_driver_register(&mlxsw_sp3_driver);5489	if (err)5490		goto err_sp3_core_driver_register;5491 5492	err = mlxsw_core_driver_register(&mlxsw_sp4_driver);5493	if (err)5494		goto err_sp4_core_driver_register;5495 5496	err = mlxsw_pci_driver_register(&mlxsw_sp1_pci_driver);5497	if (err)5498		goto err_sp1_pci_driver_register;5499 5500	err = mlxsw_pci_driver_register(&mlxsw_sp2_pci_driver);5501	if (err)5502		goto err_sp2_pci_driver_register;5503 5504	err = mlxsw_pci_driver_register(&mlxsw_sp3_pci_driver);5505	if (err)5506		goto err_sp3_pci_driver_register;5507 5508	err = mlxsw_pci_driver_register(&mlxsw_sp4_pci_driver);5509	if (err)5510		goto err_sp4_pci_driver_register;5511 5512	return 0;5513 5514err_sp4_pci_driver_register:5515	mlxsw_pci_driver_unregister(&mlxsw_sp3_pci_driver);5516err_sp3_pci_driver_register:5517	mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver);5518err_sp2_pci_driver_register:5519	mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver);5520err_sp1_pci_driver_register:5521	mlxsw_core_driver_unregister(&mlxsw_sp4_driver);5522err_sp4_core_driver_register:5523	mlxsw_core_driver_unregister(&mlxsw_sp3_driver);5524err_sp3_core_driver_register:5525	mlxsw_core_driver_unregister(&mlxsw_sp2_driver);5526err_sp2_core_driver_register:5527	mlxsw_core_driver_unregister(&mlxsw_sp1_driver);5528	return err;5529}5530 5531static void __exit mlxsw_sp_module_exit(void)5532{5533	mlxsw_pci_driver_unregister(&mlxsw_sp4_pci_driver);5534	mlxsw_pci_driver_unregister(&mlxsw_sp3_pci_driver);5535	mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver);5536	mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver);5537	mlxsw_core_driver_unregister(&mlxsw_sp4_driver);5538	mlxsw_core_driver_unregister(&mlxsw_sp3_driver);5539	mlxsw_core_driver_unregister(&mlxsw_sp2_driver);5540	mlxsw_core_driver_unregister(&mlxsw_sp1_driver);5541}5542 5543module_init(mlxsw_sp_module_init);5544module_exit(mlxsw_sp_module_exit);5545 5546MODULE_LICENSE("Dual BSD/GPL");5547MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");5548MODULE_DESCRIPTION("Mellanox Spectrum driver");5549MODULE_DEVICE_TABLE(pci, mlxsw_sp1_pci_id_table);5550MODULE_DEVICE_TABLE(pci, mlxsw_sp2_pci_id_table);5551MODULE_DEVICE_TABLE(pci, mlxsw_sp3_pci_id_table);5552MODULE_DEVICE_TABLE(pci, mlxsw_sp4_pci_id_table);5553MODULE_FIRMWARE(MLXSW_SP1_FW_FILENAME);5554MODULE_FIRMWARE(MLXSW_SP2_FW_FILENAME);5555MODULE_FIRMWARE(MLXSW_SP3_FW_FILENAME);5556MODULE_FIRMWARE(MLXSW_SP_LINECARDS_INI_BUNDLE_FILENAME);5557