brintos

brintos / linux-shallow public Read only

0
0
Text · 63.1 KiB · 7aef30d Raw
2398 lines · c
1/*2 * Copyright (c) 2015, Mellanox Technologies. All rights reserved.3 *4 * This software is available to you under a choice of one of two5 * licenses.  You may choose to be licensed under the terms of the GNU6 * General Public License (GPL) Version 2, available from the file7 * COPYING in the main directory of this source tree, or the8 * OpenIB.org BSD license below:9 *10 *     Redistribution and use in source and binary forms, with or11 *     without modification, are permitted provided that the following12 *     conditions are met:13 *14 *      - Redistributions of source code must retain the above15 *        copyright notice, this list of conditions and the following16 *        disclaimer.17 *18 *      - Redistributions in binary form must reproduce the above19 *        copyright notice, this list of conditions and the following20 *        disclaimer in the documentation and/or other materials21 *        provided with the distribution.22 *23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30 * SOFTWARE.31 */32 33#include <linux/etherdevice.h>34#include <linux/debugfs.h>35#include <linux/mlx5/driver.h>36#include <linux/mlx5/mlx5_ifc.h>37#include <linux/mlx5/vport.h>38#include <linux/mlx5/fs.h>39#include <linux/mlx5/mpfs.h>40#include "esw/acl/lgcy.h"41#include "esw/legacy.h"42#include "esw/qos.h"43#include "mlx5_core.h"44#include "lib/eq.h"45#include "lag/lag.h"46#include "eswitch.h"47#include "fs_core.h"48#include "devlink.h"49#include "ecpf.h"50#include "en/mod_hdr.h"51#include "en_accel/ipsec.h"52 53enum {54	MLX5_ACTION_NONE = 0,55	MLX5_ACTION_ADD  = 1,56	MLX5_ACTION_DEL  = 2,57};58 59/* Vport UC/MC hash node */60struct vport_addr {61	struct l2addr_node     node;62	u8                     action;63	u16                    vport;64	struct mlx5_flow_handle *flow_rule;65	bool mpfs; /* UC MAC was added to MPFs */66	/* A flag indicating that mac was added due to mc promiscuous vport */67	bool mc_promisc;68};69 70static int mlx5_eswitch_check(const struct mlx5_core_dev *dev)71{72	if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)73		return -EOPNOTSUPP;74 75	if (!MLX5_ESWITCH_MANAGER(dev))76		return -EOPNOTSUPP;77 78	return 0;79}80 81static struct mlx5_eswitch *__mlx5_devlink_eswitch_get(struct devlink *devlink, bool check)82{83	struct mlx5_core_dev *dev = devlink_priv(devlink);84	int err;85 86	if (check) {87		err = mlx5_eswitch_check(dev);88		if (err)89			return ERR_PTR(err);90	}91 92	return dev->priv.eswitch;93}94 95struct mlx5_eswitch *__must_check96mlx5_devlink_eswitch_get(struct devlink *devlink)97{98	return __mlx5_devlink_eswitch_get(devlink, true);99}100 101struct mlx5_eswitch *mlx5_devlink_eswitch_nocheck_get(struct devlink *devlink)102{103	return __mlx5_devlink_eswitch_get(devlink, false);104}105 106struct mlx5_vport *__must_check107mlx5_eswitch_get_vport(struct mlx5_eswitch *esw, u16 vport_num)108{109	struct mlx5_vport *vport;110 111	if (!esw)112		return ERR_PTR(-EPERM);113 114	vport = xa_load(&esw->vports, vport_num);115	if (!vport) {116		esw_debug(esw->dev, "vport out of range: num(0x%x)\n", vport_num);117		return ERR_PTR(-EINVAL);118	}119	return vport;120}121 122static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport,123					u32 events_mask)124{125	u32 in[MLX5_ST_SZ_DW(modify_nic_vport_context_in)] = {};126	void *nic_vport_ctx;127 128	MLX5_SET(modify_nic_vport_context_in, in,129		 opcode, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT);130	MLX5_SET(modify_nic_vport_context_in, in, field_select.change_event, 1);131	MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport);132	if (vport || mlx5_core_is_ecpf(dev))133		MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1);134	nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in,135				     in, nic_vport_context);136 137	MLX5_SET(nic_vport_context, nic_vport_ctx, arm_change_event, 1);138 139	if (events_mask & MLX5_VPORT_UC_ADDR_CHANGE)140		MLX5_SET(nic_vport_context, nic_vport_ctx,141			 event_on_uc_address_change, 1);142	if (events_mask & MLX5_VPORT_MC_ADDR_CHANGE)143		MLX5_SET(nic_vport_context, nic_vport_ctx,144			 event_on_mc_address_change, 1);145	if (events_mask & MLX5_VPORT_PROMISC_CHANGE)146		MLX5_SET(nic_vport_context, nic_vport_ctx,147			 event_on_promisc_change, 1);148 149	return mlx5_cmd_exec_in(dev, modify_nic_vport_context, in);150}151 152/* E-Switch vport context HW commands */153int mlx5_eswitch_modify_esw_vport_context(struct mlx5_core_dev *dev, u16 vport,154					  bool other_vport, void *in)155{156	MLX5_SET(modify_esw_vport_context_in, in, opcode,157		 MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT);158	MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport);159	MLX5_SET(modify_esw_vport_context_in, in, other_vport, other_vport);160	return mlx5_cmd_exec_in(dev, modify_esw_vport_context, in);161}162 163static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u16 vport,164				  u16 vlan, u8 qos, u8 set_flags)165{166	u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {};167 168	if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||169	    !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))170		return -EOPNOTSUPP;171 172	esw_debug(dev, "Set Vport[%d] VLAN %d qos %d set=%x\n",173		  vport, vlan, qos, set_flags);174 175	if (set_flags & SET_VLAN_STRIP)176		MLX5_SET(modify_esw_vport_context_in, in,177			 esw_vport_context.vport_cvlan_strip, 1);178 179	if (set_flags & SET_VLAN_INSERT) {180		if (MLX5_CAP_ESW(dev, vport_cvlan_insert_always)) {181			/* insert either if vlan exist in packet or not */182			MLX5_SET(modify_esw_vport_context_in, in,183				 esw_vport_context.vport_cvlan_insert,184				 MLX5_VPORT_CVLAN_INSERT_ALWAYS);185		} else {186			/* insert only if no vlan in packet */187			MLX5_SET(modify_esw_vport_context_in, in,188				 esw_vport_context.vport_cvlan_insert,189				 MLX5_VPORT_CVLAN_INSERT_WHEN_NO_CVLAN);190		}191		MLX5_SET(modify_esw_vport_context_in, in,192			 esw_vport_context.cvlan_pcp, qos);193		MLX5_SET(modify_esw_vport_context_in, in,194			 esw_vport_context.cvlan_id, vlan);195	}196 197	MLX5_SET(modify_esw_vport_context_in, in,198		 field_select.vport_cvlan_strip, 1);199	MLX5_SET(modify_esw_vport_context_in, in,200		 field_select.vport_cvlan_insert, 1);201 202	return mlx5_eswitch_modify_esw_vport_context(dev, vport, true, in);203}204 205/* E-Switch FDB */206static struct mlx5_flow_handle *207__esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u16 vport, bool rx_rule,208			 u8 mac_c[ETH_ALEN], u8 mac_v[ETH_ALEN])209{210	int match_header = (is_zero_ether_addr(mac_c) ? 0 :211			    MLX5_MATCH_OUTER_HEADERS);212	struct mlx5_flow_handle *flow_rule = NULL;213	struct mlx5_flow_act flow_act = {0};214	struct mlx5_flow_destination dest = {};215	struct mlx5_flow_spec *spec;216	void *mv_misc = NULL;217	void *mc_misc = NULL;218	u8 *dmac_v = NULL;219	u8 *dmac_c = NULL;220 221	if (rx_rule)222		match_header |= MLX5_MATCH_MISC_PARAMETERS;223 224	spec = kvzalloc(sizeof(*spec), GFP_KERNEL);225	if (!spec)226		return NULL;227 228	dmac_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,229			      outer_headers.dmac_47_16);230	dmac_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,231			      outer_headers.dmac_47_16);232 233	if (match_header & MLX5_MATCH_OUTER_HEADERS) {234		ether_addr_copy(dmac_v, mac_v);235		ether_addr_copy(dmac_c, mac_c);236	}237 238	if (match_header & MLX5_MATCH_MISC_PARAMETERS) {239		mv_misc  = MLX5_ADDR_OF(fte_match_param, spec->match_value,240					misc_parameters);241		mc_misc  = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,242					misc_parameters);243		MLX5_SET(fte_match_set_misc, mv_misc, source_port, MLX5_VPORT_UPLINK);244		MLX5_SET_TO_ONES(fte_match_set_misc, mc_misc, source_port);245	}246 247	dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;248	dest.vport.num = vport;249 250	esw_debug(esw->dev,251		  "\tFDB add rule dmac_v(%pM) dmac_c(%pM) -> vport(%d)\n",252		  dmac_v, dmac_c, vport);253	spec->match_criteria_enable = match_header;254	flow_act.action =  MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;255	flow_rule =256		mlx5_add_flow_rules(esw->fdb_table.legacy.fdb, spec,257				    &flow_act, &dest, 1);258	if (IS_ERR(flow_rule)) {259		esw_warn(esw->dev,260			 "FDB: Failed to add flow rule: dmac_v(%pM) dmac_c(%pM) -> vport(%d), err(%ld)\n",261			 dmac_v, dmac_c, vport, PTR_ERR(flow_rule));262		flow_rule = NULL;263	}264 265	kvfree(spec);266	return flow_rule;267}268 269static struct mlx5_flow_handle *270esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u8 mac[ETH_ALEN], u16 vport)271{272	u8 mac_c[ETH_ALEN];273 274	eth_broadcast_addr(mac_c);275	return __esw_fdb_set_vport_rule(esw, vport, false, mac_c, mac);276}277 278static struct mlx5_flow_handle *279esw_fdb_set_vport_allmulti_rule(struct mlx5_eswitch *esw, u16 vport)280{281	u8 mac_c[ETH_ALEN];282	u8 mac_v[ETH_ALEN];283 284	eth_zero_addr(mac_c);285	eth_zero_addr(mac_v);286	mac_c[0] = 0x01;287	mac_v[0] = 0x01;288	return __esw_fdb_set_vport_rule(esw, vport, false, mac_c, mac_v);289}290 291static struct mlx5_flow_handle *292esw_fdb_set_vport_promisc_rule(struct mlx5_eswitch *esw, u16 vport)293{294	u8 mac_c[ETH_ALEN];295	u8 mac_v[ETH_ALEN];296 297	eth_zero_addr(mac_c);298	eth_zero_addr(mac_v);299	return __esw_fdb_set_vport_rule(esw, vport, true, mac_c, mac_v);300}301 302/* E-Switch vport UC/MC lists management */303typedef int (*vport_addr_action)(struct mlx5_eswitch *esw,304				 struct vport_addr *vaddr);305 306static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)307{308	u8 *mac = vaddr->node.addr;309	u16 vport = vaddr->vport;310	int err;311 312	/* Skip mlx5_mpfs_add_mac for eswitch_managers,313	 * it is already done by its netdev in mlx5e_execute_l2_action314	 */315	if (mlx5_esw_is_manager_vport(esw, vport))316		goto fdb_add;317 318	err = mlx5_mpfs_add_mac(esw->dev, mac);319	if (err) {320		esw_warn(esw->dev,321			 "Failed to add L2 table mac(%pM) for vport(0x%x), err(%d)\n",322			 mac, vport, err);323		return err;324	}325	vaddr->mpfs = true;326 327fdb_add:328	/* SRIOV is enabled: Forward UC MAC to vport */329	if (esw->fdb_table.legacy.fdb && esw->mode == MLX5_ESWITCH_LEGACY) {330		vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);331 332		esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM fr(%p)\n",333			  vport, mac, vaddr->flow_rule);334	}335 336	return 0;337}338 339static int esw_del_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)340{341	u8 *mac = vaddr->node.addr;342	u16 vport = vaddr->vport;343	int err = 0;344 345	/* Skip mlx5_mpfs_del_mac for eswitch managers,346	 * it is already done by its netdev in mlx5e_execute_l2_action347	 */348	if (!vaddr->mpfs || mlx5_esw_is_manager_vport(esw, vport))349		goto fdb_del;350 351	err = mlx5_mpfs_del_mac(esw->dev, mac);352	if (err)353		esw_warn(esw->dev,354			 "Failed to del L2 table mac(%pM) for vport(%d), err(%d)\n",355			 mac, vport, err);356	vaddr->mpfs = false;357 358fdb_del:359	if (vaddr->flow_rule)360		mlx5_del_flow_rules(vaddr->flow_rule);361	vaddr->flow_rule = NULL;362 363	return 0;364}365 366static void update_allmulti_vports(struct mlx5_eswitch *esw,367				   struct vport_addr *vaddr,368				   struct esw_mc_addr *esw_mc)369{370	u8 *mac = vaddr->node.addr;371	struct mlx5_vport *vport;372	unsigned long i;373	u16 vport_num;374 375	mlx5_esw_for_each_vport(esw, i, vport) {376		struct hlist_head *vport_hash = vport->mc_list;377		struct vport_addr *iter_vaddr =378					l2addr_hash_find(vport_hash,379							 mac,380							 struct vport_addr);381		vport_num = vport->vport;382		if (IS_ERR_OR_NULL(vport->allmulti_rule) ||383		    vaddr->vport == vport_num)384			continue;385		switch (vaddr->action) {386		case MLX5_ACTION_ADD:387			if (iter_vaddr)388				continue;389			iter_vaddr = l2addr_hash_add(vport_hash, mac,390						     struct vport_addr,391						     GFP_KERNEL);392			if (!iter_vaddr) {393				esw_warn(esw->dev,394					 "ALL-MULTI: Failed to add MAC(%pM) to vport[%d] DB\n",395					 mac, vport_num);396				continue;397			}398			iter_vaddr->vport = vport_num;399			iter_vaddr->flow_rule =400					esw_fdb_set_vport_rule(esw,401							       mac,402							       vport_num);403			iter_vaddr->mc_promisc = true;404			break;405		case MLX5_ACTION_DEL:406			if (!iter_vaddr)407				continue;408			mlx5_del_flow_rules(iter_vaddr->flow_rule);409			l2addr_hash_del(iter_vaddr);410			break;411		}412	}413}414 415static int esw_add_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)416{417	struct hlist_head *hash = esw->mc_table;418	struct esw_mc_addr *esw_mc;419	u8 *mac = vaddr->node.addr;420	u16 vport = vaddr->vport;421 422	if (!esw->fdb_table.legacy.fdb)423		return 0;424 425	esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);426	if (esw_mc)427		goto add;428 429	esw_mc = l2addr_hash_add(hash, mac, struct esw_mc_addr, GFP_KERNEL);430	if (!esw_mc)431		return -ENOMEM;432 433	esw_mc->uplink_rule = /* Forward MC MAC to Uplink */434		esw_fdb_set_vport_rule(esw, mac, MLX5_VPORT_UPLINK);435 436	/* Add this multicast mac to all the mc promiscuous vports */437	update_allmulti_vports(esw, vaddr, esw_mc);438 439add:440	/* If the multicast mac is added as a result of mc promiscuous vport,441	 * don't increment the multicast ref count442	 */443	if (!vaddr->mc_promisc)444		esw_mc->refcnt++;445 446	/* Forward MC MAC to vport */447	vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);448	esw_debug(esw->dev,449		  "\tADDED MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",450		  vport, mac, vaddr->flow_rule,451		  esw_mc->refcnt, esw_mc->uplink_rule);452	return 0;453}454 455static int esw_del_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)456{457	struct hlist_head *hash = esw->mc_table;458	struct esw_mc_addr *esw_mc;459	u8 *mac = vaddr->node.addr;460	u16 vport = vaddr->vport;461 462	if (!esw->fdb_table.legacy.fdb)463		return 0;464 465	esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);466	if (!esw_mc) {467		esw_warn(esw->dev,468			 "Failed to find eswitch MC addr for MAC(%pM) vport(%d)",469			 mac, vport);470		return -EINVAL;471	}472	esw_debug(esw->dev,473		  "\tDELETE MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",474		  vport, mac, vaddr->flow_rule, esw_mc->refcnt,475		  esw_mc->uplink_rule);476 477	if (vaddr->flow_rule)478		mlx5_del_flow_rules(vaddr->flow_rule);479	vaddr->flow_rule = NULL;480 481	/* If the multicast mac is added as a result of mc promiscuous vport,482	 * don't decrement the multicast ref count.483	 */484	if (vaddr->mc_promisc || (--esw_mc->refcnt > 0))485		return 0;486 487	/* Remove this multicast mac from all the mc promiscuous vports */488	update_allmulti_vports(esw, vaddr, esw_mc);489 490	if (esw_mc->uplink_rule)491		mlx5_del_flow_rules(esw_mc->uplink_rule);492 493	l2addr_hash_del(esw_mc);494	return 0;495}496 497/* Apply vport UC/MC list to HW l2 table and FDB table */498static void esw_apply_vport_addr_list(struct mlx5_eswitch *esw,499				      struct mlx5_vport *vport, int list_type)500{501	bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;502	vport_addr_action vport_addr_add;503	vport_addr_action vport_addr_del;504	struct vport_addr *addr;505	struct l2addr_node *node;506	struct hlist_head *hash;507	struct hlist_node *tmp;508	int hi;509 510	vport_addr_add = is_uc ? esw_add_uc_addr :511				 esw_add_mc_addr;512	vport_addr_del = is_uc ? esw_del_uc_addr :513				 esw_del_mc_addr;514 515	hash = is_uc ? vport->uc_list : vport->mc_list;516	for_each_l2hash_node(node, tmp, hash, hi) {517		addr = container_of(node, struct vport_addr, node);518		switch (addr->action) {519		case MLX5_ACTION_ADD:520			vport_addr_add(esw, addr);521			addr->action = MLX5_ACTION_NONE;522			break;523		case MLX5_ACTION_DEL:524			vport_addr_del(esw, addr);525			l2addr_hash_del(addr);526			break;527		}528	}529}530 531/* Sync vport UC/MC list from vport context */532static void esw_update_vport_addr_list(struct mlx5_eswitch *esw,533				       struct mlx5_vport *vport, int list_type)534{535	bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;536	u8 (*mac_list)[ETH_ALEN];537	struct l2addr_node *node;538	struct vport_addr *addr;539	struct hlist_head *hash;540	struct hlist_node *tmp;541	int size;542	int err;543	int hi;544	int i;545 546	size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) :547		       MLX5_MAX_MC_PER_VPORT(esw->dev);548 549	mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL);550	if (!mac_list)551		return;552 553	hash = is_uc ? vport->uc_list : vport->mc_list;554 555	for_each_l2hash_node(node, tmp, hash, hi) {556		addr = container_of(node, struct vport_addr, node);557		addr->action = MLX5_ACTION_DEL;558	}559 560	if (!vport->enabled)561		goto out;562 563	err = mlx5_query_nic_vport_mac_list(esw->dev, vport->vport, list_type,564					    mac_list, &size);565	if (err)566		goto out;567	esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n",568		  vport->vport, is_uc ? "UC" : "MC", size);569 570	for (i = 0; i < size; i++) {571		if (is_uc && !is_valid_ether_addr(mac_list[i]))572			continue;573 574		if (!is_uc && !is_multicast_ether_addr(mac_list[i]))575			continue;576 577		addr = l2addr_hash_find(hash, mac_list[i], struct vport_addr);578		if (addr) {579			addr->action = MLX5_ACTION_NONE;580			/* If this mac was previously added because of allmulti581			 * promiscuous rx mode, its now converted to be original582			 * vport mac.583			 */584			if (addr->mc_promisc) {585				struct esw_mc_addr *esw_mc =586					l2addr_hash_find(esw->mc_table,587							 mac_list[i],588							 struct esw_mc_addr);589				if (!esw_mc) {590					esw_warn(esw->dev,591						 "Failed to MAC(%pM) in mcast DB\n",592						 mac_list[i]);593					continue;594				}595				esw_mc->refcnt++;596				addr->mc_promisc = false;597			}598			continue;599		}600 601		addr = l2addr_hash_add(hash, mac_list[i], struct vport_addr,602				       GFP_KERNEL);603		if (!addr) {604			esw_warn(esw->dev,605				 "Failed to add MAC(%pM) to vport[%d] DB\n",606				 mac_list[i], vport->vport);607			continue;608		}609		addr->vport = vport->vport;610		addr->action = MLX5_ACTION_ADD;611	}612out:613	kfree(mac_list);614}615 616/* Sync vport UC/MC list from vport context617 * Must be called after esw_update_vport_addr_list618 */619static void esw_update_vport_mc_promisc(struct mlx5_eswitch *esw,620					struct mlx5_vport *vport)621{622	struct l2addr_node *node;623	struct vport_addr *addr;624	struct hlist_head *hash;625	struct hlist_node *tmp;626	int hi;627 628	hash = vport->mc_list;629 630	for_each_l2hash_node(node, tmp, esw->mc_table, hi) {631		u8 *mac = node->addr;632 633		addr = l2addr_hash_find(hash, mac, struct vport_addr);634		if (addr) {635			if (addr->action == MLX5_ACTION_DEL)636				addr->action = MLX5_ACTION_NONE;637			continue;638		}639		addr = l2addr_hash_add(hash, mac, struct vport_addr,640				       GFP_KERNEL);641		if (!addr) {642			esw_warn(esw->dev,643				 "Failed to add allmulti MAC(%pM) to vport[%d] DB\n",644				 mac, vport->vport);645			continue;646		}647		addr->vport = vport->vport;648		addr->action = MLX5_ACTION_ADD;649		addr->mc_promisc = true;650	}651}652 653/* Apply vport rx mode to HW FDB table */654static void esw_apply_vport_rx_mode(struct mlx5_eswitch *esw,655				    struct mlx5_vport *vport,656				    bool promisc, bool mc_promisc)657{658	struct esw_mc_addr *allmulti_addr = &esw->mc_promisc;659 660	if (IS_ERR_OR_NULL(vport->allmulti_rule) != mc_promisc)661		goto promisc;662 663	if (mc_promisc) {664		vport->allmulti_rule =665			esw_fdb_set_vport_allmulti_rule(esw, vport->vport);666		if (!allmulti_addr->uplink_rule)667			allmulti_addr->uplink_rule =668				esw_fdb_set_vport_allmulti_rule(esw,669								MLX5_VPORT_UPLINK);670		allmulti_addr->refcnt++;671	} else if (vport->allmulti_rule) {672		mlx5_del_flow_rules(vport->allmulti_rule);673		vport->allmulti_rule = NULL;674 675		if (--allmulti_addr->refcnt > 0)676			goto promisc;677 678		if (allmulti_addr->uplink_rule)679			mlx5_del_flow_rules(allmulti_addr->uplink_rule);680		allmulti_addr->uplink_rule = NULL;681	}682 683promisc:684	if (IS_ERR_OR_NULL(vport->promisc_rule) != promisc)685		return;686 687	if (promisc) {688		vport->promisc_rule =689			esw_fdb_set_vport_promisc_rule(esw, vport->vport);690	} else if (vport->promisc_rule) {691		mlx5_del_flow_rules(vport->promisc_rule);692		vport->promisc_rule = NULL;693	}694}695 696/* Sync vport rx mode from vport context */697static void esw_update_vport_rx_mode(struct mlx5_eswitch *esw,698				     struct mlx5_vport *vport)699{700	int promisc_all = 0;701	int promisc_uc = 0;702	int promisc_mc = 0;703	int err;704 705	err = mlx5_query_nic_vport_promisc(esw->dev,706					   vport->vport,707					   &promisc_uc,708					   &promisc_mc,709					   &promisc_all);710	if (err)711		return;712	esw_debug(esw->dev, "vport[%d] context update rx mode promisc_all=%d, all_multi=%d\n",713		  vport->vport, promisc_all, promisc_mc);714 715	if (!vport->info.trusted || !vport->enabled) {716		promisc_uc = 0;717		promisc_mc = 0;718		promisc_all = 0;719	}720 721	esw_apply_vport_rx_mode(esw, vport, promisc_all,722				(promisc_all || promisc_mc));723}724 725void esw_vport_change_handle_locked(struct mlx5_vport *vport)726{727	struct mlx5_core_dev *dev = vport->dev;728	struct mlx5_eswitch *esw = dev->priv.eswitch;729	u8 mac[ETH_ALEN];730 731	if (!MLX5_CAP_GEN(dev, log_max_l2_table))732		return;733 734	mlx5_query_nic_vport_mac_address(dev, vport->vport, true, mac);735	esw_debug(dev, "vport[%d] Context Changed: perm mac: %pM\n",736		  vport->vport, mac);737 738	if (vport->enabled_events & MLX5_VPORT_UC_ADDR_CHANGE) {739		esw_update_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_UC);740		esw_apply_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_UC);741	}742 743	if (vport->enabled_events & MLX5_VPORT_MC_ADDR_CHANGE)744		esw_update_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_MC);745 746	if (vport->enabled_events & MLX5_VPORT_PROMISC_CHANGE) {747		esw_update_vport_rx_mode(esw, vport);748		if (!IS_ERR_OR_NULL(vport->allmulti_rule))749			esw_update_vport_mc_promisc(esw, vport);750	}751 752	if (vport->enabled_events & (MLX5_VPORT_PROMISC_CHANGE | MLX5_VPORT_MC_ADDR_CHANGE))753		esw_apply_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_MC);754 755	esw_debug(esw->dev, "vport[%d] Context Changed: Done\n", vport->vport);756	if (vport->enabled)757		arm_vport_context_events_cmd(dev, vport->vport,758					     vport->enabled_events);759}760 761static void esw_vport_change_handler(struct work_struct *work)762{763	struct mlx5_vport *vport =764		container_of(work, struct mlx5_vport, vport_change_handler);765	struct mlx5_eswitch *esw = vport->dev->priv.eswitch;766 767	mutex_lock(&esw->state_lock);768	esw_vport_change_handle_locked(vport);769	mutex_unlock(&esw->state_lock);770}771 772static void node_guid_gen_from_mac(u64 *node_guid, const u8 *mac)773{774	((u8 *)node_guid)[7] = mac[0];775	((u8 *)node_guid)[6] = mac[1];776	((u8 *)node_guid)[5] = mac[2];777	((u8 *)node_guid)[4] = 0xff;778	((u8 *)node_guid)[3] = 0xfe;779	((u8 *)node_guid)[2] = mac[3];780	((u8 *)node_guid)[1] = mac[4];781	((u8 *)node_guid)[0] = mac[5];782}783 784static int esw_vport_setup_acl(struct mlx5_eswitch *esw,785			       struct mlx5_vport *vport)786{787	if (esw->mode == MLX5_ESWITCH_LEGACY)788		return esw_legacy_vport_acl_setup(esw, vport);789	else790		return esw_vport_create_offloads_acl_tables(esw, vport);791}792 793static void esw_vport_cleanup_acl(struct mlx5_eswitch *esw,794				  struct mlx5_vport *vport)795{796	if (esw->mode == MLX5_ESWITCH_LEGACY)797		esw_legacy_vport_acl_cleanup(esw, vport);798	else799		esw_vport_destroy_offloads_acl_tables(esw, vport);800}801 802static int mlx5_esw_vport_caps_get(struct mlx5_eswitch *esw, struct mlx5_vport *vport)803{804	int query_out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);805	void *query_ctx;806	void *hca_caps;807	int err;808 809	if (!MLX5_CAP_GEN(esw->dev, vhca_resource_manager))810		return 0;811 812	query_ctx = kzalloc(query_out_sz, GFP_KERNEL);813	if (!query_ctx)814		return -ENOMEM;815 816	err = mlx5_vport_get_other_func_cap(esw->dev, vport->vport, query_ctx,817					    MLX5_CAP_GENERAL);818	if (err)819		goto out_free;820 821	hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);822	vport->info.roce_enabled = MLX5_GET(cmd_hca_cap, hca_caps, roce);823 824	if (!MLX5_CAP_GEN_MAX(esw->dev, hca_cap_2))825		goto out_free;826 827	memset(query_ctx, 0, query_out_sz);828	err = mlx5_vport_get_other_func_cap(esw->dev, vport->vport, query_ctx,829					    MLX5_CAP_GENERAL_2);830	if (err)831		goto out_free;832 833	hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);834	vport->info.mig_enabled = MLX5_GET(cmd_hca_cap_2, hca_caps, migratable);835 836	err = mlx5_esw_ipsec_vf_offload_get(esw->dev, vport);837out_free:838	kfree(query_ctx);839	return err;840}841 842static int esw_vport_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport)843{844	bool vst_mode_steering = esw_vst_mode_is_steering(esw);845	u16 vport_num = vport->vport;846	int flags;847	int err;848 849	err = esw_vport_setup_acl(esw, vport);850	if (err)851		return err;852 853	if (mlx5_esw_is_manager_vport(esw, vport_num))854		return 0;855 856	err = mlx5_esw_vport_caps_get(esw, vport);857	if (err)858		goto err_caps;859 860	mlx5_modify_vport_admin_state(esw->dev,861				      MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,862				      vport_num, 1,863				      vport->info.link_state);864 865	/* Host PF has its own mac/guid. */866	if (vport_num) {867		mlx5_modify_nic_vport_mac_address(esw->dev, vport_num,868						  vport->info.mac);869		mlx5_modify_nic_vport_node_guid(esw->dev, vport_num,870						vport->info.node_guid);871	}872 873	flags = (vport->info.vlan || vport->info.qos) ?874		SET_VLAN_STRIP | SET_VLAN_INSERT : 0;875	if (esw->mode == MLX5_ESWITCH_OFFLOADS || !vst_mode_steering)876		modify_esw_vport_cvlan(esw->dev, vport_num, vport->info.vlan,877				       vport->info.qos, flags);878 879	return 0;880 881err_caps:882	esw_vport_cleanup_acl(esw, vport);883	return err;884}885 886/* Don't cleanup vport->info, it's needed to restore vport configuration */887static void esw_vport_cleanup(struct mlx5_eswitch *esw, struct mlx5_vport *vport)888{889	u16 vport_num = vport->vport;890 891	if (!mlx5_esw_is_manager_vport(esw, vport_num))892		mlx5_modify_vport_admin_state(esw->dev,893					      MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,894					      vport_num, 1,895					      MLX5_VPORT_ADMIN_STATE_DOWN);896 897	mlx5_esw_qos_vport_disable(esw, vport);898	esw_vport_cleanup_acl(esw, vport);899}900 901int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, struct mlx5_vport *vport,902			  enum mlx5_eswitch_vport_event enabled_events)903{904	u16 vport_num = vport->vport;905	int ret;906 907	mutex_lock(&esw->state_lock);908	WARN_ON(vport->enabled);909 910	esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num);911 912	ret = esw_vport_setup(esw, vport);913	if (ret)914		goto done;915 916	/* Sync with current vport context */917	vport->enabled_events = enabled_events;918	vport->enabled = true;919	if (vport->vport != MLX5_VPORT_PF &&920	    (vport->info.ipsec_crypto_enabled || vport->info.ipsec_packet_enabled))921		esw->enabled_ipsec_vf_count++;922 923	/* Esw manager is trusted by default. Host PF (vport 0) is trusted as well924	 * in smartNIC as it's a vport group manager.925	 */926	if (mlx5_esw_is_manager_vport(esw, vport_num) ||927	    (!vport_num && mlx5_core_is_ecpf(esw->dev)))928		vport->info.trusted = true;929 930	if (!mlx5_esw_is_manager_vport(esw, vport_num) &&931	    MLX5_CAP_GEN(esw->dev, vhca_resource_manager)) {932		ret = mlx5_esw_vport_vhca_id_set(esw, vport_num);933		if (ret)934			goto err_vhca_mapping;935	}936 937	/* External controller host PF has factory programmed MAC.938	 * Read it from the device.939	 */940	if (mlx5_core_is_ecpf(esw->dev) && vport_num == MLX5_VPORT_PF)941		mlx5_query_nic_vport_mac_address(esw->dev, vport_num, true, vport->info.mac);942 943	esw_vport_change_handle_locked(vport);944 945	esw->enabled_vports++;946	esw_debug(esw->dev, "Enabled VPORT(%d)\n", vport_num);947done:948	mutex_unlock(&esw->state_lock);949	return ret;950 951err_vhca_mapping:952	esw_vport_cleanup(esw, vport);953	mutex_unlock(&esw->state_lock);954	return ret;955}956 957void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vport)958{959	u16 vport_num = vport->vport;960 961	mutex_lock(&esw->state_lock);962 963	if (!vport->enabled)964		goto done;965 966	esw_debug(esw->dev, "Disabling vport(%d)\n", vport_num);967	/* Mark this vport as disabled to discard new events */968	vport->enabled = false;969 970	/* Disable events from this vport */971	if (MLX5_CAP_GEN(esw->dev, log_max_l2_table))972		arm_vport_context_events_cmd(esw->dev, vport_num, 0);973 974	if (!mlx5_esw_is_manager_vport(esw, vport_num) &&975	    MLX5_CAP_GEN(esw->dev, vhca_resource_manager))976		mlx5_esw_vport_vhca_id_clear(esw, vport_num);977 978	if (vport->vport != MLX5_VPORT_PF &&979	    (vport->info.ipsec_crypto_enabled || vport->info.ipsec_packet_enabled))980		esw->enabled_ipsec_vf_count--;981 982	/* We don't assume VFs will cleanup after themselves.983	 * Calling vport change handler while vport is disabled will cleanup984	 * the vport resources.985	 */986	esw_vport_change_handle_locked(vport);987	vport->enabled_events = 0;988	esw_apply_vport_rx_mode(esw, vport, false, false);989	esw_vport_cleanup(esw, vport);990	esw->enabled_vports--;991 992done:993	mutex_unlock(&esw->state_lock);994}995 996static int eswitch_vport_event(struct notifier_block *nb,997			       unsigned long type, void *data)998{999	struct mlx5_eswitch *esw = mlx5_nb_cof(nb, struct mlx5_eswitch, nb);1000	struct mlx5_eqe *eqe = data;1001	struct mlx5_vport *vport;1002	u16 vport_num;1003 1004	vport_num = be16_to_cpu(eqe->data.vport_change.vport_num);1005	vport = mlx5_eswitch_get_vport(esw, vport_num);1006	if (!IS_ERR(vport))1007		queue_work(esw->work_queue, &vport->vport_change_handler);1008	return NOTIFY_OK;1009}1010 1011/**1012 * mlx5_esw_query_functions - Returns raw output about functions state1013 * @dev:	Pointer to device to query1014 *1015 * mlx5_esw_query_functions() allocates and returns functions changed1016 * raw output memory pointer from device on success. Otherwise returns ERR_PTR.1017 * Caller must free the memory using kvfree() when valid pointer is returned.1018 */1019const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev)1020{1021	int outlen = MLX5_ST_SZ_BYTES(query_esw_functions_out);1022	u32 in[MLX5_ST_SZ_DW(query_esw_functions_in)] = {};1023	u32 *out;1024	int err;1025 1026	out = kvzalloc(outlen, GFP_KERNEL);1027	if (!out)1028		return ERR_PTR(-ENOMEM);1029 1030	MLX5_SET(query_esw_functions_in, in, opcode,1031		 MLX5_CMD_OP_QUERY_ESW_FUNCTIONS);1032 1033	err = mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);1034	if (!err)1035		return out;1036 1037	kvfree(out);1038	return ERR_PTR(err);1039}1040 1041static void mlx5_eswitch_event_handler_register(struct mlx5_eswitch *esw)1042{1043	if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev)) {1044		MLX5_NB_INIT(&esw->esw_funcs.nb, mlx5_esw_funcs_changed_handler,1045			     ESW_FUNCTIONS_CHANGED);1046		mlx5_eq_notifier_register(esw->dev, &esw->esw_funcs.nb);1047	}1048}1049 1050static void mlx5_eswitch_event_handler_unregister(struct mlx5_eswitch *esw)1051{1052	if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev))1053		mlx5_eq_notifier_unregister(esw->dev, &esw->esw_funcs.nb);1054 1055	flush_workqueue(esw->work_queue);1056}1057 1058static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch *esw)1059{1060	struct mlx5_vport *vport;1061	unsigned long i;1062 1063	mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) {1064		memset(&vport->qos, 0, sizeof(vport->qos));1065		memset(&vport->info, 0, sizeof(vport->info));1066		vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO;1067	}1068}1069 1070static void mlx5_eswitch_clear_ec_vf_vports_info(struct mlx5_eswitch *esw)1071{1072	struct mlx5_vport *vport;1073	unsigned long i;1074 1075	mlx5_esw_for_each_ec_vf_vport(esw, i, vport, esw->esw_funcs.num_ec_vfs) {1076		memset(&vport->qos, 0, sizeof(vport->qos));1077		memset(&vport->info, 0, sizeof(vport->info));1078		vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO;1079	}1080}1081 1082static int mlx5_eswitch_load_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport,1083				   enum mlx5_eswitch_vport_event enabled_events)1084{1085	int err;1086 1087	err = mlx5_esw_vport_enable(esw, vport, enabled_events);1088	if (err)1089		return err;1090 1091	err = mlx5_esw_offloads_load_rep(esw, vport);1092	if (err)1093		goto err_rep;1094 1095	return err;1096 1097err_rep:1098	mlx5_esw_vport_disable(esw, vport);1099	return err;1100}1101 1102static void mlx5_eswitch_unload_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport)1103{1104	mlx5_esw_offloads_unload_rep(esw, vport);1105	mlx5_esw_vport_disable(esw, vport);1106}1107 1108static int mlx5_eswitch_load_pf_vf_vport(struct mlx5_eswitch *esw, u16 vport_num,1109					 enum mlx5_eswitch_vport_event enabled_events)1110{1111	struct mlx5_vport *vport;1112	int err;1113 1114	vport = mlx5_eswitch_get_vport(esw, vport_num);1115	if (IS_ERR(vport))1116		return PTR_ERR(vport);1117 1118	err = mlx5_esw_offloads_init_pf_vf_rep(esw, vport);1119	if (err)1120		return err;1121 1122	err = mlx5_eswitch_load_vport(esw, vport, enabled_events);1123	if (err)1124		goto err_load;1125	return 0;1126 1127err_load:1128	mlx5_esw_offloads_cleanup_pf_vf_rep(esw, vport);1129	return err;1130}1131 1132static void mlx5_eswitch_unload_pf_vf_vport(struct mlx5_eswitch *esw, u16 vport_num)1133{1134	struct mlx5_vport *vport;1135 1136	vport = mlx5_eswitch_get_vport(esw, vport_num);1137	if (IS_ERR(vport))1138		return;1139 1140	mlx5_eswitch_unload_vport(esw, vport);1141	mlx5_esw_offloads_cleanup_pf_vf_rep(esw, vport);1142}1143 1144int mlx5_eswitch_load_sf_vport(struct mlx5_eswitch *esw, u16 vport_num,1145			       enum mlx5_eswitch_vport_event enabled_events,1146			       struct mlx5_devlink_port *dl_port, u32 controller, u32 sfnum)1147{1148	struct mlx5_vport *vport;1149	int err;1150 1151	vport = mlx5_eswitch_get_vport(esw, vport_num);1152	if (IS_ERR(vport))1153		return PTR_ERR(vport);1154 1155	err = mlx5_esw_offloads_init_sf_rep(esw, vport, dl_port, controller, sfnum);1156	if (err)1157		return err;1158 1159	err = mlx5_eswitch_load_vport(esw, vport, enabled_events);1160	if (err)1161		goto err_load;1162 1163	return 0;1164 1165err_load:1166	mlx5_esw_offloads_cleanup_sf_rep(esw, vport);1167	return err;1168}1169 1170void mlx5_eswitch_unload_sf_vport(struct mlx5_eswitch *esw, u16 vport_num)1171{1172	struct mlx5_vport *vport;1173 1174	vport = mlx5_eswitch_get_vport(esw, vport_num);1175	if (IS_ERR(vport))1176		return;1177 1178	mlx5_eswitch_unload_vport(esw, vport);1179	mlx5_esw_offloads_cleanup_sf_rep(esw, vport);1180}1181 1182void mlx5_eswitch_unload_vf_vports(struct mlx5_eswitch *esw, u16 num_vfs)1183{1184	struct mlx5_vport *vport;1185	unsigned long i;1186 1187	mlx5_esw_for_each_vf_vport(esw, i, vport, num_vfs) {1188		if (!vport->enabled)1189			continue;1190		mlx5_eswitch_unload_pf_vf_vport(esw, vport->vport);1191	}1192}1193 1194static void mlx5_eswitch_unload_ec_vf_vports(struct mlx5_eswitch *esw,1195					     u16 num_ec_vfs)1196{1197	struct mlx5_vport *vport;1198	unsigned long i;1199 1200	mlx5_esw_for_each_ec_vf_vport(esw, i, vport, num_ec_vfs) {1201		if (!vport->enabled)1202			continue;1203		mlx5_eswitch_unload_pf_vf_vport(esw, vport->vport);1204	}1205}1206 1207int mlx5_eswitch_load_vf_vports(struct mlx5_eswitch *esw, u16 num_vfs,1208				enum mlx5_eswitch_vport_event enabled_events)1209{1210	struct mlx5_vport *vport;1211	unsigned long i;1212	int err;1213 1214	mlx5_esw_for_each_vf_vport(esw, i, vport, num_vfs) {1215		err = mlx5_eswitch_load_pf_vf_vport(esw, vport->vport, enabled_events);1216		if (err)1217			goto vf_err;1218	}1219 1220	return 0;1221 1222vf_err:1223	mlx5_eswitch_unload_vf_vports(esw, num_vfs);1224	return err;1225}1226 1227static int mlx5_eswitch_load_ec_vf_vports(struct mlx5_eswitch *esw, u16 num_ec_vfs,1228					  enum mlx5_eswitch_vport_event enabled_events)1229{1230	struct mlx5_vport *vport;1231	unsigned long i;1232	int err;1233 1234	mlx5_esw_for_each_ec_vf_vport(esw, i, vport, num_ec_vfs) {1235		err = mlx5_eswitch_load_pf_vf_vport(esw, vport->vport, enabled_events);1236		if (err)1237			goto vf_err;1238	}1239 1240	return 0;1241 1242vf_err:1243	mlx5_eswitch_unload_ec_vf_vports(esw, num_ec_vfs);1244	return err;1245}1246 1247static int host_pf_enable_hca(struct mlx5_core_dev *dev)1248{1249	if (!mlx5_core_is_ecpf(dev))1250		return 0;1251 1252	/* Once vport and representor are ready, take out the external host PF1253	 * out of initializing state. Enabling HCA clears the iser->initializing1254	 * bit and host PF driver loading can progress.1255	 */1256	return mlx5_cmd_host_pf_enable_hca(dev);1257}1258 1259static void host_pf_disable_hca(struct mlx5_core_dev *dev)1260{1261	if (!mlx5_core_is_ecpf(dev))1262		return;1263 1264	mlx5_cmd_host_pf_disable_hca(dev);1265}1266 1267/* mlx5_eswitch_enable_pf_vf_vports() enables vports of PF, ECPF and VFs1268 * whichever are present on the eswitch.1269 */1270int1271mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw,1272				 enum mlx5_eswitch_vport_event enabled_events)1273{1274	bool pf_needed;1275	int ret;1276 1277	pf_needed = mlx5_core_is_ecpf_esw_manager(esw->dev) ||1278		    esw->mode == MLX5_ESWITCH_LEGACY;1279 1280	/* Enable PF vport */1281	if (pf_needed) {1282		ret = mlx5_eswitch_load_pf_vf_vport(esw, MLX5_VPORT_PF,1283						    enabled_events);1284		if (ret)1285			return ret;1286	}1287 1288	/* Enable external host PF HCA */1289	ret = host_pf_enable_hca(esw->dev);1290	if (ret)1291		goto pf_hca_err;1292 1293	/* Enable ECPF vport */1294	if (mlx5_ecpf_vport_exists(esw->dev)) {1295		ret = mlx5_eswitch_load_pf_vf_vport(esw, MLX5_VPORT_ECPF, enabled_events);1296		if (ret)1297			goto ecpf_err;1298		if (mlx5_core_ec_sriov_enabled(esw->dev)) {1299			ret = mlx5_eswitch_load_ec_vf_vports(esw, esw->esw_funcs.num_ec_vfs,1300							     enabled_events);1301			if (ret)1302				goto ec_vf_err;1303		}1304	}1305 1306	/* Enable VF vports */1307	ret = mlx5_eswitch_load_vf_vports(esw, esw->esw_funcs.num_vfs,1308					  enabled_events);1309	if (ret)1310		goto vf_err;1311	return 0;1312 1313vf_err:1314	if (mlx5_core_ec_sriov_enabled(esw->dev))1315		mlx5_eswitch_unload_ec_vf_vports(esw, esw->esw_funcs.num_ec_vfs);1316ec_vf_err:1317	if (mlx5_ecpf_vport_exists(esw->dev))1318		mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_ECPF);1319ecpf_err:1320	host_pf_disable_hca(esw->dev);1321pf_hca_err:1322	if (pf_needed)1323		mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_PF);1324	return ret;1325}1326 1327/* mlx5_eswitch_disable_pf_vf_vports() disables vports of PF, ECPF and VFs1328 * whichever are previously enabled on the eswitch.1329 */1330void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw)1331{1332	mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs);1333 1334	if (mlx5_ecpf_vport_exists(esw->dev)) {1335		if (mlx5_core_ec_sriov_enabled(esw->dev))1336			mlx5_eswitch_unload_ec_vf_vports(esw, esw->esw_funcs.num_vfs);1337		mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_ECPF);1338	}1339 1340	host_pf_disable_hca(esw->dev);1341 1342	if (mlx5_core_is_ecpf_esw_manager(esw->dev) ||1343	    esw->mode == MLX5_ESWITCH_LEGACY)1344		mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_PF);1345}1346 1347static void mlx5_eswitch_get_devlink_param(struct mlx5_eswitch *esw)1348{1349	struct devlink *devlink = priv_to_devlink(esw->dev);1350	union devlink_param_value val;1351	int err;1352 1353	err = devl_param_driverinit_value_get(devlink,1354					      MLX5_DEVLINK_PARAM_ID_ESW_LARGE_GROUP_NUM,1355					      &val);1356	if (!err) {1357		esw->params.large_group_num = val.vu32;1358	} else {1359		esw_warn(esw->dev,1360			 "Devlink can't get param fdb_large_groups, uses default (%d).\n",1361			 ESW_OFFLOADS_DEFAULT_NUM_GROUPS);1362		esw->params.large_group_num = ESW_OFFLOADS_DEFAULT_NUM_GROUPS;1363	}1364}1365 1366static void1367mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, int num_vfs)1368{1369	const u32 *out;1370 1371	if (num_vfs < 0)1372		return;1373 1374	if (!mlx5_core_is_ecpf_esw_manager(esw->dev)) {1375		esw->esw_funcs.num_vfs = num_vfs;1376		return;1377	}1378 1379	out = mlx5_esw_query_functions(esw->dev);1380	if (IS_ERR(out))1381		return;1382 1383	esw->esw_funcs.num_vfs = MLX5_GET(query_esw_functions_out, out,1384					  host_params_context.host_num_of_vfs);1385	if (mlx5_core_ec_sriov_enabled(esw->dev))1386		esw->esw_funcs.num_ec_vfs = num_vfs;1387 1388	kvfree(out);1389}1390 1391static void mlx5_esw_mode_change_notify(struct mlx5_eswitch *esw, u16 mode)1392{1393	struct mlx5_esw_event_info info = {};1394 1395	info.new_mode = mode;1396 1397	blocking_notifier_call_chain(&esw->n_head, 0, &info);1398}1399 1400static int mlx5_esw_acls_ns_init(struct mlx5_eswitch *esw)1401{1402	struct mlx5_core_dev *dev = esw->dev;1403	int total_vports;1404	int err;1405 1406	if (esw->flags & MLX5_ESWITCH_VPORT_ACL_NS_CREATED)1407		return 0;1408 1409	total_vports = mlx5_eswitch_get_total_vports(dev);1410 1411	if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support)) {1412		err = mlx5_fs_egress_acls_init(dev, total_vports);1413		if (err)1414			return err;1415	} else {1416		esw_warn(dev, "egress ACL is not supported by FW\n");1417	}1418 1419	if (MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support)) {1420		err = mlx5_fs_ingress_acls_init(dev, total_vports);1421		if (err)1422			goto err;1423	} else {1424		esw_warn(dev, "ingress ACL is not supported by FW\n");1425	}1426	esw->flags |= MLX5_ESWITCH_VPORT_ACL_NS_CREATED;1427	return 0;1428 1429err:1430	if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support))1431		mlx5_fs_egress_acls_cleanup(dev);1432	return err;1433}1434 1435static void mlx5_esw_acls_ns_cleanup(struct mlx5_eswitch *esw)1436{1437	struct mlx5_core_dev *dev = esw->dev;1438 1439	esw->flags &= ~MLX5_ESWITCH_VPORT_ACL_NS_CREATED;1440	if (MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support))1441		mlx5_fs_ingress_acls_cleanup(dev);1442	if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support))1443		mlx5_fs_egress_acls_cleanup(dev);1444}1445 1446/**1447 * mlx5_eswitch_enable_locked - Enable eswitch1448 * @esw:	Pointer to eswitch1449 * @num_vfs:	Enable eswitch for given number of VFs. This is optional.1450 *		Valid value are 0, > 0 and MLX5_ESWITCH_IGNORE_NUM_VFS.1451 *		Caller should pass num_vfs > 0 when enabling eswitch for1452 *		vf vports. Caller should pass num_vfs = 0, when eswitch1453 *		is enabled without sriov VFs or when caller1454 *		is unaware of the sriov state of the host PF on ECPF based1455 *		eswitch. Caller should pass < 0 when num_vfs should be1456 *		completely ignored. This is typically the case when eswitch1457 *		is enabled without sriov regardless of PF/ECPF system.1458 * mlx5_eswitch_enable_locked() Enables eswitch in either legacy or offloads1459 * mode. If num_vfs >=0 is provided, it setup VF related eswitch vports.1460 * It returns 0 on success or error code on failure.1461 */1462int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs)1463{1464	int err;1465 1466	devl_assert_locked(priv_to_devlink(esw->dev));1467 1468	if (!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) {1469		esw_warn(esw->dev, "FDB is not supported, aborting ...\n");1470		return -EOPNOTSUPP;1471	}1472 1473	mlx5_eswitch_get_devlink_param(esw);1474 1475	err = mlx5_esw_acls_ns_init(esw);1476	if (err)1477		return err;1478 1479	mlx5_eswitch_update_num_of_vfs(esw, num_vfs);1480 1481	MLX5_NB_INIT(&esw->nb, eswitch_vport_event, NIC_VPORT_CHANGE);1482	mlx5_eq_notifier_register(esw->dev, &esw->nb);1483 1484	if (esw->mode == MLX5_ESWITCH_LEGACY) {1485		err = esw_legacy_enable(esw);1486	} else {1487		mlx5_rescan_drivers(esw->dev);1488		err = esw_offloads_enable(esw);1489	}1490 1491	if (err)1492		goto err_esw_enable;1493 1494	esw->fdb_table.flags |= MLX5_ESW_FDB_CREATED;1495 1496	mlx5_eswitch_event_handler_register(esw);1497 1498	esw_info(esw->dev, "Enable: mode(%s), nvfs(%d), necvfs(%d), active vports(%d)\n",1499		 esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",1500		 esw->esw_funcs.num_vfs, esw->esw_funcs.num_ec_vfs, esw->enabled_vports);1501 1502	mlx5_esw_mode_change_notify(esw, esw->mode);1503 1504	return 0;1505 1506err_esw_enable:1507	mlx5_eq_notifier_unregister(esw->dev, &esw->nb);1508	mlx5_esw_acls_ns_cleanup(esw);1509	return err;1510}1511 1512/**1513 * mlx5_eswitch_enable - Enable eswitch1514 * @esw:	Pointer to eswitch1515 * @num_vfs:	Enable eswitch switch for given number of VFs.1516 *		Caller must pass num_vfs > 0 when enabling eswitch for1517 *		vf vports.1518 * mlx5_eswitch_enable() returns 0 on success or error code on failure.1519 */1520int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs)1521{1522	bool toggle_lag;1523	int ret = 0;1524 1525	if (!mlx5_esw_allowed(esw))1526		return 0;1527 1528	devl_assert_locked(priv_to_devlink(esw->dev));1529 1530	toggle_lag = !mlx5_esw_is_fdb_created(esw);1531 1532	if (toggle_lag)1533		mlx5_lag_disable_change(esw->dev);1534 1535	if (!mlx5_esw_is_fdb_created(esw)) {1536		ret = mlx5_eswitch_enable_locked(esw, num_vfs);1537	} else {1538		enum mlx5_eswitch_vport_event vport_events;1539 1540		vport_events = (esw->mode == MLX5_ESWITCH_LEGACY) ?1541					MLX5_LEGACY_SRIOV_VPORT_EVENTS : MLX5_VPORT_UC_ADDR_CHANGE;1542		/* If this is the ECPF the number of host VFs is managed via the1543		 * eswitch function change event handler, and any num_vfs provided1544		 * here are intended to be EC VFs.1545		 */1546		if (!mlx5_core_is_ecpf(esw->dev)) {1547			ret = mlx5_eswitch_load_vf_vports(esw, num_vfs, vport_events);1548			if (!ret)1549				esw->esw_funcs.num_vfs = num_vfs;1550		} else if (mlx5_core_ec_sriov_enabled(esw->dev)) {1551			ret = mlx5_eswitch_load_ec_vf_vports(esw, num_vfs, vport_events);1552			if (!ret)1553				esw->esw_funcs.num_ec_vfs = num_vfs;1554		}1555	}1556 1557	if (toggle_lag)1558		mlx5_lag_enable_change(esw->dev);1559 1560	return ret;1561}1562 1563/* When disabling sriov, free driver level resources. */1564void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf)1565{1566	if (!mlx5_esw_allowed(esw))1567		return;1568 1569	devl_assert_locked(priv_to_devlink(esw->dev));1570	/* If driver is unloaded, this function is called twice by remove_one()1571	 * and mlx5_unload(). Prevent the second call.1572	 */1573	if (!esw->esw_funcs.num_vfs && !esw->esw_funcs.num_ec_vfs && !clear_vf)1574		return;1575 1576	esw_info(esw->dev, "Unload vfs: mode(%s), nvfs(%d), necvfs(%d), active vports(%d)\n",1577		 esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",1578		 esw->esw_funcs.num_vfs, esw->esw_funcs.num_ec_vfs, esw->enabled_vports);1579 1580	if (!mlx5_core_is_ecpf(esw->dev)) {1581		mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs);1582		if (clear_vf)1583			mlx5_eswitch_clear_vf_vports_info(esw);1584	} else if (mlx5_core_ec_sriov_enabled(esw->dev)) {1585		mlx5_eswitch_unload_ec_vf_vports(esw, esw->esw_funcs.num_ec_vfs);1586		if (clear_vf)1587			mlx5_eswitch_clear_ec_vf_vports_info(esw);1588	}1589 1590	if (esw->mode == MLX5_ESWITCH_OFFLOADS) {1591		struct devlink *devlink = priv_to_devlink(esw->dev);1592 1593		devl_rate_nodes_destroy(devlink);1594	}1595	/* Destroy legacy fdb when disabling sriov in legacy mode. */1596	if (esw->mode == MLX5_ESWITCH_LEGACY)1597		mlx5_eswitch_disable_locked(esw);1598 1599	if (!mlx5_core_is_ecpf(esw->dev))1600		esw->esw_funcs.num_vfs = 0;1601	else1602		esw->esw_funcs.num_ec_vfs = 0;1603}1604 1605/* Free resources for corresponding eswitch mode. It is called by devlink1606 * when changing eswitch mode or modprobe when unloading driver.1607 */1608void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw)1609{1610	struct devlink *devlink = priv_to_devlink(esw->dev);1611 1612	/* Notify eswitch users that it is exiting from current mode.1613	 * So that it can do necessary cleanup before the eswitch is disabled.1614	 */1615	mlx5_esw_mode_change_notify(esw, MLX5_ESWITCH_LEGACY);1616 1617	mlx5_eq_notifier_unregister(esw->dev, &esw->nb);1618	mlx5_eswitch_event_handler_unregister(esw);1619 1620	esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), necvfs(%d), active vports(%d)\n",1621		 esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",1622		 esw->esw_funcs.num_vfs, esw->esw_funcs.num_ec_vfs, esw->enabled_vports);1623 1624	if (esw->fdb_table.flags & MLX5_ESW_FDB_CREATED) {1625		esw->fdb_table.flags &= ~MLX5_ESW_FDB_CREATED;1626		if (esw->mode == MLX5_ESWITCH_OFFLOADS)1627			esw_offloads_disable(esw);1628		else if (esw->mode == MLX5_ESWITCH_LEGACY)1629			esw_legacy_disable(esw);1630		mlx5_esw_acls_ns_cleanup(esw);1631	}1632 1633	if (esw->mode == MLX5_ESWITCH_OFFLOADS)1634		devl_rate_nodes_destroy(devlink);1635}1636 1637void mlx5_eswitch_disable(struct mlx5_eswitch *esw)1638{1639	if (!mlx5_esw_allowed(esw))1640		return;1641 1642	devl_assert_locked(priv_to_devlink(esw->dev));1643	mlx5_lag_disable_change(esw->dev);1644	mlx5_eswitch_disable_locked(esw);1645	esw->mode = MLX5_ESWITCH_LEGACY;1646	mlx5_lag_enable_change(esw->dev);1647}1648 1649static int mlx5_query_hca_cap_host_pf(struct mlx5_core_dev *dev, void *out)1650{1651	u16 opmod = (MLX5_CAP_GENERAL << 1) | (HCA_CAP_OPMOD_GET_MAX & 0x01);1652	u8 in[MLX5_ST_SZ_BYTES(query_hca_cap_in)] = {};1653 1654	MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP);1655	MLX5_SET(query_hca_cap_in, in, op_mod, opmod);1656	MLX5_SET(query_hca_cap_in, in, function_id, MLX5_VPORT_PF);1657	MLX5_SET(query_hca_cap_in, in, other_function, true);1658	return mlx5_cmd_exec_inout(dev, query_hca_cap, in, out);1659}1660 1661int mlx5_esw_sf_max_hpf_functions(struct mlx5_core_dev *dev, u16 *max_sfs, u16 *sf_base_id)1662 1663{1664	int query_out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);1665	void *query_ctx;1666	void *hca_caps;1667	int err;1668 1669	if (!mlx5_core_is_ecpf(dev)) {1670		*max_sfs = 0;1671		return 0;1672	}1673 1674	query_ctx = kzalloc(query_out_sz, GFP_KERNEL);1675	if (!query_ctx)1676		return -ENOMEM;1677 1678	err = mlx5_query_hca_cap_host_pf(dev, query_ctx);1679	if (err)1680		goto out_free;1681 1682	hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);1683	*max_sfs = MLX5_GET(cmd_hca_cap, hca_caps, max_num_sf);1684	*sf_base_id = MLX5_GET(cmd_hca_cap, hca_caps, sf_base_id);1685 1686out_free:1687	kfree(query_ctx);1688	return err;1689}1690 1691static int mlx5_esw_vport_alloc(struct mlx5_eswitch *esw,1692				int index, u16 vport_num)1693{1694	struct mlx5_vport *vport;1695	int err;1696 1697	vport = kzalloc(sizeof(*vport), GFP_KERNEL);1698	if (!vport)1699		return -ENOMEM;1700 1701	vport->dev = esw->dev;1702	vport->vport = vport_num;1703	vport->index = index;1704	vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO;1705	INIT_WORK(&vport->vport_change_handler, esw_vport_change_handler);1706	err = xa_insert(&esw->vports, vport_num, vport, GFP_KERNEL);1707	if (err)1708		goto insert_err;1709 1710	esw->total_vports++;1711	return 0;1712 1713insert_err:1714	kfree(vport);1715	return err;1716}1717 1718static void mlx5_esw_vport_free(struct mlx5_eswitch *esw, struct mlx5_vport *vport)1719{1720	xa_erase(&esw->vports, vport->vport);1721	kfree(vport);1722}1723 1724static void mlx5_esw_vports_cleanup(struct mlx5_eswitch *esw)1725{1726	struct mlx5_vport *vport;1727	unsigned long i;1728 1729	mlx5_esw_for_each_vport(esw, i, vport)1730		mlx5_esw_vport_free(esw, vport);1731	xa_destroy(&esw->vports);1732}1733 1734static int mlx5_esw_vports_init(struct mlx5_eswitch *esw)1735{1736	struct mlx5_core_dev *dev = esw->dev;1737	u16 max_host_pf_sfs;1738	u16 base_sf_num;1739	int idx = 0;1740	int err;1741	int i;1742 1743	xa_init(&esw->vports);1744 1745	err = mlx5_esw_vport_alloc(esw, idx, MLX5_VPORT_PF);1746	if (err)1747		goto err;1748	if (esw->first_host_vport == MLX5_VPORT_PF)1749		xa_set_mark(&esw->vports, idx, MLX5_ESW_VPT_HOST_FN);1750	idx++;1751 1752	for (i = 0; i < mlx5_core_max_vfs(dev); i++) {1753		err = mlx5_esw_vport_alloc(esw, idx, idx);1754		if (err)1755			goto err;1756		xa_set_mark(&esw->vports, idx, MLX5_ESW_VPT_VF);1757		xa_set_mark(&esw->vports, idx, MLX5_ESW_VPT_HOST_FN);1758		idx++;1759	}1760	base_sf_num = mlx5_sf_start_function_id(dev);1761	for (i = 0; i < mlx5_sf_max_functions(dev); i++) {1762		err = mlx5_esw_vport_alloc(esw, idx, base_sf_num + i);1763		if (err)1764			goto err;1765		xa_set_mark(&esw->vports, base_sf_num + i, MLX5_ESW_VPT_SF);1766		idx++;1767	}1768 1769	err = mlx5_esw_sf_max_hpf_functions(dev, &max_host_pf_sfs, &base_sf_num);1770	if (err)1771		goto err;1772	for (i = 0; i < max_host_pf_sfs; i++) {1773		err = mlx5_esw_vport_alloc(esw, idx, base_sf_num + i);1774		if (err)1775			goto err;1776		xa_set_mark(&esw->vports, base_sf_num + i, MLX5_ESW_VPT_SF);1777		idx++;1778	}1779 1780	if (mlx5_core_ec_sriov_enabled(esw->dev)) {1781		int ec_vf_base_num = mlx5_core_ec_vf_vport_base(dev);1782 1783		for (i = 0; i < mlx5_core_max_ec_vfs(esw->dev); i++) {1784			err = mlx5_esw_vport_alloc(esw, idx, ec_vf_base_num + i);1785			if (err)1786				goto err;1787			idx++;1788		}1789	}1790 1791	if (mlx5_ecpf_vport_exists(dev) ||1792	    mlx5_core_is_ecpf_esw_manager(dev)) {1793		err = mlx5_esw_vport_alloc(esw, idx, MLX5_VPORT_ECPF);1794		if (err)1795			goto err;1796		idx++;1797	}1798	err = mlx5_esw_vport_alloc(esw, idx, MLX5_VPORT_UPLINK);1799	if (err)1800		goto err;1801	return 0;1802 1803err:1804	mlx5_esw_vports_cleanup(esw);1805	return err;1806}1807 1808static int mlx5_devlink_esw_multiport_set(struct devlink *devlink, u32 id,1809					  struct devlink_param_gset_ctx *ctx,1810					  struct netlink_ext_ack *extack)1811{1812	struct mlx5_core_dev *dev = devlink_priv(devlink);1813 1814	if (!MLX5_ESWITCH_MANAGER(dev))1815		return -EOPNOTSUPP;1816 1817	if (ctx->val.vbool)1818		return mlx5_lag_mpesw_enable(dev);1819 1820	mlx5_lag_mpesw_disable(dev);1821	return 0;1822}1823 1824static int mlx5_devlink_esw_multiport_get(struct devlink *devlink, u32 id,1825					  struct devlink_param_gset_ctx *ctx)1826{1827	struct mlx5_core_dev *dev = devlink_priv(devlink);1828 1829	ctx->val.vbool = mlx5_lag_is_mpesw(dev);1830	return 0;1831}1832 1833static const struct devlink_param mlx5_eswitch_params[] = {1834	DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_ID_ESW_MULTIPORT,1835			     "esw_multiport", DEVLINK_PARAM_TYPE_BOOL,1836			     BIT(DEVLINK_PARAM_CMODE_RUNTIME),1837			     mlx5_devlink_esw_multiport_get,1838			     mlx5_devlink_esw_multiport_set, NULL),1839};1840 1841int mlx5_eswitch_init(struct mlx5_core_dev *dev)1842{1843	struct mlx5_eswitch *esw;1844	int err;1845 1846	if (!MLX5_VPORT_MANAGER(dev) && !MLX5_ESWITCH_MANAGER(dev))1847		return 0;1848 1849	esw = kzalloc(sizeof(*esw), GFP_KERNEL);1850	if (!esw)1851		return -ENOMEM;1852 1853	err = devl_params_register(priv_to_devlink(dev), mlx5_eswitch_params,1854				   ARRAY_SIZE(mlx5_eswitch_params));1855	if (err)1856		goto free_esw;1857 1858	esw->dev = dev;1859	esw->manager_vport = mlx5_eswitch_manager_vport(dev);1860	esw->first_host_vport = mlx5_eswitch_first_host_vport_num(dev);1861 1862	esw->debugfs_root = debugfs_create_dir("esw", mlx5_debugfs_get_dev_root(dev));1863	esw->work_queue = create_singlethread_workqueue("mlx5_esw_wq");1864	if (!esw->work_queue) {1865		err = -ENOMEM;1866		goto abort;1867	}1868 1869	err = mlx5_esw_vports_init(esw);1870	if (err)1871		goto abort;1872 1873	dev->priv.eswitch = esw;1874	err = esw_offloads_init(esw);1875	if (err)1876		goto reps_err;1877 1878	mutex_init(&esw->offloads.encap_tbl_lock);1879	hash_init(esw->offloads.encap_tbl);1880	mutex_init(&esw->offloads.decap_tbl_lock);1881	hash_init(esw->offloads.decap_tbl);1882	mlx5e_mod_hdr_tbl_init(&esw->offloads.mod_hdr);1883	atomic64_set(&esw->offloads.num_flows, 0);1884	ida_init(&esw->offloads.vport_metadata_ida);1885	xa_init_flags(&esw->offloads.vhca_map, XA_FLAGS_ALLOC);1886	mutex_init(&esw->state_lock);1887	init_rwsem(&esw->mode_lock);1888	refcount_set(&esw->qos.refcnt, 0);1889 1890	esw->enabled_vports = 0;1891	esw->mode = MLX5_ESWITCH_LEGACY;1892	esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE;1893	if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) &&1894	    MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap))1895		esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;1896	else1897		esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;1898	BLOCKING_INIT_NOTIFIER_HEAD(&esw->n_head);1899 1900	esw_info(dev,1901		 "Total vports %d, per vport: max uc(%d) max mc(%d)\n",1902		 esw->total_vports,1903		 MLX5_MAX_UC_PER_VPORT(dev),1904		 MLX5_MAX_MC_PER_VPORT(dev));1905	return 0;1906 1907reps_err:1908	mlx5_esw_vports_cleanup(esw);1909	dev->priv.eswitch = NULL;1910abort:1911	if (esw->work_queue)1912		destroy_workqueue(esw->work_queue);1913	debugfs_remove_recursive(esw->debugfs_root);1914	devl_params_unregister(priv_to_devlink(dev), mlx5_eswitch_params,1915			       ARRAY_SIZE(mlx5_eswitch_params));1916free_esw:1917	kfree(esw);1918	return err;1919}1920 1921void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)1922{1923	if (!esw)1924		return;1925 1926	esw_info(esw->dev, "cleanup\n");1927 1928	destroy_workqueue(esw->work_queue);1929	WARN_ON(refcount_read(&esw->qos.refcnt));1930	mutex_destroy(&esw->state_lock);1931	WARN_ON(!xa_empty(&esw->offloads.vhca_map));1932	xa_destroy(&esw->offloads.vhca_map);1933	ida_destroy(&esw->offloads.vport_metadata_ida);1934	mlx5e_mod_hdr_tbl_destroy(&esw->offloads.mod_hdr);1935	mutex_destroy(&esw->offloads.encap_tbl_lock);1936	mutex_destroy(&esw->offloads.decap_tbl_lock);1937	esw_offloads_cleanup(esw);1938	esw->dev->priv.eswitch = NULL;1939	mlx5_esw_vports_cleanup(esw);1940	debugfs_remove_recursive(esw->debugfs_root);1941	devl_params_unregister(priv_to_devlink(esw->dev), mlx5_eswitch_params,1942			       ARRAY_SIZE(mlx5_eswitch_params));1943	kfree(esw);1944}1945 1946/* Vport Administration */1947static int1948mlx5_esw_set_vport_mac_locked(struct mlx5_eswitch *esw,1949			      struct mlx5_vport *evport, const u8 *mac)1950{1951	u16 vport_num = evport->vport;1952	u64 node_guid;1953	int err = 0;1954 1955	if (is_multicast_ether_addr(mac))1956		return -EINVAL;1957 1958	if (evport->info.spoofchk && !is_valid_ether_addr(mac))1959		mlx5_core_warn(esw->dev,1960			       "Set invalid MAC while spoofchk is on, vport(%d)\n",1961			       vport_num);1962 1963	err = mlx5_modify_nic_vport_mac_address(esw->dev, vport_num, mac);1964	if (err) {1965		mlx5_core_warn(esw->dev,1966			       "Failed to mlx5_modify_nic_vport_mac vport(%d) err=(%d)\n",1967			       vport_num, err);1968		return err;1969	}1970 1971	node_guid_gen_from_mac(&node_guid, mac);1972	err = mlx5_modify_nic_vport_node_guid(esw->dev, vport_num, node_guid);1973	if (err)1974		mlx5_core_warn(esw->dev,1975			       "Failed to set vport %d node guid, err = %d. RDMA_CM will not function properly for this VF.\n",1976			       vport_num, err);1977 1978	ether_addr_copy(evport->info.mac, mac);1979	evport->info.node_guid = node_guid;1980	if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY)1981		err = esw_acl_ingress_lgcy_setup(esw, evport);1982 1983	return err;1984}1985 1986int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,1987			       u16 vport, const u8 *mac)1988{1989	struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);1990	int err = 0;1991 1992	if (IS_ERR(evport))1993		return PTR_ERR(evport);1994 1995	mutex_lock(&esw->state_lock);1996	err = mlx5_esw_set_vport_mac_locked(esw, evport, mac);1997	mutex_unlock(&esw->state_lock);1998	return err;1999}2000 2001static bool mlx5_esw_check_port_type(struct mlx5_eswitch *esw, u16 vport_num, xa_mark_t mark)2002{2003	return xa_get_mark(&esw->vports, vport_num, mark);2004}2005 2006bool mlx5_eswitch_is_vf_vport(struct mlx5_eswitch *esw, u16 vport_num)2007{2008	return mlx5_esw_check_port_type(esw, vport_num, MLX5_ESW_VPT_VF);2009}2010 2011bool mlx5_eswitch_is_pf_vf_vport(struct mlx5_eswitch *esw, u16 vport_num)2012{2013	return vport_num == MLX5_VPORT_PF ||2014		mlx5_eswitch_is_vf_vport(esw, vport_num);2015}2016 2017bool mlx5_esw_is_sf_vport(struct mlx5_eswitch *esw, u16 vport_num)2018{2019	return mlx5_esw_check_port_type(esw, vport_num, MLX5_ESW_VPT_SF);2020}2021 2022int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,2023				 u16 vport, int link_state)2024{2025	struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);2026	int opmod = MLX5_VPORT_STATE_OP_MOD_ESW_VPORT;2027	int other_vport = 1;2028	int err = 0;2029 2030	if (!mlx5_esw_allowed(esw))2031		return -EPERM;2032	if (IS_ERR(evport))2033		return PTR_ERR(evport);2034 2035	if (vport == MLX5_VPORT_UPLINK) {2036		opmod = MLX5_VPORT_STATE_OP_MOD_UPLINK;2037		other_vport = 0;2038		vport = 0;2039	}2040	mutex_lock(&esw->state_lock);2041	if (esw->mode != MLX5_ESWITCH_LEGACY) {2042		err = -EOPNOTSUPP;2043		goto unlock;2044	}2045 2046	err = mlx5_modify_vport_admin_state(esw->dev, opmod, vport, other_vport, link_state);2047	if (err) {2048		mlx5_core_warn(esw->dev, "Failed to set vport %d link state, opmod = %d, err = %d",2049			       vport, opmod, err);2050		goto unlock;2051	}2052 2053	evport->info.link_state = link_state;2054 2055unlock:2056	mutex_unlock(&esw->state_lock);2057	return err;2058}2059 2060int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,2061				  u16 vport, struct ifla_vf_info *ivi)2062{2063	struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);2064 2065	if (IS_ERR(evport))2066		return PTR_ERR(evport);2067 2068	memset(ivi, 0, sizeof(*ivi));2069	ivi->vf = vport - 1;2070 2071	mutex_lock(&esw->state_lock);2072	ether_addr_copy(ivi->mac, evport->info.mac);2073	ivi->linkstate = evport->info.link_state;2074	ivi->vlan = evport->info.vlan;2075	ivi->qos = evport->info.qos;2076	ivi->spoofchk = evport->info.spoofchk;2077	ivi->trusted = evport->info.trusted;2078	if (evport->qos.enabled) {2079		ivi->min_tx_rate = evport->qos.min_rate;2080		ivi->max_tx_rate = evport->qos.max_rate;2081	}2082	mutex_unlock(&esw->state_lock);2083 2084	return 0;2085}2086 2087int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,2088				  u16 vport, u16 vlan, u8 qos, u8 set_flags)2089{2090	struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);2091	bool vst_mode_steering = esw_vst_mode_is_steering(esw);2092	int err = 0;2093 2094	if (IS_ERR(evport))2095		return PTR_ERR(evport);2096	if (vlan > 4095 || qos > 7)2097		return -EINVAL;2098 2099	if (esw->mode == MLX5_ESWITCH_OFFLOADS || !vst_mode_steering) {2100		err = modify_esw_vport_cvlan(esw->dev, vport, vlan, qos, set_flags);2101		if (err)2102			return err;2103	}2104 2105	evport->info.vlan = vlan;2106	evport->info.qos = qos;2107	if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY) {2108		err = esw_acl_ingress_lgcy_setup(esw, evport);2109		if (err)2110			return err;2111		err = esw_acl_egress_lgcy_setup(esw, evport);2112	}2113 2114	return err;2115}2116 2117int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,2118				 u16 vport_num,2119				 struct ifla_vf_stats *vf_stats)2120{2121	struct mlx5_vport *vport = mlx5_eswitch_get_vport(esw, vport_num);2122	int outlen = MLX5_ST_SZ_BYTES(query_vport_counter_out);2123	u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)] = {};2124	struct mlx5_vport_drop_stats stats = {};2125	int err = 0;2126	u32 *out;2127 2128	if (IS_ERR(vport))2129		return PTR_ERR(vport);2130 2131	out = kvzalloc(outlen, GFP_KERNEL);2132	if (!out)2133		return -ENOMEM;2134 2135	MLX5_SET(query_vport_counter_in, in, opcode,2136		 MLX5_CMD_OP_QUERY_VPORT_COUNTER);2137	MLX5_SET(query_vport_counter_in, in, op_mod, 0);2138	MLX5_SET(query_vport_counter_in, in, vport_number, vport->vport);2139	MLX5_SET(query_vport_counter_in, in, other_vport, 1);2140 2141	err = mlx5_cmd_exec_inout(esw->dev, query_vport_counter, in, out);2142	if (err)2143		goto free_out;2144 2145	#define MLX5_GET_CTR(p, x) \2146		MLX5_GET64(query_vport_counter_out, p, x)2147 2148	memset(vf_stats, 0, sizeof(*vf_stats));2149	vf_stats->rx_packets =2150		MLX5_GET_CTR(out, received_eth_unicast.packets) +2151		MLX5_GET_CTR(out, received_ib_unicast.packets) +2152		MLX5_GET_CTR(out, received_eth_multicast.packets) +2153		MLX5_GET_CTR(out, received_ib_multicast.packets) +2154		MLX5_GET_CTR(out, received_eth_broadcast.packets);2155 2156	vf_stats->rx_bytes =2157		MLX5_GET_CTR(out, received_eth_unicast.octets) +2158		MLX5_GET_CTR(out, received_ib_unicast.octets) +2159		MLX5_GET_CTR(out, received_eth_multicast.octets) +2160		MLX5_GET_CTR(out, received_ib_multicast.octets) +2161		MLX5_GET_CTR(out, received_eth_broadcast.octets);2162 2163	vf_stats->tx_packets =2164		MLX5_GET_CTR(out, transmitted_eth_unicast.packets) +2165		MLX5_GET_CTR(out, transmitted_ib_unicast.packets) +2166		MLX5_GET_CTR(out, transmitted_eth_multicast.packets) +2167		MLX5_GET_CTR(out, transmitted_ib_multicast.packets) +2168		MLX5_GET_CTR(out, transmitted_eth_broadcast.packets);2169 2170	vf_stats->tx_bytes =2171		MLX5_GET_CTR(out, transmitted_eth_unicast.octets) +2172		MLX5_GET_CTR(out, transmitted_ib_unicast.octets) +2173		MLX5_GET_CTR(out, transmitted_eth_multicast.octets) +2174		MLX5_GET_CTR(out, transmitted_ib_multicast.octets) +2175		MLX5_GET_CTR(out, transmitted_eth_broadcast.octets);2176 2177	vf_stats->multicast =2178		MLX5_GET_CTR(out, received_eth_multicast.packets) +2179		MLX5_GET_CTR(out, received_ib_multicast.packets);2180 2181	vf_stats->broadcast =2182		MLX5_GET_CTR(out, received_eth_broadcast.packets);2183 2184	err = mlx5_esw_query_vport_drop_stats(esw->dev, vport, &stats);2185	if (err)2186		goto free_out;2187	vf_stats->rx_dropped = stats.rx_dropped;2188	vf_stats->tx_dropped = stats.tx_dropped;2189 2190free_out:2191	kvfree(out);2192	return err;2193}2194 2195u8 mlx5_eswitch_mode(const struct mlx5_core_dev *dev)2196{2197	struct mlx5_eswitch *esw = dev->priv.eswitch;2198 2199	return mlx5_esw_allowed(esw) ? esw->mode : MLX5_ESWITCH_LEGACY;2200}2201EXPORT_SYMBOL_GPL(mlx5_eswitch_mode);2202 2203enum devlink_eswitch_encap_mode2204mlx5_eswitch_get_encap_mode(const struct mlx5_core_dev *dev)2205{2206	struct mlx5_eswitch *esw;2207 2208	esw = dev->priv.eswitch;2209	return (mlx5_eswitch_mode(dev) == MLX5_ESWITCH_OFFLOADS)  ? esw->offloads.encap :2210		DEVLINK_ESWITCH_ENCAP_MODE_NONE;2211}2212EXPORT_SYMBOL(mlx5_eswitch_get_encap_mode);2213 2214bool mlx5_esw_multipath_prereq(struct mlx5_core_dev *dev0,2215			       struct mlx5_core_dev *dev1)2216{2217	return (dev0->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS &&2218		dev1->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS);2219}2220 2221int mlx5_esw_event_notifier_register(struct mlx5_eswitch *esw, struct notifier_block *nb)2222{2223	return blocking_notifier_chain_register(&esw->n_head, nb);2224}2225 2226void mlx5_esw_event_notifier_unregister(struct mlx5_eswitch *esw, struct notifier_block *nb)2227{2228	blocking_notifier_chain_unregister(&esw->n_head, nb);2229}2230 2231/**2232 * mlx5_esw_hold() - Try to take a read lock on esw mode lock.2233 * @mdev: mlx5 core device.2234 *2235 * Should be called by esw resources callers.2236 *2237 * Return: true on success or false.2238 */2239bool mlx5_esw_hold(struct mlx5_core_dev *mdev)2240{2241	struct mlx5_eswitch *esw = mdev->priv.eswitch;2242 2243	/* e.g. VF doesn't have eswitch so nothing to do */2244	if (!mlx5_esw_allowed(esw))2245		return true;2246 2247	if (down_read_trylock(&esw->mode_lock) != 0) {2248		if (esw->eswitch_operation_in_progress) {2249			up_read(&esw->mode_lock);2250			return false;2251		}2252		return true;2253	}2254 2255	return false;2256}2257 2258/**2259 * mlx5_esw_release() - Release a read lock on esw mode lock.2260 * @mdev: mlx5 core device.2261 */2262void mlx5_esw_release(struct mlx5_core_dev *mdev)2263{2264	struct mlx5_eswitch *esw = mdev->priv.eswitch;2265 2266	if (mlx5_esw_allowed(esw))2267		up_read(&esw->mode_lock);2268}2269 2270/**2271 * mlx5_esw_get() - Increase esw user count.2272 * @mdev: mlx5 core device.2273 */2274void mlx5_esw_get(struct mlx5_core_dev *mdev)2275{2276	struct mlx5_eswitch *esw = mdev->priv.eswitch;2277 2278	if (mlx5_esw_allowed(esw))2279		atomic64_inc(&esw->user_count);2280}2281 2282/**2283 * mlx5_esw_put() - Decrease esw user count.2284 * @mdev: mlx5 core device.2285 */2286void mlx5_esw_put(struct mlx5_core_dev *mdev)2287{2288	struct mlx5_eswitch *esw = mdev->priv.eswitch;2289 2290	if (mlx5_esw_allowed(esw))2291		atomic64_dec_if_positive(&esw->user_count);2292}2293 2294/**2295 * mlx5_esw_try_lock() - Take a write lock on esw mode lock.2296 * @esw: eswitch device.2297 *2298 * Should be called by esw mode change routine.2299 *2300 * Return:2301 * * 0       - esw mode if successfully locked and refcount is 0.2302 * * -EBUSY  - refcount is not 0.2303 * * -EINVAL - In the middle of switching mode or lock is already held.2304 */2305int mlx5_esw_try_lock(struct mlx5_eswitch *esw)2306{2307	if (down_write_trylock(&esw->mode_lock) == 0)2308		return -EINVAL;2309 2310	if (esw->eswitch_operation_in_progress ||2311	    atomic64_read(&esw->user_count) > 0) {2312		up_write(&esw->mode_lock);2313		return -EBUSY;2314	}2315 2316	return esw->mode;2317}2318 2319int mlx5_esw_lock(struct mlx5_eswitch *esw)2320{2321	down_write(&esw->mode_lock);2322 2323	if (esw->eswitch_operation_in_progress) {2324		up_write(&esw->mode_lock);2325		return -EBUSY;2326	}2327 2328	return 0;2329}2330 2331/**2332 * mlx5_esw_unlock() - Release write lock on esw mode lock2333 * @esw: eswitch device.2334 */2335void mlx5_esw_unlock(struct mlx5_eswitch *esw)2336{2337	up_write(&esw->mode_lock);2338}2339 2340/**2341 * mlx5_eswitch_get_total_vports - Get total vports of the eswitch2342 *2343 * @dev: Pointer to core device2344 *2345 * mlx5_eswitch_get_total_vports returns total number of eswitch vports.2346 */2347u16 mlx5_eswitch_get_total_vports(const struct mlx5_core_dev *dev)2348{2349	struct mlx5_eswitch *esw;2350 2351	esw = dev->priv.eswitch;2352	return mlx5_esw_allowed(esw) ? esw->total_vports : 0;2353}2354EXPORT_SYMBOL_GPL(mlx5_eswitch_get_total_vports);2355 2356/**2357 * mlx5_eswitch_get_core_dev - Get the mdev device2358 * @esw : eswitch device.2359 *2360 * Return the mellanox core device which manages the eswitch.2361 */2362struct mlx5_core_dev *mlx5_eswitch_get_core_dev(struct mlx5_eswitch *esw)2363{2364	return mlx5_esw_allowed(esw) ? esw->dev : NULL;2365}2366EXPORT_SYMBOL(mlx5_eswitch_get_core_dev);2367 2368bool mlx5_eswitch_block_ipsec(struct mlx5_core_dev *dev)2369{2370	struct mlx5_eswitch *esw = dev->priv.eswitch;2371 2372	if (!mlx5_esw_allowed(esw))2373		return true;2374 2375	mutex_lock(&esw->state_lock);2376	if (esw->enabled_ipsec_vf_count) {2377		mutex_unlock(&esw->state_lock);2378		return false;2379	}2380 2381	dev->num_ipsec_offloads++;2382	mutex_unlock(&esw->state_lock);2383	return true;2384}2385 2386void mlx5_eswitch_unblock_ipsec(struct mlx5_core_dev *dev)2387{2388	struct mlx5_eswitch *esw = dev->priv.eswitch;2389 2390	if (!mlx5_esw_allowed(esw))2391		/* Failure means no eswitch => core dev is not a PF */2392		return;2393 2394	mutex_lock(&esw->state_lock);2395	dev->num_ipsec_offloads--;2396	mutex_unlock(&esw->state_lock);2397}2398