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