0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/etherdevice.h>
0034 #include <linux/mlx5/driver.h>
0035 #include <linux/mlx5/mlx5_ifc.h>
0036 #include <linux/mlx5/vport.h>
0037 #include <linux/mlx5/fs.h>
0038 #include <linux/mlx5/mpfs.h>
0039 #include <linux/debugfs.h>
0040 #include "esw/acl/lgcy.h"
0041 #include "esw/legacy.h"
0042 #include "esw/qos.h"
0043 #include "mlx5_core.h"
0044 #include "lib/eq.h"
0045 #include "eswitch.h"
0046 #include "fs_core.h"
0047 #include "devlink.h"
0048 #include "ecpf.h"
0049 #include "en/mod_hdr.h"
0050
0051 enum {
0052 MLX5_ACTION_NONE = 0,
0053 MLX5_ACTION_ADD = 1,
0054 MLX5_ACTION_DEL = 2,
0055 };
0056
0057
0058 struct vport_addr {
0059 struct l2addr_node node;
0060 u8 action;
0061 u16 vport;
0062 struct mlx5_flow_handle *flow_rule;
0063 bool mpfs;
0064
0065 bool mc_promisc;
0066 };
0067
0068 static int mlx5_eswitch_check(const struct mlx5_core_dev *dev)
0069 {
0070 if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
0071 return -EOPNOTSUPP;
0072
0073 if (!MLX5_ESWITCH_MANAGER(dev))
0074 return -EOPNOTSUPP;
0075
0076 return 0;
0077 }
0078
0079 struct mlx5_eswitch *mlx5_devlink_eswitch_get(struct devlink *devlink)
0080 {
0081 struct mlx5_core_dev *dev = devlink_priv(devlink);
0082 int err;
0083
0084 err = mlx5_eswitch_check(dev);
0085 if (err)
0086 return ERR_PTR(err);
0087
0088 return dev->priv.eswitch;
0089 }
0090
0091 struct mlx5_vport *__must_check
0092 mlx5_eswitch_get_vport(struct mlx5_eswitch *esw, u16 vport_num)
0093 {
0094 struct mlx5_vport *vport;
0095
0096 if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager))
0097 return ERR_PTR(-EPERM);
0098
0099 vport = xa_load(&esw->vports, vport_num);
0100 if (!vport) {
0101 esw_debug(esw->dev, "vport out of range: num(0x%x)\n", vport_num);
0102 return ERR_PTR(-EINVAL);
0103 }
0104 return vport;
0105 }
0106
0107 static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport,
0108 u32 events_mask)
0109 {
0110 u32 in[MLX5_ST_SZ_DW(modify_nic_vport_context_in)] = {};
0111 void *nic_vport_ctx;
0112
0113 MLX5_SET(modify_nic_vport_context_in, in,
0114 opcode, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT);
0115 MLX5_SET(modify_nic_vport_context_in, in, field_select.change_event, 1);
0116 MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport);
0117 MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1);
0118 nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in,
0119 in, nic_vport_context);
0120
0121 MLX5_SET(nic_vport_context, nic_vport_ctx, arm_change_event, 1);
0122
0123 if (events_mask & MLX5_VPORT_UC_ADDR_CHANGE)
0124 MLX5_SET(nic_vport_context, nic_vport_ctx,
0125 event_on_uc_address_change, 1);
0126 if (events_mask & MLX5_VPORT_MC_ADDR_CHANGE)
0127 MLX5_SET(nic_vport_context, nic_vport_ctx,
0128 event_on_mc_address_change, 1);
0129 if (events_mask & MLX5_VPORT_PROMISC_CHANGE)
0130 MLX5_SET(nic_vport_context, nic_vport_ctx,
0131 event_on_promisc_change, 1);
0132
0133 return mlx5_cmd_exec_in(dev, modify_nic_vport_context, in);
0134 }
0135
0136
0137 int mlx5_eswitch_modify_esw_vport_context(struct mlx5_core_dev *dev, u16 vport,
0138 bool other_vport, void *in)
0139 {
0140 MLX5_SET(modify_esw_vport_context_in, in, opcode,
0141 MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT);
0142 MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport);
0143 MLX5_SET(modify_esw_vport_context_in, in, other_vport, other_vport);
0144 return mlx5_cmd_exec_in(dev, modify_esw_vport_context, in);
0145 }
0146
0147 static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u16 vport,
0148 u16 vlan, u8 qos, u8 set_flags)
0149 {
0150 u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {};
0151
0152 if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||
0153 !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))
0154 return -EOPNOTSUPP;
0155
0156 esw_debug(dev, "Set Vport[%d] VLAN %d qos %d set=%x\n",
0157 vport, vlan, qos, set_flags);
0158
0159 if (set_flags & SET_VLAN_STRIP)
0160 MLX5_SET(modify_esw_vport_context_in, in,
0161 esw_vport_context.vport_cvlan_strip, 1);
0162
0163 if (set_flags & SET_VLAN_INSERT) {
0164
0165 MLX5_SET(modify_esw_vport_context_in, in,
0166 esw_vport_context.vport_cvlan_insert, 1);
0167
0168 MLX5_SET(modify_esw_vport_context_in, in,
0169 esw_vport_context.cvlan_pcp, qos);
0170 MLX5_SET(modify_esw_vport_context_in, in,
0171 esw_vport_context.cvlan_id, vlan);
0172 }
0173
0174 MLX5_SET(modify_esw_vport_context_in, in,
0175 field_select.vport_cvlan_strip, 1);
0176 MLX5_SET(modify_esw_vport_context_in, in,
0177 field_select.vport_cvlan_insert, 1);
0178
0179 return mlx5_eswitch_modify_esw_vport_context(dev, vport, true, in);
0180 }
0181
0182
0183 static struct mlx5_flow_handle *
0184 __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u16 vport, bool rx_rule,
0185 u8 mac_c[ETH_ALEN], u8 mac_v[ETH_ALEN])
0186 {
0187 int match_header = (is_zero_ether_addr(mac_c) ? 0 :
0188 MLX5_MATCH_OUTER_HEADERS);
0189 struct mlx5_flow_handle *flow_rule = NULL;
0190 struct mlx5_flow_act flow_act = {0};
0191 struct mlx5_flow_destination dest = {};
0192 struct mlx5_flow_spec *spec;
0193 void *mv_misc = NULL;
0194 void *mc_misc = NULL;
0195 u8 *dmac_v = NULL;
0196 u8 *dmac_c = NULL;
0197
0198 if (rx_rule)
0199 match_header |= MLX5_MATCH_MISC_PARAMETERS;
0200
0201 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
0202 if (!spec)
0203 return NULL;
0204
0205 dmac_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
0206 outer_headers.dmac_47_16);
0207 dmac_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
0208 outer_headers.dmac_47_16);
0209
0210 if (match_header & MLX5_MATCH_OUTER_HEADERS) {
0211 ether_addr_copy(dmac_v, mac_v);
0212 ether_addr_copy(dmac_c, mac_c);
0213 }
0214
0215 if (match_header & MLX5_MATCH_MISC_PARAMETERS) {
0216 mv_misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
0217 misc_parameters);
0218 mc_misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
0219 misc_parameters);
0220 MLX5_SET(fte_match_set_misc, mv_misc, source_port, MLX5_VPORT_UPLINK);
0221 MLX5_SET_TO_ONES(fte_match_set_misc, mc_misc, source_port);
0222 }
0223
0224 dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
0225 dest.vport.num = vport;
0226
0227 esw_debug(esw->dev,
0228 "\tFDB add rule dmac_v(%pM) dmac_c(%pM) -> vport(%d)\n",
0229 dmac_v, dmac_c, vport);
0230 spec->match_criteria_enable = match_header;
0231 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
0232 flow_rule =
0233 mlx5_add_flow_rules(esw->fdb_table.legacy.fdb, spec,
0234 &flow_act, &dest, 1);
0235 if (IS_ERR(flow_rule)) {
0236 esw_warn(esw->dev,
0237 "FDB: Failed to add flow rule: dmac_v(%pM) dmac_c(%pM) -> vport(%d), err(%ld)\n",
0238 dmac_v, dmac_c, vport, PTR_ERR(flow_rule));
0239 flow_rule = NULL;
0240 }
0241
0242 kvfree(spec);
0243 return flow_rule;
0244 }
0245
0246 static struct mlx5_flow_handle *
0247 esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u8 mac[ETH_ALEN], u16 vport)
0248 {
0249 u8 mac_c[ETH_ALEN];
0250
0251 eth_broadcast_addr(mac_c);
0252 return __esw_fdb_set_vport_rule(esw, vport, false, mac_c, mac);
0253 }
0254
0255 static struct mlx5_flow_handle *
0256 esw_fdb_set_vport_allmulti_rule(struct mlx5_eswitch *esw, u16 vport)
0257 {
0258 u8 mac_c[ETH_ALEN];
0259 u8 mac_v[ETH_ALEN];
0260
0261 eth_zero_addr(mac_c);
0262 eth_zero_addr(mac_v);
0263 mac_c[0] = 0x01;
0264 mac_v[0] = 0x01;
0265 return __esw_fdb_set_vport_rule(esw, vport, false, mac_c, mac_v);
0266 }
0267
0268 static struct mlx5_flow_handle *
0269 esw_fdb_set_vport_promisc_rule(struct mlx5_eswitch *esw, u16 vport)
0270 {
0271 u8 mac_c[ETH_ALEN];
0272 u8 mac_v[ETH_ALEN];
0273
0274 eth_zero_addr(mac_c);
0275 eth_zero_addr(mac_v);
0276 return __esw_fdb_set_vport_rule(esw, vport, true, mac_c, mac_v);
0277 }
0278
0279
0280 typedef int (*vport_addr_action)(struct mlx5_eswitch *esw,
0281 struct vport_addr *vaddr);
0282
0283 static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
0284 {
0285 u8 *mac = vaddr->node.addr;
0286 u16 vport = vaddr->vport;
0287 int err;
0288
0289
0290
0291
0292 if (mlx5_esw_is_manager_vport(esw, vport))
0293 goto fdb_add;
0294
0295 err = mlx5_mpfs_add_mac(esw->dev, mac);
0296 if (err) {
0297 esw_warn(esw->dev,
0298 "Failed to add L2 table mac(%pM) for vport(0x%x), err(%d)\n",
0299 mac, vport, err);
0300 return err;
0301 }
0302 vaddr->mpfs = true;
0303
0304 fdb_add:
0305
0306 if (esw->fdb_table.legacy.fdb && esw->mode == MLX5_ESWITCH_LEGACY)
0307 vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
0308
0309 esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM fr(%p)\n",
0310 vport, mac, vaddr->flow_rule);
0311
0312 return 0;
0313 }
0314
0315 static int esw_del_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
0316 {
0317 u8 *mac = vaddr->node.addr;
0318 u16 vport = vaddr->vport;
0319 int err = 0;
0320
0321
0322
0323
0324 if (!vaddr->mpfs || mlx5_esw_is_manager_vport(esw, vport))
0325 goto fdb_del;
0326
0327 err = mlx5_mpfs_del_mac(esw->dev, mac);
0328 if (err)
0329 esw_warn(esw->dev,
0330 "Failed to del L2 table mac(%pM) for vport(%d), err(%d)\n",
0331 mac, vport, err);
0332 vaddr->mpfs = false;
0333
0334 fdb_del:
0335 if (vaddr->flow_rule)
0336 mlx5_del_flow_rules(vaddr->flow_rule);
0337 vaddr->flow_rule = NULL;
0338
0339 return 0;
0340 }
0341
0342 static void update_allmulti_vports(struct mlx5_eswitch *esw,
0343 struct vport_addr *vaddr,
0344 struct esw_mc_addr *esw_mc)
0345 {
0346 u8 *mac = vaddr->node.addr;
0347 struct mlx5_vport *vport;
0348 unsigned long i;
0349 u16 vport_num;
0350
0351 mlx5_esw_for_each_vport(esw, i, vport) {
0352 struct hlist_head *vport_hash = vport->mc_list;
0353 struct vport_addr *iter_vaddr =
0354 l2addr_hash_find(vport_hash,
0355 mac,
0356 struct vport_addr);
0357 vport_num = vport->vport;
0358 if (IS_ERR_OR_NULL(vport->allmulti_rule) ||
0359 vaddr->vport == vport_num)
0360 continue;
0361 switch (vaddr->action) {
0362 case MLX5_ACTION_ADD:
0363 if (iter_vaddr)
0364 continue;
0365 iter_vaddr = l2addr_hash_add(vport_hash, mac,
0366 struct vport_addr,
0367 GFP_KERNEL);
0368 if (!iter_vaddr) {
0369 esw_warn(esw->dev,
0370 "ALL-MULTI: Failed to add MAC(%pM) to vport[%d] DB\n",
0371 mac, vport_num);
0372 continue;
0373 }
0374 iter_vaddr->vport = vport_num;
0375 iter_vaddr->flow_rule =
0376 esw_fdb_set_vport_rule(esw,
0377 mac,
0378 vport_num);
0379 iter_vaddr->mc_promisc = true;
0380 break;
0381 case MLX5_ACTION_DEL:
0382 if (!iter_vaddr)
0383 continue;
0384 mlx5_del_flow_rules(iter_vaddr->flow_rule);
0385 l2addr_hash_del(iter_vaddr);
0386 break;
0387 }
0388 }
0389 }
0390
0391 static int esw_add_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
0392 {
0393 struct hlist_head *hash = esw->mc_table;
0394 struct esw_mc_addr *esw_mc;
0395 u8 *mac = vaddr->node.addr;
0396 u16 vport = vaddr->vport;
0397
0398 if (!esw->fdb_table.legacy.fdb)
0399 return 0;
0400
0401 esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);
0402 if (esw_mc)
0403 goto add;
0404
0405 esw_mc = l2addr_hash_add(hash, mac, struct esw_mc_addr, GFP_KERNEL);
0406 if (!esw_mc)
0407 return -ENOMEM;
0408
0409 esw_mc->uplink_rule =
0410 esw_fdb_set_vport_rule(esw, mac, MLX5_VPORT_UPLINK);
0411
0412
0413 update_allmulti_vports(esw, vaddr, esw_mc);
0414
0415 add:
0416
0417
0418
0419 if (!vaddr->mc_promisc)
0420 esw_mc->refcnt++;
0421
0422
0423 vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
0424 esw_debug(esw->dev,
0425 "\tADDED MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
0426 vport, mac, vaddr->flow_rule,
0427 esw_mc->refcnt, esw_mc->uplink_rule);
0428 return 0;
0429 }
0430
0431 static int esw_del_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
0432 {
0433 struct hlist_head *hash = esw->mc_table;
0434 struct esw_mc_addr *esw_mc;
0435 u8 *mac = vaddr->node.addr;
0436 u16 vport = vaddr->vport;
0437
0438 if (!esw->fdb_table.legacy.fdb)
0439 return 0;
0440
0441 esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);
0442 if (!esw_mc) {
0443 esw_warn(esw->dev,
0444 "Failed to find eswitch MC addr for MAC(%pM) vport(%d)",
0445 mac, vport);
0446 return -EINVAL;
0447 }
0448 esw_debug(esw->dev,
0449 "\tDELETE MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
0450 vport, mac, vaddr->flow_rule, esw_mc->refcnt,
0451 esw_mc->uplink_rule);
0452
0453 if (vaddr->flow_rule)
0454 mlx5_del_flow_rules(vaddr->flow_rule);
0455 vaddr->flow_rule = NULL;
0456
0457
0458
0459
0460 if (vaddr->mc_promisc || (--esw_mc->refcnt > 0))
0461 return 0;
0462
0463
0464 update_allmulti_vports(esw, vaddr, esw_mc);
0465
0466 if (esw_mc->uplink_rule)
0467 mlx5_del_flow_rules(esw_mc->uplink_rule);
0468
0469 l2addr_hash_del(esw_mc);
0470 return 0;
0471 }
0472
0473
0474 static void esw_apply_vport_addr_list(struct mlx5_eswitch *esw,
0475 struct mlx5_vport *vport, int list_type)
0476 {
0477 bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;
0478 vport_addr_action vport_addr_add;
0479 vport_addr_action vport_addr_del;
0480 struct vport_addr *addr;
0481 struct l2addr_node *node;
0482 struct hlist_head *hash;
0483 struct hlist_node *tmp;
0484 int hi;
0485
0486 vport_addr_add = is_uc ? esw_add_uc_addr :
0487 esw_add_mc_addr;
0488 vport_addr_del = is_uc ? esw_del_uc_addr :
0489 esw_del_mc_addr;
0490
0491 hash = is_uc ? vport->uc_list : vport->mc_list;
0492 for_each_l2hash_node(node, tmp, hash, hi) {
0493 addr = container_of(node, struct vport_addr, node);
0494 switch (addr->action) {
0495 case MLX5_ACTION_ADD:
0496 vport_addr_add(esw, addr);
0497 addr->action = MLX5_ACTION_NONE;
0498 break;
0499 case MLX5_ACTION_DEL:
0500 vport_addr_del(esw, addr);
0501 l2addr_hash_del(addr);
0502 break;
0503 }
0504 }
0505 }
0506
0507
0508 static void esw_update_vport_addr_list(struct mlx5_eswitch *esw,
0509 struct mlx5_vport *vport, int list_type)
0510 {
0511 bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;
0512 u8 (*mac_list)[ETH_ALEN];
0513 struct l2addr_node *node;
0514 struct vport_addr *addr;
0515 struct hlist_head *hash;
0516 struct hlist_node *tmp;
0517 int size;
0518 int err;
0519 int hi;
0520 int i;
0521
0522 size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) :
0523 MLX5_MAX_MC_PER_VPORT(esw->dev);
0524
0525 mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL);
0526 if (!mac_list)
0527 return;
0528
0529 hash = is_uc ? vport->uc_list : vport->mc_list;
0530
0531 for_each_l2hash_node(node, tmp, hash, hi) {
0532 addr = container_of(node, struct vport_addr, node);
0533 addr->action = MLX5_ACTION_DEL;
0534 }
0535
0536 if (!vport->enabled)
0537 goto out;
0538
0539 err = mlx5_query_nic_vport_mac_list(esw->dev, vport->vport, list_type,
0540 mac_list, &size);
0541 if (err)
0542 goto out;
0543 esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n",
0544 vport->vport, is_uc ? "UC" : "MC", size);
0545
0546 for (i = 0; i < size; i++) {
0547 if (is_uc && !is_valid_ether_addr(mac_list[i]))
0548 continue;
0549
0550 if (!is_uc && !is_multicast_ether_addr(mac_list[i]))
0551 continue;
0552
0553 addr = l2addr_hash_find(hash, mac_list[i], struct vport_addr);
0554 if (addr) {
0555 addr->action = MLX5_ACTION_NONE;
0556
0557
0558
0559
0560 if (addr->mc_promisc) {
0561 struct esw_mc_addr *esw_mc =
0562 l2addr_hash_find(esw->mc_table,
0563 mac_list[i],
0564 struct esw_mc_addr);
0565 if (!esw_mc) {
0566 esw_warn(esw->dev,
0567 "Failed to MAC(%pM) in mcast DB\n",
0568 mac_list[i]);
0569 continue;
0570 }
0571 esw_mc->refcnt++;
0572 addr->mc_promisc = false;
0573 }
0574 continue;
0575 }
0576
0577 addr = l2addr_hash_add(hash, mac_list[i], struct vport_addr,
0578 GFP_KERNEL);
0579 if (!addr) {
0580 esw_warn(esw->dev,
0581 "Failed to add MAC(%pM) to vport[%d] DB\n",
0582 mac_list[i], vport->vport);
0583 continue;
0584 }
0585 addr->vport = vport->vport;
0586 addr->action = MLX5_ACTION_ADD;
0587 }
0588 out:
0589 kfree(mac_list);
0590 }
0591
0592
0593
0594
0595 static void esw_update_vport_mc_promisc(struct mlx5_eswitch *esw,
0596 struct mlx5_vport *vport)
0597 {
0598 struct l2addr_node *node;
0599 struct vport_addr *addr;
0600 struct hlist_head *hash;
0601 struct hlist_node *tmp;
0602 int hi;
0603
0604 hash = vport->mc_list;
0605
0606 for_each_l2hash_node(node, tmp, esw->mc_table, hi) {
0607 u8 *mac = node->addr;
0608
0609 addr = l2addr_hash_find(hash, mac, struct vport_addr);
0610 if (addr) {
0611 if (addr->action == MLX5_ACTION_DEL)
0612 addr->action = MLX5_ACTION_NONE;
0613 continue;
0614 }
0615 addr = l2addr_hash_add(hash, mac, struct vport_addr,
0616 GFP_KERNEL);
0617 if (!addr) {
0618 esw_warn(esw->dev,
0619 "Failed to add allmulti MAC(%pM) to vport[%d] DB\n",
0620 mac, vport->vport);
0621 continue;
0622 }
0623 addr->vport = vport->vport;
0624 addr->action = MLX5_ACTION_ADD;
0625 addr->mc_promisc = true;
0626 }
0627 }
0628
0629
0630 static void esw_apply_vport_rx_mode(struct mlx5_eswitch *esw,
0631 struct mlx5_vport *vport,
0632 bool promisc, bool mc_promisc)
0633 {
0634 struct esw_mc_addr *allmulti_addr = &esw->mc_promisc;
0635
0636 if (IS_ERR_OR_NULL(vport->allmulti_rule) != mc_promisc)
0637 goto promisc;
0638
0639 if (mc_promisc) {
0640 vport->allmulti_rule =
0641 esw_fdb_set_vport_allmulti_rule(esw, vport->vport);
0642 if (!allmulti_addr->uplink_rule)
0643 allmulti_addr->uplink_rule =
0644 esw_fdb_set_vport_allmulti_rule(esw,
0645 MLX5_VPORT_UPLINK);
0646 allmulti_addr->refcnt++;
0647 } else if (vport->allmulti_rule) {
0648 mlx5_del_flow_rules(vport->allmulti_rule);
0649 vport->allmulti_rule = NULL;
0650
0651 if (--allmulti_addr->refcnt > 0)
0652 goto promisc;
0653
0654 if (allmulti_addr->uplink_rule)
0655 mlx5_del_flow_rules(allmulti_addr->uplink_rule);
0656 allmulti_addr->uplink_rule = NULL;
0657 }
0658
0659 promisc:
0660 if (IS_ERR_OR_NULL(vport->promisc_rule) != promisc)
0661 return;
0662
0663 if (promisc) {
0664 vport->promisc_rule =
0665 esw_fdb_set_vport_promisc_rule(esw, vport->vport);
0666 } else if (vport->promisc_rule) {
0667 mlx5_del_flow_rules(vport->promisc_rule);
0668 vport->promisc_rule = NULL;
0669 }
0670 }
0671
0672
0673 static void esw_update_vport_rx_mode(struct mlx5_eswitch *esw,
0674 struct mlx5_vport *vport)
0675 {
0676 int promisc_all = 0;
0677 int promisc_uc = 0;
0678 int promisc_mc = 0;
0679 int err;
0680
0681 err = mlx5_query_nic_vport_promisc(esw->dev,
0682 vport->vport,
0683 &promisc_uc,
0684 &promisc_mc,
0685 &promisc_all);
0686 if (err)
0687 return;
0688 esw_debug(esw->dev, "vport[%d] context update rx mode promisc_all=%d, all_multi=%d\n",
0689 vport->vport, promisc_all, promisc_mc);
0690
0691 if (!vport->info.trusted || !vport->enabled) {
0692 promisc_uc = 0;
0693 promisc_mc = 0;
0694 promisc_all = 0;
0695 }
0696
0697 esw_apply_vport_rx_mode(esw, vport, promisc_all,
0698 (promisc_all || promisc_mc));
0699 }
0700
0701 void esw_vport_change_handle_locked(struct mlx5_vport *vport)
0702 {
0703 struct mlx5_core_dev *dev = vport->dev;
0704 struct mlx5_eswitch *esw = dev->priv.eswitch;
0705 u8 mac[ETH_ALEN];
0706
0707 mlx5_query_nic_vport_mac_address(dev, vport->vport, true, mac);
0708 esw_debug(dev, "vport[%d] Context Changed: perm mac: %pM\n",
0709 vport->vport, mac);
0710
0711 if (vport->enabled_events & MLX5_VPORT_UC_ADDR_CHANGE) {
0712 esw_update_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_UC);
0713 esw_apply_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_UC);
0714 }
0715
0716 if (vport->enabled_events & MLX5_VPORT_MC_ADDR_CHANGE)
0717 esw_update_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_MC);
0718
0719 if (vport->enabled_events & MLX5_VPORT_PROMISC_CHANGE) {
0720 esw_update_vport_rx_mode(esw, vport);
0721 if (!IS_ERR_OR_NULL(vport->allmulti_rule))
0722 esw_update_vport_mc_promisc(esw, vport);
0723 }
0724
0725 if (vport->enabled_events & (MLX5_VPORT_PROMISC_CHANGE | MLX5_VPORT_MC_ADDR_CHANGE))
0726 esw_apply_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_MC);
0727
0728 esw_debug(esw->dev, "vport[%d] Context Changed: Done\n", vport->vport);
0729 if (vport->enabled)
0730 arm_vport_context_events_cmd(dev, vport->vport,
0731 vport->enabled_events);
0732 }
0733
0734 static void esw_vport_change_handler(struct work_struct *work)
0735 {
0736 struct mlx5_vport *vport =
0737 container_of(work, struct mlx5_vport, vport_change_handler);
0738 struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
0739
0740 mutex_lock(&esw->state_lock);
0741 esw_vport_change_handle_locked(vport);
0742 mutex_unlock(&esw->state_lock);
0743 }
0744
0745 static void node_guid_gen_from_mac(u64 *node_guid, const u8 *mac)
0746 {
0747 ((u8 *)node_guid)[7] = mac[0];
0748 ((u8 *)node_guid)[6] = mac[1];
0749 ((u8 *)node_guid)[5] = mac[2];
0750 ((u8 *)node_guid)[4] = 0xff;
0751 ((u8 *)node_guid)[3] = 0xfe;
0752 ((u8 *)node_guid)[2] = mac[3];
0753 ((u8 *)node_guid)[1] = mac[4];
0754 ((u8 *)node_guid)[0] = mac[5];
0755 }
0756
0757 static int esw_vport_setup_acl(struct mlx5_eswitch *esw,
0758 struct mlx5_vport *vport)
0759 {
0760 if (esw->mode == MLX5_ESWITCH_LEGACY)
0761 return esw_legacy_vport_acl_setup(esw, vport);
0762 else
0763 return esw_vport_create_offloads_acl_tables(esw, vport);
0764 }
0765
0766 static void esw_vport_cleanup_acl(struct mlx5_eswitch *esw,
0767 struct mlx5_vport *vport)
0768 {
0769 if (esw->mode == MLX5_ESWITCH_LEGACY)
0770 esw_legacy_vport_acl_cleanup(esw, vport);
0771 else
0772 esw_vport_destroy_offloads_acl_tables(esw, vport);
0773 }
0774
0775 static int esw_vport_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
0776 {
0777 u16 vport_num = vport->vport;
0778 int flags;
0779 int err;
0780
0781 err = esw_vport_setup_acl(esw, vport);
0782 if (err)
0783 return err;
0784
0785 if (mlx5_esw_is_manager_vport(esw, vport_num))
0786 return 0;
0787
0788 mlx5_modify_vport_admin_state(esw->dev,
0789 MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,
0790 vport_num, 1,
0791 vport->info.link_state);
0792
0793
0794 if (vport_num) {
0795 mlx5_modify_nic_vport_mac_address(esw->dev, vport_num,
0796 vport->info.mac);
0797 mlx5_modify_nic_vport_node_guid(esw->dev, vport_num,
0798 vport->info.node_guid);
0799 }
0800
0801 flags = (vport->info.vlan || vport->info.qos) ?
0802 SET_VLAN_STRIP | SET_VLAN_INSERT : 0;
0803 modify_esw_vport_cvlan(esw->dev, vport_num, vport->info.vlan,
0804 vport->info.qos, flags);
0805
0806 return 0;
0807 }
0808
0809
0810 static void esw_vport_cleanup(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
0811 {
0812 u16 vport_num = vport->vport;
0813
0814 if (!mlx5_esw_is_manager_vport(esw, vport_num))
0815 mlx5_modify_vport_admin_state(esw->dev,
0816 MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,
0817 vport_num, 1,
0818 MLX5_VPORT_ADMIN_STATE_DOWN);
0819
0820 mlx5_esw_qos_vport_disable(esw, vport);
0821 esw_vport_cleanup_acl(esw, vport);
0822 }
0823
0824 int mlx5_esw_vport_enable(struct mlx5_eswitch *esw, u16 vport_num,
0825 enum mlx5_eswitch_vport_event enabled_events)
0826 {
0827 struct mlx5_vport *vport;
0828 int ret;
0829
0830 vport = mlx5_eswitch_get_vport(esw, vport_num);
0831 if (IS_ERR(vport))
0832 return PTR_ERR(vport);
0833
0834 mutex_lock(&esw->state_lock);
0835 WARN_ON(vport->enabled);
0836
0837 esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num);
0838
0839 ret = esw_vport_setup(esw, vport);
0840 if (ret)
0841 goto done;
0842
0843
0844 vport->enabled_events = enabled_events;
0845 vport->enabled = true;
0846
0847
0848
0849
0850 if (mlx5_esw_is_manager_vport(esw, vport_num) ||
0851 (!vport_num && mlx5_core_is_ecpf(esw->dev)))
0852 vport->info.trusted = true;
0853
0854 if (!mlx5_esw_is_manager_vport(esw, vport->vport) &&
0855 MLX5_CAP_GEN(esw->dev, vhca_resource_manager)) {
0856 ret = mlx5_esw_vport_vhca_id_set(esw, vport_num);
0857 if (ret)
0858 goto err_vhca_mapping;
0859 }
0860
0861
0862
0863
0864 if (mlx5_core_is_ecpf(esw->dev) && vport_num == MLX5_VPORT_PF)
0865 mlx5_query_nic_vport_mac_address(esw->dev, vport_num, true, vport->info.mac);
0866
0867 esw_vport_change_handle_locked(vport);
0868
0869 esw->enabled_vports++;
0870 esw_debug(esw->dev, "Enabled VPORT(%d)\n", vport_num);
0871 done:
0872 mutex_unlock(&esw->state_lock);
0873 return ret;
0874
0875 err_vhca_mapping:
0876 esw_vport_cleanup(esw, vport);
0877 mutex_unlock(&esw->state_lock);
0878 return ret;
0879 }
0880
0881 void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, u16 vport_num)
0882 {
0883 struct mlx5_vport *vport;
0884
0885 vport = mlx5_eswitch_get_vport(esw, vport_num);
0886 if (IS_ERR(vport))
0887 return;
0888
0889 mutex_lock(&esw->state_lock);
0890 if (!vport->enabled)
0891 goto done;
0892
0893 esw_debug(esw->dev, "Disabling vport(%d)\n", vport_num);
0894
0895 vport->enabled = false;
0896
0897
0898 arm_vport_context_events_cmd(esw->dev, vport->vport, 0);
0899
0900 if (!mlx5_esw_is_manager_vport(esw, vport->vport) &&
0901 MLX5_CAP_GEN(esw->dev, vhca_resource_manager))
0902 mlx5_esw_vport_vhca_id_clear(esw, vport_num);
0903
0904
0905
0906
0907
0908 esw_vport_change_handle_locked(vport);
0909 vport->enabled_events = 0;
0910 esw_vport_cleanup(esw, vport);
0911 esw->enabled_vports--;
0912
0913 done:
0914 mutex_unlock(&esw->state_lock);
0915 }
0916
0917 static int eswitch_vport_event(struct notifier_block *nb,
0918 unsigned long type, void *data)
0919 {
0920 struct mlx5_eswitch *esw = mlx5_nb_cof(nb, struct mlx5_eswitch, nb);
0921 struct mlx5_eqe *eqe = data;
0922 struct mlx5_vport *vport;
0923 u16 vport_num;
0924
0925 vport_num = be16_to_cpu(eqe->data.vport_change.vport_num);
0926 vport = mlx5_eswitch_get_vport(esw, vport_num);
0927 if (!IS_ERR(vport))
0928 queue_work(esw->work_queue, &vport->vport_change_handler);
0929 return NOTIFY_OK;
0930 }
0931
0932
0933
0934
0935
0936
0937
0938
0939
0940 const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev)
0941 {
0942 int outlen = MLX5_ST_SZ_BYTES(query_esw_functions_out);
0943 u32 in[MLX5_ST_SZ_DW(query_esw_functions_in)] = {};
0944 u32 *out;
0945 int err;
0946
0947 out = kvzalloc(outlen, GFP_KERNEL);
0948 if (!out)
0949 return ERR_PTR(-ENOMEM);
0950
0951 MLX5_SET(query_esw_functions_in, in, opcode,
0952 MLX5_CMD_OP_QUERY_ESW_FUNCTIONS);
0953
0954 err = mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
0955 if (!err)
0956 return out;
0957
0958 kvfree(out);
0959 return ERR_PTR(err);
0960 }
0961
0962 static void mlx5_eswitch_event_handlers_register(struct mlx5_eswitch *esw)
0963 {
0964 MLX5_NB_INIT(&esw->nb, eswitch_vport_event, NIC_VPORT_CHANGE);
0965 mlx5_eq_notifier_register(esw->dev, &esw->nb);
0966
0967 if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev)) {
0968 MLX5_NB_INIT(&esw->esw_funcs.nb, mlx5_esw_funcs_changed_handler,
0969 ESW_FUNCTIONS_CHANGED);
0970 mlx5_eq_notifier_register(esw->dev, &esw->esw_funcs.nb);
0971 }
0972 }
0973
0974 static void mlx5_eswitch_event_handlers_unregister(struct mlx5_eswitch *esw)
0975 {
0976 if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev))
0977 mlx5_eq_notifier_unregister(esw->dev, &esw->esw_funcs.nb);
0978
0979 mlx5_eq_notifier_unregister(esw->dev, &esw->nb);
0980
0981 flush_workqueue(esw->work_queue);
0982 }
0983
0984 static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch *esw)
0985 {
0986 struct mlx5_vport *vport;
0987 unsigned long i;
0988
0989 mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) {
0990 memset(&vport->qos, 0, sizeof(vport->qos));
0991 memset(&vport->info, 0, sizeof(vport->info));
0992 vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO;
0993 }
0994 }
0995
0996
0997 int mlx5_eswitch_load_vport(struct mlx5_eswitch *esw, u16 vport_num,
0998 enum mlx5_eswitch_vport_event enabled_events)
0999 {
1000 int err;
1001
1002 err = mlx5_esw_vport_enable(esw, vport_num, enabled_events);
1003 if (err)
1004 return err;
1005
1006 mlx5_esw_vport_debugfs_create(esw, vport_num, false, 0);
1007 err = esw_offloads_load_rep(esw, vport_num);
1008 if (err)
1009 goto err_rep;
1010
1011 return err;
1012
1013 err_rep:
1014 mlx5_esw_vport_debugfs_destroy(esw, vport_num);
1015 mlx5_esw_vport_disable(esw, vport_num);
1016 return err;
1017 }
1018
1019 void mlx5_eswitch_unload_vport(struct mlx5_eswitch *esw, u16 vport_num)
1020 {
1021 esw_offloads_unload_rep(esw, vport_num);
1022 mlx5_esw_vport_debugfs_destroy(esw, vport_num);
1023 mlx5_esw_vport_disable(esw, vport_num);
1024 }
1025
1026 void mlx5_eswitch_unload_vf_vports(struct mlx5_eswitch *esw, u16 num_vfs)
1027 {
1028 struct mlx5_vport *vport;
1029 unsigned long i;
1030
1031 mlx5_esw_for_each_vf_vport(esw, i, vport, num_vfs) {
1032 if (!vport->enabled)
1033 continue;
1034 mlx5_eswitch_unload_vport(esw, vport->vport);
1035 }
1036 }
1037
1038 int mlx5_eswitch_load_vf_vports(struct mlx5_eswitch *esw, u16 num_vfs,
1039 enum mlx5_eswitch_vport_event enabled_events)
1040 {
1041 struct mlx5_vport *vport;
1042 unsigned long i;
1043 int err;
1044
1045 mlx5_esw_for_each_vf_vport(esw, i, vport, num_vfs) {
1046 err = mlx5_eswitch_load_vport(esw, vport->vport, enabled_events);
1047 if (err)
1048 goto vf_err;
1049 }
1050
1051 return 0;
1052
1053 vf_err:
1054 mlx5_eswitch_unload_vf_vports(esw, num_vfs);
1055 return err;
1056 }
1057
1058 static int host_pf_enable_hca(struct mlx5_core_dev *dev)
1059 {
1060 if (!mlx5_core_is_ecpf(dev))
1061 return 0;
1062
1063
1064
1065
1066
1067 return mlx5_cmd_host_pf_enable_hca(dev);
1068 }
1069
1070 static void host_pf_disable_hca(struct mlx5_core_dev *dev)
1071 {
1072 if (!mlx5_core_is_ecpf(dev))
1073 return;
1074
1075 mlx5_cmd_host_pf_disable_hca(dev);
1076 }
1077
1078
1079
1080
1081 int
1082 mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw,
1083 enum mlx5_eswitch_vport_event enabled_events)
1084 {
1085 int ret;
1086
1087
1088 ret = mlx5_eswitch_load_vport(esw, MLX5_VPORT_PF, enabled_events);
1089 if (ret)
1090 return ret;
1091
1092
1093 ret = host_pf_enable_hca(esw->dev);
1094 if (ret)
1095 goto pf_hca_err;
1096
1097
1098 if (mlx5_ecpf_vport_exists(esw->dev)) {
1099 ret = mlx5_eswitch_load_vport(esw, MLX5_VPORT_ECPF, enabled_events);
1100 if (ret)
1101 goto ecpf_err;
1102 }
1103
1104
1105 ret = mlx5_eswitch_load_vf_vports(esw, esw->esw_funcs.num_vfs,
1106 enabled_events);
1107 if (ret)
1108 goto vf_err;
1109 return 0;
1110
1111 vf_err:
1112 if (mlx5_ecpf_vport_exists(esw->dev))
1113 mlx5_eswitch_unload_vport(esw, MLX5_VPORT_ECPF);
1114 ecpf_err:
1115 host_pf_disable_hca(esw->dev);
1116 pf_hca_err:
1117 mlx5_eswitch_unload_vport(esw, MLX5_VPORT_PF);
1118 return ret;
1119 }
1120
1121
1122
1123
1124 void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw)
1125 {
1126 mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs);
1127
1128 if (mlx5_ecpf_vport_exists(esw->dev))
1129 mlx5_eswitch_unload_vport(esw, MLX5_VPORT_ECPF);
1130
1131 host_pf_disable_hca(esw->dev);
1132 mlx5_eswitch_unload_vport(esw, MLX5_VPORT_PF);
1133 }
1134
1135 static void mlx5_eswitch_get_devlink_param(struct mlx5_eswitch *esw)
1136 {
1137 struct devlink *devlink = priv_to_devlink(esw->dev);
1138 union devlink_param_value val;
1139 int err;
1140
1141 err = devlink_param_driverinit_value_get(devlink,
1142 MLX5_DEVLINK_PARAM_ID_ESW_LARGE_GROUP_NUM,
1143 &val);
1144 if (!err) {
1145 esw->params.large_group_num = val.vu32;
1146 } else {
1147 esw_warn(esw->dev,
1148 "Devlink can't get param fdb_large_groups, uses default (%d).\n",
1149 ESW_OFFLOADS_DEFAULT_NUM_GROUPS);
1150 esw->params.large_group_num = ESW_OFFLOADS_DEFAULT_NUM_GROUPS;
1151 }
1152 }
1153
1154 static void
1155 mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, int num_vfs)
1156 {
1157 const u32 *out;
1158
1159 if (num_vfs < 0)
1160 return;
1161
1162 if (!mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1163 esw->esw_funcs.num_vfs = num_vfs;
1164 return;
1165 }
1166
1167 out = mlx5_esw_query_functions(esw->dev);
1168 if (IS_ERR(out))
1169 return;
1170
1171 esw->esw_funcs.num_vfs = MLX5_GET(query_esw_functions_out, out,
1172 host_params_context.host_num_of_vfs);
1173 kvfree(out);
1174 }
1175
1176 static void mlx5_esw_mode_change_notify(struct mlx5_eswitch *esw, u16 mode)
1177 {
1178 struct mlx5_esw_event_info info = {};
1179
1180 info.new_mode = mode;
1181
1182 blocking_notifier_call_chain(&esw->n_head, 0, &info);
1183 }
1184
1185 static int mlx5_esw_acls_ns_init(struct mlx5_eswitch *esw)
1186 {
1187 struct mlx5_core_dev *dev = esw->dev;
1188 int total_vports;
1189 int err;
1190
1191 if (esw->flags & MLX5_ESWITCH_VPORT_ACL_NS_CREATED)
1192 return 0;
1193
1194 total_vports = mlx5_eswitch_get_total_vports(dev);
1195
1196 if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support)) {
1197 err = mlx5_fs_egress_acls_init(dev, total_vports);
1198 if (err)
1199 return err;
1200 } else {
1201 esw_warn(dev, "engress ACL is not supported by FW\n");
1202 }
1203
1204 if (MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support)) {
1205 err = mlx5_fs_ingress_acls_init(dev, total_vports);
1206 if (err)
1207 goto err;
1208 } else {
1209 esw_warn(dev, "ingress ACL is not supported by FW\n");
1210 }
1211 esw->flags |= MLX5_ESWITCH_VPORT_ACL_NS_CREATED;
1212 return 0;
1213
1214 err:
1215 if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support))
1216 mlx5_fs_egress_acls_cleanup(dev);
1217 return err;
1218 }
1219
1220 static void mlx5_esw_acls_ns_cleanup(struct mlx5_eswitch *esw)
1221 {
1222 struct mlx5_core_dev *dev = esw->dev;
1223
1224 esw->flags &= ~MLX5_ESWITCH_VPORT_ACL_NS_CREATED;
1225 if (MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support))
1226 mlx5_fs_ingress_acls_cleanup(dev);
1227 if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support))
1228 mlx5_fs_egress_acls_cleanup(dev);
1229 }
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247 int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs)
1248 {
1249 int err;
1250
1251 lockdep_assert_held(&esw->mode_lock);
1252
1253 if (!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) {
1254 esw_warn(esw->dev, "FDB is not supported, aborting ...\n");
1255 return -EOPNOTSUPP;
1256 }
1257
1258 mlx5_eswitch_get_devlink_param(esw);
1259
1260 err = mlx5_esw_acls_ns_init(esw);
1261 if (err)
1262 return err;
1263
1264 mlx5_eswitch_update_num_of_vfs(esw, num_vfs);
1265
1266 if (esw->mode == MLX5_ESWITCH_LEGACY) {
1267 err = esw_legacy_enable(esw);
1268 } else {
1269 mlx5_rescan_drivers(esw->dev);
1270 err = esw_offloads_enable(esw);
1271 }
1272
1273 if (err)
1274 goto abort;
1275
1276 esw->fdb_table.flags |= MLX5_ESW_FDB_CREATED;
1277
1278 mlx5_eswitch_event_handlers_register(esw);
1279
1280 esw_info(esw->dev, "Enable: mode(%s), nvfs(%d), active vports(%d)\n",
1281 esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
1282 esw->esw_funcs.num_vfs, esw->enabled_vports);
1283
1284 mlx5_esw_mode_change_notify(esw, esw->mode);
1285
1286 return 0;
1287
1288 abort:
1289 mlx5_esw_acls_ns_cleanup(esw);
1290 return err;
1291 }
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301 int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs)
1302 {
1303 bool toggle_lag;
1304 int ret;
1305
1306 if (!mlx5_esw_allowed(esw))
1307 return 0;
1308
1309 devl_assert_locked(priv_to_devlink(esw->dev));
1310
1311 toggle_lag = !mlx5_esw_is_fdb_created(esw);
1312
1313 if (toggle_lag)
1314 mlx5_lag_disable_change(esw->dev);
1315
1316 down_write(&esw->mode_lock);
1317 if (!mlx5_esw_is_fdb_created(esw)) {
1318 ret = mlx5_eswitch_enable_locked(esw, num_vfs);
1319 } else {
1320 enum mlx5_eswitch_vport_event vport_events;
1321
1322 vport_events = (esw->mode == MLX5_ESWITCH_LEGACY) ?
1323 MLX5_LEGACY_SRIOV_VPORT_EVENTS : MLX5_VPORT_UC_ADDR_CHANGE;
1324 ret = mlx5_eswitch_load_vf_vports(esw, num_vfs, vport_events);
1325 if (!ret)
1326 esw->esw_funcs.num_vfs = num_vfs;
1327 }
1328 up_write(&esw->mode_lock);
1329
1330 if (toggle_lag)
1331 mlx5_lag_enable_change(esw->dev);
1332
1333 return ret;
1334 }
1335
1336
1337 void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf)
1338 {
1339 if (!mlx5_esw_allowed(esw))
1340 return;
1341
1342 devl_assert_locked(priv_to_devlink(esw->dev));
1343 down_write(&esw->mode_lock);
1344
1345
1346
1347 if (!esw->esw_funcs.num_vfs && !clear_vf)
1348 goto unlock;
1349
1350 esw_info(esw->dev, "Unload vfs: mode(%s), nvfs(%d), active vports(%d)\n",
1351 esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
1352 esw->esw_funcs.num_vfs, esw->enabled_vports);
1353
1354 mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs);
1355 if (clear_vf)
1356 mlx5_eswitch_clear_vf_vports_info(esw);
1357
1358
1359
1360 if (esw->mode == MLX5_ESWITCH_OFFLOADS) {
1361 struct devlink *devlink = priv_to_devlink(esw->dev);
1362
1363 esw_offloads_del_send_to_vport_meta_rules(esw);
1364 devl_rate_nodes_destroy(devlink);
1365 }
1366
1367 esw->esw_funcs.num_vfs = 0;
1368
1369 unlock:
1370 up_write(&esw->mode_lock);
1371 }
1372
1373
1374
1375
1376 void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw)
1377 {
1378 struct devlink *devlink = priv_to_devlink(esw->dev);
1379
1380
1381
1382
1383 mlx5_esw_mode_change_notify(esw, MLX5_ESWITCH_LEGACY);
1384
1385 mlx5_eswitch_event_handlers_unregister(esw);
1386
1387 esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), active vports(%d)\n",
1388 esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
1389 esw->esw_funcs.num_vfs, esw->enabled_vports);
1390
1391 esw->fdb_table.flags &= ~MLX5_ESW_FDB_CREATED;
1392 if (esw->mode == MLX5_ESWITCH_OFFLOADS)
1393 esw_offloads_disable(esw);
1394 else if (esw->mode == MLX5_ESWITCH_LEGACY)
1395 esw_legacy_disable(esw);
1396 mlx5_esw_acls_ns_cleanup(esw);
1397
1398 if (esw->mode == MLX5_ESWITCH_OFFLOADS)
1399 devl_rate_nodes_destroy(devlink);
1400 }
1401
1402 void mlx5_eswitch_disable(struct mlx5_eswitch *esw)
1403 {
1404 if (!mlx5_esw_allowed(esw))
1405 return;
1406
1407 devl_assert_locked(priv_to_devlink(esw->dev));
1408 mlx5_lag_disable_change(esw->dev);
1409 down_write(&esw->mode_lock);
1410 mlx5_eswitch_disable_locked(esw);
1411 up_write(&esw->mode_lock);
1412 mlx5_lag_enable_change(esw->dev);
1413 }
1414
1415 static int mlx5_query_hca_cap_host_pf(struct mlx5_core_dev *dev, void *out)
1416 {
1417 u16 opmod = (MLX5_CAP_GENERAL << 1) | (HCA_CAP_OPMOD_GET_MAX & 0x01);
1418 u8 in[MLX5_ST_SZ_BYTES(query_hca_cap_in)] = {};
1419
1420 MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP);
1421 MLX5_SET(query_hca_cap_in, in, op_mod, opmod);
1422 MLX5_SET(query_hca_cap_in, in, function_id, MLX5_VPORT_PF);
1423 MLX5_SET(query_hca_cap_in, in, other_function, true);
1424 return mlx5_cmd_exec_inout(dev, query_hca_cap, in, out);
1425 }
1426
1427 int mlx5_esw_sf_max_hpf_functions(struct mlx5_core_dev *dev, u16 *max_sfs, u16 *sf_base_id)
1428
1429 {
1430 int query_out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
1431 void *query_ctx;
1432 void *hca_caps;
1433 int err;
1434
1435 if (!mlx5_core_is_ecpf(dev)) {
1436 *max_sfs = 0;
1437 return 0;
1438 }
1439
1440 query_ctx = kzalloc(query_out_sz, GFP_KERNEL);
1441 if (!query_ctx)
1442 return -ENOMEM;
1443
1444 err = mlx5_query_hca_cap_host_pf(dev, query_ctx);
1445 if (err)
1446 goto out_free;
1447
1448 hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);
1449 *max_sfs = MLX5_GET(cmd_hca_cap, hca_caps, max_num_sf);
1450 *sf_base_id = MLX5_GET(cmd_hca_cap, hca_caps, sf_base_id);
1451
1452 out_free:
1453 kfree(query_ctx);
1454 return err;
1455 }
1456
1457 static int mlx5_esw_vport_alloc(struct mlx5_eswitch *esw, struct mlx5_core_dev *dev,
1458 int index, u16 vport_num)
1459 {
1460 struct mlx5_vport *vport;
1461 int err;
1462
1463 vport = kzalloc(sizeof(*vport), GFP_KERNEL);
1464 if (!vport)
1465 return -ENOMEM;
1466
1467 vport->dev = esw->dev;
1468 vport->vport = vport_num;
1469 vport->index = index;
1470 vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO;
1471 INIT_WORK(&vport->vport_change_handler, esw_vport_change_handler);
1472 err = xa_insert(&esw->vports, vport_num, vport, GFP_KERNEL);
1473 if (err)
1474 goto insert_err;
1475
1476 esw->total_vports++;
1477 return 0;
1478
1479 insert_err:
1480 kfree(vport);
1481 return err;
1482 }
1483
1484 static void mlx5_esw_vport_free(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
1485 {
1486 xa_erase(&esw->vports, vport->vport);
1487 kfree(vport);
1488 }
1489
1490 static void mlx5_esw_vports_cleanup(struct mlx5_eswitch *esw)
1491 {
1492 struct mlx5_vport *vport;
1493 unsigned long i;
1494
1495 mlx5_esw_for_each_vport(esw, i, vport)
1496 mlx5_esw_vport_free(esw, vport);
1497 xa_destroy(&esw->vports);
1498 }
1499
1500 static int mlx5_esw_vports_init(struct mlx5_eswitch *esw)
1501 {
1502 struct mlx5_core_dev *dev = esw->dev;
1503 u16 max_host_pf_sfs;
1504 u16 base_sf_num;
1505 int idx = 0;
1506 int err;
1507 int i;
1508
1509 xa_init(&esw->vports);
1510
1511 err = mlx5_esw_vport_alloc(esw, dev, idx, MLX5_VPORT_PF);
1512 if (err)
1513 goto err;
1514 if (esw->first_host_vport == MLX5_VPORT_PF)
1515 xa_set_mark(&esw->vports, idx, MLX5_ESW_VPT_HOST_FN);
1516 idx++;
1517
1518 for (i = 0; i < mlx5_core_max_vfs(dev); i++) {
1519 err = mlx5_esw_vport_alloc(esw, dev, idx, idx);
1520 if (err)
1521 goto err;
1522 xa_set_mark(&esw->vports, idx, MLX5_ESW_VPT_VF);
1523 xa_set_mark(&esw->vports, idx, MLX5_ESW_VPT_HOST_FN);
1524 idx++;
1525 }
1526 base_sf_num = mlx5_sf_start_function_id(dev);
1527 for (i = 0; i < mlx5_sf_max_functions(dev); i++) {
1528 err = mlx5_esw_vport_alloc(esw, dev, idx, base_sf_num + i);
1529 if (err)
1530 goto err;
1531 xa_set_mark(&esw->vports, base_sf_num + i, MLX5_ESW_VPT_SF);
1532 idx++;
1533 }
1534
1535 err = mlx5_esw_sf_max_hpf_functions(dev, &max_host_pf_sfs, &base_sf_num);
1536 if (err)
1537 goto err;
1538 for (i = 0; i < max_host_pf_sfs; i++) {
1539 err = mlx5_esw_vport_alloc(esw, dev, idx, base_sf_num + i);
1540 if (err)
1541 goto err;
1542 xa_set_mark(&esw->vports, base_sf_num + i, MLX5_ESW_VPT_SF);
1543 idx++;
1544 }
1545
1546 if (mlx5_ecpf_vport_exists(dev)) {
1547 err = mlx5_esw_vport_alloc(esw, dev, idx, MLX5_VPORT_ECPF);
1548 if (err)
1549 goto err;
1550 idx++;
1551 }
1552 err = mlx5_esw_vport_alloc(esw, dev, idx, MLX5_VPORT_UPLINK);
1553 if (err)
1554 goto err;
1555 return 0;
1556
1557 err:
1558 mlx5_esw_vports_cleanup(esw);
1559 return err;
1560 }
1561
1562 int mlx5_eswitch_init(struct mlx5_core_dev *dev)
1563 {
1564 struct mlx5_eswitch *esw;
1565 int err;
1566
1567 if (!MLX5_VPORT_MANAGER(dev))
1568 return 0;
1569
1570 esw = kzalloc(sizeof(*esw), GFP_KERNEL);
1571 if (!esw)
1572 return -ENOMEM;
1573
1574 esw->dev = dev;
1575 esw->manager_vport = mlx5_eswitch_manager_vport(dev);
1576 esw->first_host_vport = mlx5_eswitch_first_host_vport_num(dev);
1577
1578 esw->work_queue = create_singlethread_workqueue("mlx5_esw_wq");
1579 if (!esw->work_queue) {
1580 err = -ENOMEM;
1581 goto abort;
1582 }
1583
1584 err = mlx5_esw_vports_init(esw);
1585 if (err)
1586 goto abort;
1587
1588 err = esw_offloads_init_reps(esw);
1589 if (err)
1590 goto reps_err;
1591
1592 mutex_init(&esw->offloads.encap_tbl_lock);
1593 hash_init(esw->offloads.encap_tbl);
1594 mutex_init(&esw->offloads.decap_tbl_lock);
1595 hash_init(esw->offloads.decap_tbl);
1596 mlx5e_mod_hdr_tbl_init(&esw->offloads.mod_hdr);
1597 atomic64_set(&esw->offloads.num_flows, 0);
1598 ida_init(&esw->offloads.vport_metadata_ida);
1599 xa_init_flags(&esw->offloads.vhca_map, XA_FLAGS_ALLOC);
1600 mutex_init(&esw->state_lock);
1601 init_rwsem(&esw->mode_lock);
1602 refcount_set(&esw->qos.refcnt, 0);
1603
1604 esw->enabled_vports = 0;
1605 esw->mode = MLX5_ESWITCH_LEGACY;
1606 esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE;
1607 if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) &&
1608 MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap))
1609 esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;
1610 else
1611 esw->offloads.encap = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
1612 if (MLX5_ESWITCH_MANAGER(dev) &&
1613 mlx5_esw_vport_match_metadata_supported(esw))
1614 esw->flags |= MLX5_ESWITCH_VPORT_MATCH_METADATA;
1615
1616 dev->priv.eswitch = esw;
1617 BLOCKING_INIT_NOTIFIER_HEAD(&esw->n_head);
1618
1619 esw->dbgfs = debugfs_create_dir("esw", mlx5_debugfs_get_dev_root(esw->dev));
1620 esw_info(dev,
1621 "Total vports %d, per vport: max uc(%d) max mc(%d)\n",
1622 esw->total_vports,
1623 MLX5_MAX_UC_PER_VPORT(dev),
1624 MLX5_MAX_MC_PER_VPORT(dev));
1625 return 0;
1626
1627 reps_err:
1628 mlx5_esw_vports_cleanup(esw);
1629 abort:
1630 if (esw->work_queue)
1631 destroy_workqueue(esw->work_queue);
1632 kfree(esw);
1633 return err;
1634 }
1635
1636 void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
1637 {
1638 if (!esw || !MLX5_VPORT_MANAGER(esw->dev))
1639 return;
1640
1641 esw_info(esw->dev, "cleanup\n");
1642
1643 debugfs_remove_recursive(esw->dbgfs);
1644 esw->dev->priv.eswitch = NULL;
1645 destroy_workqueue(esw->work_queue);
1646 WARN_ON(refcount_read(&esw->qos.refcnt));
1647 mutex_destroy(&esw->state_lock);
1648 WARN_ON(!xa_empty(&esw->offloads.vhca_map));
1649 xa_destroy(&esw->offloads.vhca_map);
1650 ida_destroy(&esw->offloads.vport_metadata_ida);
1651 mlx5e_mod_hdr_tbl_destroy(&esw->offloads.mod_hdr);
1652 mutex_destroy(&esw->offloads.encap_tbl_lock);
1653 mutex_destroy(&esw->offloads.decap_tbl_lock);
1654 esw_offloads_cleanup_reps(esw);
1655 mlx5_esw_vports_cleanup(esw);
1656 kfree(esw);
1657 }
1658
1659
1660 static int
1661 mlx5_esw_set_vport_mac_locked(struct mlx5_eswitch *esw,
1662 struct mlx5_vport *evport, const u8 *mac)
1663 {
1664 u16 vport_num = evport->vport;
1665 u64 node_guid;
1666 int err = 0;
1667
1668 if (is_multicast_ether_addr(mac))
1669 return -EINVAL;
1670
1671 if (evport->info.spoofchk && !is_valid_ether_addr(mac))
1672 mlx5_core_warn(esw->dev,
1673 "Set invalid MAC while spoofchk is on, vport(%d)\n",
1674 vport_num);
1675
1676 err = mlx5_modify_nic_vport_mac_address(esw->dev, vport_num, mac);
1677 if (err) {
1678 mlx5_core_warn(esw->dev,
1679 "Failed to mlx5_modify_nic_vport_mac vport(%d) err=(%d)\n",
1680 vport_num, err);
1681 return err;
1682 }
1683
1684 node_guid_gen_from_mac(&node_guid, mac);
1685 err = mlx5_modify_nic_vport_node_guid(esw->dev, vport_num, node_guid);
1686 if (err)
1687 mlx5_core_warn(esw->dev,
1688 "Failed to set vport %d node guid, err = %d. RDMA_CM will not function properly for this VF.\n",
1689 vport_num, err);
1690
1691 ether_addr_copy(evport->info.mac, mac);
1692 evport->info.node_guid = node_guid;
1693 if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY)
1694 err = esw_acl_ingress_lgcy_setup(esw, evport);
1695
1696 return err;
1697 }
1698
1699 int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
1700 u16 vport, const u8 *mac)
1701 {
1702 struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
1703 int err = 0;
1704
1705 if (IS_ERR(evport))
1706 return PTR_ERR(evport);
1707
1708 mutex_lock(&esw->state_lock);
1709 err = mlx5_esw_set_vport_mac_locked(esw, evport, mac);
1710 mutex_unlock(&esw->state_lock);
1711 return err;
1712 }
1713
1714 static bool mlx5_esw_check_port_type(struct mlx5_eswitch *esw, u16 vport_num, xa_mark_t mark)
1715 {
1716 struct mlx5_vport *vport;
1717
1718 vport = mlx5_eswitch_get_vport(esw, vport_num);
1719 if (IS_ERR(vport))
1720 return false;
1721
1722 return xa_get_mark(&esw->vports, vport_num, mark);
1723 }
1724
1725 bool mlx5_eswitch_is_vf_vport(struct mlx5_eswitch *esw, u16 vport_num)
1726 {
1727 return mlx5_esw_check_port_type(esw, vport_num, MLX5_ESW_VPT_VF);
1728 }
1729
1730 bool mlx5_esw_is_sf_vport(struct mlx5_eswitch *esw, u16 vport_num)
1731 {
1732 return mlx5_esw_check_port_type(esw, vport_num, MLX5_ESW_VPT_SF);
1733 }
1734
1735 int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
1736 u16 vport, int link_state)
1737 {
1738 struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
1739 int opmod = MLX5_VPORT_STATE_OP_MOD_ESW_VPORT;
1740 int other_vport = 1;
1741 int err = 0;
1742
1743 if (!mlx5_esw_allowed(esw))
1744 return -EPERM;
1745 if (IS_ERR(evport))
1746 return PTR_ERR(evport);
1747
1748 if (vport == MLX5_VPORT_UPLINK) {
1749 opmod = MLX5_VPORT_STATE_OP_MOD_UPLINK;
1750 other_vport = 0;
1751 vport = 0;
1752 }
1753 mutex_lock(&esw->state_lock);
1754 if (esw->mode != MLX5_ESWITCH_LEGACY) {
1755 err = -EOPNOTSUPP;
1756 goto unlock;
1757 }
1758
1759 err = mlx5_modify_vport_admin_state(esw->dev, opmod, vport, other_vport, link_state);
1760 if (err) {
1761 mlx5_core_warn(esw->dev, "Failed to set vport %d link state, opmod = %d, err = %d",
1762 vport, opmod, err);
1763 goto unlock;
1764 }
1765
1766 evport->info.link_state = link_state;
1767
1768 unlock:
1769 mutex_unlock(&esw->state_lock);
1770 return err;
1771 }
1772
1773 int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
1774 u16 vport, struct ifla_vf_info *ivi)
1775 {
1776 struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
1777
1778 if (IS_ERR(evport))
1779 return PTR_ERR(evport);
1780
1781 memset(ivi, 0, sizeof(*ivi));
1782 ivi->vf = vport - 1;
1783
1784 mutex_lock(&esw->state_lock);
1785 ether_addr_copy(ivi->mac, evport->info.mac);
1786 ivi->linkstate = evport->info.link_state;
1787 ivi->vlan = evport->info.vlan;
1788 ivi->qos = evport->info.qos;
1789 ivi->spoofchk = evport->info.spoofchk;
1790 ivi->trusted = evport->info.trusted;
1791 if (evport->qos.enabled) {
1792 ivi->min_tx_rate = evport->qos.min_rate;
1793 ivi->max_tx_rate = evport->qos.max_rate;
1794 }
1795 mutex_unlock(&esw->state_lock);
1796
1797 return 0;
1798 }
1799
1800 int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
1801 u16 vport, u16 vlan, u8 qos, u8 set_flags)
1802 {
1803 struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
1804 int err = 0;
1805
1806 if (IS_ERR(evport))
1807 return PTR_ERR(evport);
1808 if (vlan > 4095 || qos > 7)
1809 return -EINVAL;
1810
1811 err = modify_esw_vport_cvlan(esw->dev, vport, vlan, qos, set_flags);
1812 if (err)
1813 return err;
1814
1815 evport->info.vlan = vlan;
1816 evport->info.qos = qos;
1817 if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY) {
1818 err = esw_acl_ingress_lgcy_setup(esw, evport);
1819 if (err)
1820 return err;
1821 err = esw_acl_egress_lgcy_setup(esw, evport);
1822 }
1823
1824 return err;
1825 }
1826
1827 int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
1828 u16 vport_num,
1829 struct ifla_vf_stats *vf_stats)
1830 {
1831 struct mlx5_vport *vport = mlx5_eswitch_get_vport(esw, vport_num);
1832 int outlen = MLX5_ST_SZ_BYTES(query_vport_counter_out);
1833 u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)] = {};
1834 struct mlx5_vport_drop_stats stats = {};
1835 int err = 0;
1836 u32 *out;
1837
1838 if (IS_ERR(vport))
1839 return PTR_ERR(vport);
1840
1841 out = kvzalloc(outlen, GFP_KERNEL);
1842 if (!out)
1843 return -ENOMEM;
1844
1845 MLX5_SET(query_vport_counter_in, in, opcode,
1846 MLX5_CMD_OP_QUERY_VPORT_COUNTER);
1847 MLX5_SET(query_vport_counter_in, in, op_mod, 0);
1848 MLX5_SET(query_vport_counter_in, in, vport_number, vport->vport);
1849 MLX5_SET(query_vport_counter_in, in, other_vport, 1);
1850
1851 err = mlx5_cmd_exec_inout(esw->dev, query_vport_counter, in, out);
1852 if (err)
1853 goto free_out;
1854
1855 #define MLX5_GET_CTR(p, x) \
1856 MLX5_GET64(query_vport_counter_out, p, x)
1857
1858 memset(vf_stats, 0, sizeof(*vf_stats));
1859 vf_stats->rx_packets =
1860 MLX5_GET_CTR(out, received_eth_unicast.packets) +
1861 MLX5_GET_CTR(out, received_ib_unicast.packets) +
1862 MLX5_GET_CTR(out, received_eth_multicast.packets) +
1863 MLX5_GET_CTR(out, received_ib_multicast.packets) +
1864 MLX5_GET_CTR(out, received_eth_broadcast.packets);
1865
1866 vf_stats->rx_bytes =
1867 MLX5_GET_CTR(out, received_eth_unicast.octets) +
1868 MLX5_GET_CTR(out, received_ib_unicast.octets) +
1869 MLX5_GET_CTR(out, received_eth_multicast.octets) +
1870 MLX5_GET_CTR(out, received_ib_multicast.octets) +
1871 MLX5_GET_CTR(out, received_eth_broadcast.octets);
1872
1873 vf_stats->tx_packets =
1874 MLX5_GET_CTR(out, transmitted_eth_unicast.packets) +
1875 MLX5_GET_CTR(out, transmitted_ib_unicast.packets) +
1876 MLX5_GET_CTR(out, transmitted_eth_multicast.packets) +
1877 MLX5_GET_CTR(out, transmitted_ib_multicast.packets) +
1878 MLX5_GET_CTR(out, transmitted_eth_broadcast.packets);
1879
1880 vf_stats->tx_bytes =
1881 MLX5_GET_CTR(out, transmitted_eth_unicast.octets) +
1882 MLX5_GET_CTR(out, transmitted_ib_unicast.octets) +
1883 MLX5_GET_CTR(out, transmitted_eth_multicast.octets) +
1884 MLX5_GET_CTR(out, transmitted_ib_multicast.octets) +
1885 MLX5_GET_CTR(out, transmitted_eth_broadcast.octets);
1886
1887 vf_stats->multicast =
1888 MLX5_GET_CTR(out, received_eth_multicast.packets) +
1889 MLX5_GET_CTR(out, received_ib_multicast.packets);
1890
1891 vf_stats->broadcast =
1892 MLX5_GET_CTR(out, received_eth_broadcast.packets);
1893
1894 err = mlx5_esw_query_vport_drop_stats(esw->dev, vport, &stats);
1895 if (err)
1896 goto free_out;
1897 vf_stats->rx_dropped = stats.rx_dropped;
1898 vf_stats->tx_dropped = stats.tx_dropped;
1899
1900 free_out:
1901 kvfree(out);
1902 return err;
1903 }
1904
1905 u8 mlx5_eswitch_mode(const struct mlx5_core_dev *dev)
1906 {
1907 struct mlx5_eswitch *esw = dev->priv.eswitch;
1908
1909 return mlx5_esw_allowed(esw) ? esw->mode : MLX5_ESWITCH_LEGACY;
1910 }
1911 EXPORT_SYMBOL_GPL(mlx5_eswitch_mode);
1912
1913 enum devlink_eswitch_encap_mode
1914 mlx5_eswitch_get_encap_mode(const struct mlx5_core_dev *dev)
1915 {
1916 struct mlx5_eswitch *esw;
1917
1918 esw = dev->priv.eswitch;
1919 return (mlx5_eswitch_mode(dev) == MLX5_ESWITCH_OFFLOADS) ? esw->offloads.encap :
1920 DEVLINK_ESWITCH_ENCAP_MODE_NONE;
1921 }
1922 EXPORT_SYMBOL(mlx5_eswitch_get_encap_mode);
1923
1924 bool mlx5_esw_multipath_prereq(struct mlx5_core_dev *dev0,
1925 struct mlx5_core_dev *dev1)
1926 {
1927 return (dev0->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS &&
1928 dev1->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS);
1929 }
1930
1931 int mlx5_esw_event_notifier_register(struct mlx5_eswitch *esw, struct notifier_block *nb)
1932 {
1933 return blocking_notifier_chain_register(&esw->n_head, nb);
1934 }
1935
1936 void mlx5_esw_event_notifier_unregister(struct mlx5_eswitch *esw, struct notifier_block *nb)
1937 {
1938 blocking_notifier_chain_unregister(&esw->n_head, nb);
1939 }
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949 bool mlx5_esw_hold(struct mlx5_core_dev *mdev)
1950 {
1951 struct mlx5_eswitch *esw = mdev->priv.eswitch;
1952
1953
1954 if (!mlx5_esw_allowed(esw))
1955 return true;
1956
1957 if (down_read_trylock(&esw->mode_lock) != 0)
1958 return true;
1959
1960 return false;
1961 }
1962
1963
1964
1965
1966
1967 void mlx5_esw_release(struct mlx5_core_dev *mdev)
1968 {
1969 struct mlx5_eswitch *esw = mdev->priv.eswitch;
1970
1971 if (mlx5_esw_allowed(esw))
1972 up_read(&esw->mode_lock);
1973 }
1974
1975
1976
1977
1978
1979 void mlx5_esw_get(struct mlx5_core_dev *mdev)
1980 {
1981 struct mlx5_eswitch *esw = mdev->priv.eswitch;
1982
1983 if (mlx5_esw_allowed(esw))
1984 atomic64_inc(&esw->user_count);
1985 }
1986
1987
1988
1989
1990
1991 void mlx5_esw_put(struct mlx5_core_dev *mdev)
1992 {
1993 struct mlx5_eswitch *esw = mdev->priv.eswitch;
1994
1995 if (mlx5_esw_allowed(esw))
1996 atomic64_dec_if_positive(&esw->user_count);
1997 }
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010 int mlx5_esw_try_lock(struct mlx5_eswitch *esw)
2011 {
2012 if (down_write_trylock(&esw->mode_lock) == 0)
2013 return -EINVAL;
2014
2015 if (atomic64_read(&esw->user_count) > 0) {
2016 up_write(&esw->mode_lock);
2017 return -EBUSY;
2018 }
2019
2020 return esw->mode;
2021 }
2022
2023
2024
2025
2026
2027 void mlx5_esw_unlock(struct mlx5_eswitch *esw)
2028 {
2029 up_write(&esw->mode_lock);
2030 }
2031
2032
2033
2034
2035
2036
2037
2038
2039 u16 mlx5_eswitch_get_total_vports(const struct mlx5_core_dev *dev)
2040 {
2041 struct mlx5_eswitch *esw;
2042
2043 esw = dev->priv.eswitch;
2044 return mlx5_esw_allowed(esw) ? esw->total_vports : 0;
2045 }
2046 EXPORT_SYMBOL_GPL(mlx5_eswitch_get_total_vports);
2047
2048
2049
2050
2051
2052
2053
2054 struct mlx5_core_dev *mlx5_eswitch_get_core_dev(struct mlx5_eswitch *esw)
2055 {
2056 return mlx5_esw_allowed(esw) ? esw->dev : NULL;
2057 }
2058 EXPORT_SYMBOL(mlx5_eswitch_get_core_dev);