1 /*- 2 * Copyright (c) 2013-2017, Mellanox Technologies, Ltd. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include "opt_rss.h" 27 #include "opt_ratelimit.h" 28 29 #include <linux/etherdevice.h> 30 #include <dev/mlx5/driver.h> 31 #include <dev/mlx5/mlx5_ifc.h> 32 #include <dev/mlx5/vport.h> 33 #include <dev/mlx5/fs.h> 34 #include <dev/mlx5/mpfs.h> 35 #include <dev/mlx5/mlx5_core/mlx5_core.h> 36 #include <dev/mlx5/mlx5_core/eswitch.h> 37 38 #define UPLINK_VPORT 0xFFFF 39 40 #define MLX5_DEBUG_ESWITCH_MASK BIT(3) 41 42 #define esw_info(dev, format, ...) \ 43 printf("mlx5_core: INFO: ""(%s): E-Switch: " format, (dev)->priv.name, ##__VA_ARGS__) 44 45 #define esw_warn(dev, format, ...) \ 46 printf("mlx5_core: WARN: ""(%s): E-Switch: " format, (dev)->priv.name, ##__VA_ARGS__) 47 48 #define esw_debug(dev, format, ...) \ 49 mlx5_core_dbg_mask(dev, MLX5_DEBUG_ESWITCH_MASK, format, ##__VA_ARGS__) 50 51 enum { 52 MLX5_ACTION_NONE = 0, 53 MLX5_ACTION_ADD = 1, 54 MLX5_ACTION_DEL = 2, 55 }; 56 57 /* E-Switch UC L2 table hash node */ 58 struct esw_uc_addr { 59 struct l2addr_node node; 60 u32 table_index; 61 u32 vport; 62 }; 63 64 /* E-Switch MC FDB table hash node */ 65 struct esw_mc_addr { /* SRIOV only */ 66 struct l2addr_node node; 67 struct mlx5_flow_rule *uplink_rule; /* Forward to uplink rule */ 68 u32 refcnt; 69 }; 70 71 /* Vport UC/MC hash node */ 72 struct vport_addr { 73 struct l2addr_node node; 74 u8 action; 75 u32 vport; 76 struct mlx5_flow_rule *flow_rule; /* SRIOV only */ 77 }; 78 79 enum { 80 UC_ADDR_CHANGE = BIT(0), 81 MC_ADDR_CHANGE = BIT(1), 82 }; 83 84 /* Vport context events */ 85 #define SRIOV_VPORT_EVENTS (UC_ADDR_CHANGE | \ 86 MC_ADDR_CHANGE) 87 88 static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport, 89 u32 events_mask) 90 { 91 int in[MLX5_ST_SZ_DW(modify_nic_vport_context_in)] = {0}; 92 int out[MLX5_ST_SZ_DW(modify_nic_vport_context_out)] = {0}; 93 void *nic_vport_ctx; 94 95 MLX5_SET(modify_nic_vport_context_in, in, 96 opcode, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT); 97 MLX5_SET(modify_nic_vport_context_in, in, field_select.change_event, 1); 98 MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport); 99 if (vport) 100 MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1); 101 nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in, 102 in, nic_vport_context); 103 104 MLX5_SET(nic_vport_context, nic_vport_ctx, arm_change_event, 1); 105 106 if (events_mask & UC_ADDR_CHANGE) 107 MLX5_SET(nic_vport_context, nic_vport_ctx, 108 event_on_uc_address_change, 1); 109 if (events_mask & MC_ADDR_CHANGE) 110 MLX5_SET(nic_vport_context, nic_vport_ctx, 111 event_on_mc_address_change, 1); 112 113 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); 114 } 115 116 /* E-Switch vport context HW commands */ 117 static int query_esw_vport_context_cmd(struct mlx5_core_dev *mdev, u32 vport, 118 u32 *out, int outlen) 119 { 120 u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {0}; 121 122 MLX5_SET(query_nic_vport_context_in, in, opcode, 123 MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT); 124 125 MLX5_SET(query_esw_vport_context_in, in, vport_number, vport); 126 if (vport) 127 MLX5_SET(query_esw_vport_context_in, in, other_vport, 1); 128 129 return mlx5_cmd_exec(mdev, in, sizeof(in), out, outlen); 130 } 131 132 static int query_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport, 133 u16 *vlan, u8 *qos) 134 { 135 u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {0}; 136 int err; 137 bool cvlan_strip; 138 bool cvlan_insert; 139 140 *vlan = 0; 141 *qos = 0; 142 143 if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) || 144 !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist)) 145 return -ENOTSUPP; 146 147 err = query_esw_vport_context_cmd(dev, vport, out, sizeof(out)); 148 if (err) 149 goto out; 150 151 cvlan_strip = MLX5_GET(query_esw_vport_context_out, out, 152 esw_vport_context.vport_cvlan_strip); 153 154 cvlan_insert = MLX5_GET(query_esw_vport_context_out, out, 155 esw_vport_context.vport_cvlan_insert); 156 157 if (cvlan_strip || cvlan_insert) { 158 *vlan = MLX5_GET(query_esw_vport_context_out, out, 159 esw_vport_context.cvlan_id); 160 *qos = MLX5_GET(query_esw_vport_context_out, out, 161 esw_vport_context.cvlan_pcp); 162 } 163 164 esw_debug(dev, "Query Vport[%d] cvlan: VLAN %d qos=%d\n", 165 vport, *vlan, *qos); 166 out: 167 return err; 168 } 169 170 static int modify_esw_vport_context_cmd(struct mlx5_core_dev *dev, u16 vport, 171 void *in, int inlen) 172 { 173 u32 out[MLX5_ST_SZ_DW(modify_esw_vport_context_out)] = {0}; 174 175 MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport); 176 if (vport) 177 MLX5_SET(modify_esw_vport_context_in, in, other_vport, 1); 178 179 MLX5_SET(modify_esw_vport_context_in, in, opcode, 180 MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT); 181 182 return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); 183 } 184 185 static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport, 186 u16 vlan, u8 qos, bool set) 187 { 188 u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {0}; 189 190 if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) || 191 !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist)) 192 return -ENOTSUPP; 193 194 esw_debug(dev, "Set Vport[%d] VLAN %d qos %d set=%d\n", 195 vport, vlan, qos, set); 196 197 if (set) { 198 MLX5_SET(modify_esw_vport_context_in, in, 199 esw_vport_context.vport_cvlan_strip, 1); 200 /* insert only if no vlan in packet */ 201 MLX5_SET(modify_esw_vport_context_in, in, 202 esw_vport_context.vport_cvlan_insert, 1); 203 MLX5_SET(modify_esw_vport_context_in, in, 204 esw_vport_context.cvlan_pcp, qos); 205 MLX5_SET(modify_esw_vport_context_in, in, 206 esw_vport_context.cvlan_id, vlan); 207 } 208 209 MLX5_SET(modify_esw_vport_context_in, in, 210 field_select.vport_cvlan_strip, 1); 211 MLX5_SET(modify_esw_vport_context_in, in, 212 field_select.vport_cvlan_insert, 1); 213 214 return modify_esw_vport_context_cmd(dev, vport, in, sizeof(in)); 215 } 216 217 /* E-Switch FDB */ 218 static struct mlx5_flow_rule * 219 esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u8 mac[ETH_ALEN], u32 vport) 220 { 221 int match_header = MLX5_MATCH_OUTER_HEADERS; 222 struct mlx5_flow_destination dest; 223 struct mlx5_flow_rule *flow_rule = NULL; 224 struct mlx5_flow_act flow_act = {}; 225 u32 *match_v; 226 u32 *match_c; 227 u8 *dmac_v; 228 u8 *dmac_c; 229 230 match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); 231 match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); 232 if (!match_v || !match_c) { 233 printf("mlx5_core: WARN: ""FDB: Failed to alloc match parameters\n"); 234 goto out; 235 } 236 dmac_v = MLX5_ADDR_OF(fte_match_param, match_v, 237 outer_headers.dmac_47_16); 238 dmac_c = MLX5_ADDR_OF(fte_match_param, match_c, 239 outer_headers.dmac_47_16); 240 241 ether_addr_copy(dmac_v, mac); 242 /* Match criteria mask */ 243 memset(dmac_c, 0xff, 6); 244 245 dest.type = MLX5_FLOW_CONTEXT_DEST_TYPE_VPORT; 246 dest.vport_num = vport; 247 248 esw_debug(esw->dev, 249 "\tFDB add rule dmac_v(%pM) dmac_c(%pM) -> vport(%d)\n", 250 dmac_v, dmac_c, vport); 251 flow_rule = 252 mlx5_add_flow_rule(esw->fdb_table.fdb, 253 match_header, 254 match_c, 255 match_v, 256 MLX5_FLOW_RULE_FWD_ACTION_DEST, 257 &flow_act, &dest); 258 if (IS_ERR_OR_NULL(flow_rule)) { 259 printf("mlx5_core: WARN: ""FDB: Failed to add flow rule: dmac_v(%pM) dmac_c(%pM) -> vport(%d), err(%ld)\n", dmac_v, dmac_c, vport, PTR_ERR(flow_rule)); 260 flow_rule = NULL; 261 } 262 out: 263 kfree(match_v); 264 kfree(match_c); 265 return flow_rule; 266 } 267 268 static int esw_create_fdb_table(struct mlx5_eswitch *esw) 269 { 270 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 271 struct mlx5_core_dev *dev = esw->dev; 272 struct mlx5_flow_namespace *root_ns; 273 struct mlx5_flow_table *fdb; 274 struct mlx5_flow_group *g; 275 void *match_criteria; 276 int table_size; 277 u32 *flow_group_in; 278 u8 *dmac; 279 int err = 0; 280 281 esw_debug(dev, "Create FDB log_max_size(%d)\n", 282 MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size)); 283 284 root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB); 285 if (!root_ns) { 286 esw_warn(dev, "Failed to get FDB flow namespace\n"); 287 return -ENOMEM; 288 } 289 290 flow_group_in = mlx5_vzalloc(inlen); 291 if (!flow_group_in) 292 return -ENOMEM; 293 memset(flow_group_in, 0, inlen); 294 295 /* (-2) Since MaorG said so .. */ 296 table_size = BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size)) - 2; 297 298 fdb = mlx5_create_flow_table(root_ns, 0, "FDB", table_size); 299 if (IS_ERR_OR_NULL(fdb)) { 300 err = PTR_ERR(fdb); 301 esw_warn(dev, "Failed to create FDB Table err %d\n", err); 302 goto out; 303 } 304 305 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, 306 MLX5_MATCH_OUTER_HEADERS); 307 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria); 308 dmac = MLX5_ADDR_OF(fte_match_param, match_criteria, outer_headers.dmac_47_16); 309 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0); 310 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, table_size - 1); 311 eth_broadcast_addr(dmac); 312 313 g = mlx5_create_flow_group(fdb, flow_group_in); 314 if (IS_ERR_OR_NULL(g)) { 315 err = PTR_ERR(g); 316 esw_warn(dev, "Failed to create flow group err(%d)\n", err); 317 goto out; 318 } 319 320 esw->fdb_table.addr_grp = g; 321 esw->fdb_table.fdb = fdb; 322 out: 323 kfree(flow_group_in); 324 if (err && !IS_ERR_OR_NULL(fdb)) 325 mlx5_destroy_flow_table(fdb); 326 return err; 327 } 328 329 static void esw_destroy_fdb_table(struct mlx5_eswitch *esw) 330 { 331 if (!esw->fdb_table.fdb) 332 return; 333 334 esw_debug(esw->dev, "Destroy FDB Table\n"); 335 mlx5_destroy_flow_group(esw->fdb_table.addr_grp); 336 mlx5_destroy_flow_table(esw->fdb_table.fdb); 337 esw->fdb_table.fdb = NULL; 338 esw->fdb_table.addr_grp = NULL; 339 } 340 341 /* E-Switch vport UC/MC lists management */ 342 typedef int (*vport_addr_action)(struct mlx5_eswitch *esw, 343 struct vport_addr *vaddr); 344 345 static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr) 346 { 347 struct hlist_head *hash = esw->l2_table.l2_hash; 348 struct esw_uc_addr *esw_uc; 349 u8 *mac = vaddr->node.addr; 350 u32 vport = vaddr->vport; 351 int err; 352 353 esw_uc = l2addr_hash_find(hash, mac, struct esw_uc_addr); 354 if (esw_uc) { 355 esw_warn(esw->dev, 356 "Failed to set L2 mac(%pM) for vport(%d), mac is already in use by vport(%d)\n", 357 mac, vport, esw_uc->vport); 358 return -EEXIST; 359 } 360 361 esw_uc = l2addr_hash_add(hash, mac, struct esw_uc_addr, GFP_KERNEL); 362 if (!esw_uc) 363 return -ENOMEM; 364 esw_uc->vport = vport; 365 366 err = mlx5_mpfs_add_mac(esw->dev, &esw_uc->table_index, mac, 0, 0); 367 if (err) 368 goto abort; 369 370 if (esw->fdb_table.fdb) /* SRIOV is enabled: Forward UC MAC to vport */ 371 vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport); 372 373 esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM index:%d fr(%p)\n", 374 vport, mac, esw_uc->table_index, vaddr->flow_rule); 375 return err; 376 abort: 377 l2addr_hash_del(esw_uc); 378 return err; 379 } 380 381 static int esw_del_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr) 382 { 383 struct hlist_head *hash = esw->l2_table.l2_hash; 384 struct esw_uc_addr *esw_uc; 385 u8 *mac = vaddr->node.addr; 386 u32 vport = vaddr->vport; 387 388 esw_uc = l2addr_hash_find(hash, mac, struct esw_uc_addr); 389 if (!esw_uc || esw_uc->vport != vport) { 390 esw_debug(esw->dev, 391 "MAC(%pM) doesn't belong to vport (%d)\n", 392 mac, vport); 393 return -EINVAL; 394 } 395 esw_debug(esw->dev, "\tDELETE UC MAC: vport[%d] %pM index:%d fr(%p)\n", 396 vport, mac, esw_uc->table_index, vaddr->flow_rule); 397 398 mlx5_mpfs_del_mac(esw->dev, esw_uc->table_index); 399 400 mlx5_del_flow_rule(&vaddr->flow_rule); 401 402 l2addr_hash_del(esw_uc); 403 return 0; 404 } 405 406 static int esw_add_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr) 407 { 408 struct hlist_head *hash = esw->mc_table; 409 struct esw_mc_addr *esw_mc; 410 u8 *mac = vaddr->node.addr; 411 u32 vport = vaddr->vport; 412 413 if (!esw->fdb_table.fdb) 414 return 0; 415 416 esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr); 417 if (esw_mc) 418 goto add; 419 420 esw_mc = l2addr_hash_add(hash, mac, struct esw_mc_addr, GFP_KERNEL); 421 if (!esw_mc) 422 return -ENOMEM; 423 424 esw_mc->uplink_rule = /* Forward MC MAC to Uplink */ 425 esw_fdb_set_vport_rule(esw, mac, UPLINK_VPORT); 426 add: 427 esw_mc->refcnt++; 428 /* Forward MC MAC to vport */ 429 vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport); 430 esw_debug(esw->dev, 431 "\tADDED MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n", 432 vport, mac, vaddr->flow_rule, 433 esw_mc->refcnt, esw_mc->uplink_rule); 434 return 0; 435 } 436 437 static int esw_del_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr) 438 { 439 struct hlist_head *hash = esw->mc_table; 440 struct esw_mc_addr *esw_mc; 441 u8 *mac = vaddr->node.addr; 442 u32 vport = vaddr->vport; 443 444 if (!esw->fdb_table.fdb) 445 return 0; 446 447 esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr); 448 if (!esw_mc) { 449 esw_warn(esw->dev, 450 "Failed to find eswitch MC addr for MAC(%pM) vport(%d)", 451 mac, vport); 452 return -EINVAL; 453 } 454 esw_debug(esw->dev, 455 "\tDELETE MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n", 456 vport, mac, vaddr->flow_rule, esw_mc->refcnt, 457 esw_mc->uplink_rule); 458 459 mlx5_del_flow_rule(&vaddr->flow_rule); 460 461 if (--esw_mc->refcnt) 462 return 0; 463 464 mlx5_del_flow_rule(&esw_mc->uplink_rule); 465 466 l2addr_hash_del(esw_mc); 467 return 0; 468 } 469 470 /* Apply vport UC/MC list to HW l2 table and FDB table */ 471 static void esw_apply_vport_addr_list(struct mlx5_eswitch *esw, 472 u32 vport_num, int list_type) 473 { 474 struct mlx5_vport *vport = &esw->vports[vport_num]; 475 bool is_uc = list_type == MLX5_NIC_VPORT_LIST_TYPE_UC; 476 vport_addr_action vport_addr_add; 477 vport_addr_action vport_addr_del; 478 struct vport_addr *addr; 479 struct l2addr_node *node; 480 struct hlist_head *hash; 481 struct hlist_node *tmp; 482 int hi; 483 484 vport_addr_add = is_uc ? esw_add_uc_addr : 485 esw_add_mc_addr; 486 vport_addr_del = is_uc ? esw_del_uc_addr : 487 esw_del_mc_addr; 488 489 hash = is_uc ? vport->uc_list : vport->mc_list; 490 for_each_l2hash_node(node, tmp, hash, hi) { 491 addr = container_of(node, struct vport_addr, node); 492 switch (addr->action) { 493 case MLX5_ACTION_ADD: 494 vport_addr_add(esw, addr); 495 addr->action = MLX5_ACTION_NONE; 496 break; 497 case MLX5_ACTION_DEL: 498 vport_addr_del(esw, addr); 499 l2addr_hash_del(addr); 500 break; 501 } 502 } 503 } 504 505 /* Sync vport UC/MC list from vport context */ 506 static void esw_update_vport_addr_list(struct mlx5_eswitch *esw, 507 u32 vport_num, int list_type) 508 { 509 struct mlx5_vport *vport = &esw->vports[vport_num]; 510 bool is_uc = list_type == MLX5_NIC_VPORT_LIST_TYPE_UC; 511 u8 (*mac_list)[ETH_ALEN]; 512 struct l2addr_node *node; 513 struct vport_addr *addr; 514 struct hlist_head *hash; 515 struct hlist_node *tmp; 516 int size; 517 int err; 518 int hi; 519 int i; 520 521 size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) : 522 MLX5_MAX_MC_PER_VPORT(esw->dev); 523 524 mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL); 525 if (!mac_list) 526 return; 527 528 hash = is_uc ? vport->uc_list : vport->mc_list; 529 530 for_each_l2hash_node(node, tmp, hash, hi) { 531 addr = container_of(node, struct vport_addr, node); 532 addr->action = MLX5_ACTION_DEL; 533 } 534 535 err = mlx5_query_nic_vport_mac_list(esw->dev, vport_num, list_type, 536 mac_list, &size); 537 if (err) 538 return; 539 esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n", 540 vport_num, is_uc ? "UC" : "MC", size); 541 542 for (i = 0; i < size; i++) { 543 if (is_uc && !is_valid_ether_addr(mac_list[i])) 544 continue; 545 546 if (!is_uc && !is_multicast_ether_addr(mac_list[i])) 547 continue; 548 549 addr = l2addr_hash_find(hash, mac_list[i], struct vport_addr); 550 if (addr) { 551 addr->action = MLX5_ACTION_NONE; 552 continue; 553 } 554 555 addr = l2addr_hash_add(hash, mac_list[i], struct vport_addr, 556 GFP_KERNEL); 557 if (!addr) { 558 esw_warn(esw->dev, 559 "Failed to add MAC(%pM) to vport[%d] DB\n", 560 mac_list[i], vport_num); 561 continue; 562 } 563 addr->vport = vport_num; 564 addr->action = MLX5_ACTION_ADD; 565 } 566 kfree(mac_list); 567 } 568 569 static void esw_vport_change_handler(struct work_struct *work) 570 { 571 struct mlx5_vport *vport = 572 container_of(work, struct mlx5_vport, vport_change_handler); 573 struct mlx5_core_dev *dev = vport->dev; 574 struct mlx5_eswitch *esw = dev->priv.eswitch; 575 u8 mac[ETH_ALEN]; 576 577 mlx5_query_nic_vport_mac_address(dev, vport->vport, mac); 578 esw_debug(dev, "vport[%d] Context Changed: perm mac: %pM\n", 579 vport->vport, mac); 580 581 if (vport->enabled_events & UC_ADDR_CHANGE) { 582 esw_update_vport_addr_list(esw, vport->vport, 583 MLX5_NIC_VPORT_LIST_TYPE_UC); 584 esw_apply_vport_addr_list(esw, vport->vport, 585 MLX5_NIC_VPORT_LIST_TYPE_UC); 586 } 587 588 if (vport->enabled_events & MC_ADDR_CHANGE) { 589 esw_update_vport_addr_list(esw, vport->vport, 590 MLX5_NIC_VPORT_LIST_TYPE_MC); 591 esw_apply_vport_addr_list(esw, vport->vport, 592 MLX5_NIC_VPORT_LIST_TYPE_MC); 593 } 594 595 esw_debug(esw->dev, "vport[%d] Context Changed: Done\n", vport->vport); 596 if (vport->enabled) 597 arm_vport_context_events_cmd(dev, vport->vport, 598 vport->enabled_events); 599 } 600 601 static void esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, 602 struct mlx5_vport *vport) 603 { 604 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 605 struct mlx5_flow_group *vlan_grp = NULL; 606 struct mlx5_flow_group *drop_grp = NULL; 607 struct mlx5_core_dev *dev = esw->dev; 608 struct mlx5_flow_namespace *root_ns; 609 struct mlx5_flow_table *acl; 610 void *match_criteria; 611 char table_name[32]; 612 u32 *flow_group_in; 613 int table_size = 2; 614 int err = 0; 615 616 if (!MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support)) 617 return; 618 619 esw_debug(dev, "Create vport[%d] egress ACL log_max_size(%d)\n", 620 vport->vport, MLX5_CAP_ESW_EGRESS_ACL(dev, log_max_ft_size)); 621 622 root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS); 623 if (!root_ns) { 624 esw_warn(dev, "Failed to get E-Switch egress flow namespace\n"); 625 return; 626 } 627 628 flow_group_in = mlx5_vzalloc(inlen); 629 if (!flow_group_in) 630 return; 631 632 snprintf(table_name, 32, "egress_%d", vport->vport); 633 acl = mlx5_create_vport_flow_table(root_ns, vport->vport, 0, table_name, table_size); 634 if (IS_ERR_OR_NULL(acl)) { 635 err = PTR_ERR(acl); 636 esw_warn(dev, "Failed to create E-Switch vport[%d] egress flow Table, err(%d)\n", 637 vport->vport, err); 638 goto out; 639 } 640 641 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); 642 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria); 643 MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.cvlan_tag); 644 MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.first_vid); 645 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0); 646 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0); 647 648 vlan_grp = mlx5_create_flow_group(acl, flow_group_in); 649 if (IS_ERR_OR_NULL(vlan_grp)) { 650 err = PTR_ERR(vlan_grp); 651 esw_warn(dev, "Failed to create E-Switch vport[%d] egress allowed vlans flow group, err(%d)\n", 652 vport->vport, err); 653 goto out; 654 } 655 656 memset(flow_group_in, 0, inlen); 657 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1); 658 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1); 659 drop_grp = mlx5_create_flow_group(acl, flow_group_in); 660 if (IS_ERR_OR_NULL(drop_grp)) { 661 err = PTR_ERR(drop_grp); 662 esw_warn(dev, "Failed to create E-Switch vport[%d] egress drop flow group, err(%d)\n", 663 vport->vport, err); 664 goto out; 665 } 666 667 vport->egress.acl = acl; 668 vport->egress.drop_grp = drop_grp; 669 vport->egress.allowed_vlans_grp = vlan_grp; 670 out: 671 kfree(flow_group_in); 672 if (err && !IS_ERR_OR_NULL(vlan_grp)) 673 mlx5_destroy_flow_group(vlan_grp); 674 if (err && !IS_ERR_OR_NULL(acl)) 675 mlx5_destroy_flow_table(acl); 676 } 677 678 static void esw_vport_cleanup_egress_rules(struct mlx5_eswitch *esw, 679 struct mlx5_vport *vport) 680 { 681 mlx5_del_flow_rule(&vport->egress.allowed_vlan); 682 mlx5_del_flow_rule(&vport->egress.drop_rule); 683 } 684 685 static void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw, 686 struct mlx5_vport *vport) 687 { 688 if (IS_ERR_OR_NULL(vport->egress.acl)) 689 return; 690 691 esw_debug(esw->dev, "Destroy vport[%d] E-Switch egress ACL\n", vport->vport); 692 693 esw_vport_cleanup_egress_rules(esw, vport); 694 mlx5_destroy_flow_group(vport->egress.allowed_vlans_grp); 695 mlx5_destroy_flow_group(vport->egress.drop_grp); 696 mlx5_destroy_flow_table(vport->egress.acl); 697 vport->egress.allowed_vlans_grp = NULL; 698 vport->egress.drop_grp = NULL; 699 vport->egress.acl = NULL; 700 } 701 702 static void esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, 703 struct mlx5_vport *vport) 704 { 705 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 706 struct mlx5_core_dev *dev = esw->dev; 707 struct mlx5_flow_namespace *root_ns; 708 struct mlx5_flow_table *acl; 709 struct mlx5_flow_group *g; 710 void *match_criteria; 711 char table_name[32]; 712 u32 *flow_group_in; 713 int table_size = 1; 714 int err = 0; 715 716 if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support)) 717 return; 718 719 esw_debug(dev, "Create vport[%d] ingress ACL log_max_size(%d)\n", 720 vport->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size)); 721 722 root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS); 723 if (!root_ns) { 724 esw_warn(dev, "Failed to get E-Switch ingress flow namespace\n"); 725 return; 726 } 727 728 flow_group_in = mlx5_vzalloc(inlen); 729 if (!flow_group_in) 730 return; 731 732 snprintf(table_name, 32, "ingress_%d", vport->vport); 733 acl = mlx5_create_vport_flow_table(root_ns, vport->vport, 0, table_name, table_size); 734 if (IS_ERR_OR_NULL(acl)) { 735 err = PTR_ERR(acl); 736 esw_warn(dev, "Failed to create E-Switch vport[%d] ingress flow Table, err(%d)\n", 737 vport->vport, err); 738 goto out; 739 } 740 741 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); 742 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria); 743 MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.cvlan_tag); 744 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0); 745 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0); 746 747 g = mlx5_create_flow_group(acl, flow_group_in); 748 if (IS_ERR_OR_NULL(g)) { 749 err = PTR_ERR(g); 750 esw_warn(dev, "Failed to create E-Switch vport[%d] ingress flow group, err(%d)\n", 751 vport->vport, err); 752 goto out; 753 } 754 755 vport->ingress.acl = acl; 756 vport->ingress.drop_grp = g; 757 out: 758 kfree(flow_group_in); 759 if (err && !IS_ERR_OR_NULL(acl)) 760 mlx5_destroy_flow_table(acl); 761 } 762 763 static void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw, 764 struct mlx5_vport *vport) 765 { 766 mlx5_del_flow_rule(&vport->ingress.drop_rule); 767 } 768 769 static void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw, 770 struct mlx5_vport *vport) 771 { 772 if (IS_ERR_OR_NULL(vport->ingress.acl)) 773 return; 774 775 esw_debug(esw->dev, "Destroy vport[%d] E-Switch ingress ACL\n", vport->vport); 776 777 esw_vport_cleanup_ingress_rules(esw, vport); 778 mlx5_destroy_flow_group(vport->ingress.drop_grp); 779 mlx5_destroy_flow_table(vport->ingress.acl); 780 vport->ingress.acl = NULL; 781 vport->ingress.drop_grp = NULL; 782 } 783 784 static int esw_vport_ingress_config(struct mlx5_eswitch *esw, 785 struct mlx5_vport *vport) 786 { 787 struct mlx5_flow_act flow_act = {}; 788 struct mlx5_flow_destination dest; 789 u32 *match_v; 790 u32 *match_c; 791 int err = 0; 792 793 if (IS_ERR_OR_NULL(vport->ingress.acl)) { 794 esw_warn(esw->dev, 795 "vport[%d] configure ingress rules failed, ingress acl is not initialized!\n", 796 vport->vport); 797 return -EPERM; 798 } 799 800 esw_vport_cleanup_ingress_rules(esw, vport); 801 802 if (!vport->vlan && !vport->qos) 803 return 0; 804 805 esw_debug(esw->dev, 806 "vport[%d] configure ingress rules, vlan(%d) qos(%d)\n", 807 vport->vport, vport->vlan, vport->qos); 808 809 match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); 810 match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); 811 if (!match_v || !match_c) { 812 err = -ENOMEM; 813 esw_warn(esw->dev, "vport[%d] configure ingress rules failed, err(%d)\n", 814 vport->vport, err); 815 goto out; 816 } 817 MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.cvlan_tag); 818 MLX5_SET_TO_ONES(fte_match_param, match_v, outer_headers.cvlan_tag); 819 820 dest.type = MLX5_FLOW_CONTEXT_DEST_TYPE_VPORT; 821 dest.vport_num = vport->vport; 822 823 vport->ingress.drop_rule = 824 mlx5_add_flow_rule(vport->ingress.acl, 825 MLX5_MATCH_OUTER_HEADERS, 826 match_c, 827 match_v, 828 MLX5_FLOW_RULE_FWD_ACTION_DROP, 829 &flow_act, &dest); 830 if (IS_ERR_OR_NULL(vport->ingress.drop_rule)) { 831 err = PTR_ERR(vport->ingress.drop_rule); 832 printf("mlx5_core: WARN: ""vport[%d] configure ingress rules, err(%d)\n", vport->vport, err); 833 vport->ingress.drop_rule = NULL; 834 } 835 out: 836 kfree(match_v); 837 kfree(match_c); 838 return err; 839 } 840 841 static int esw_vport_egress_config(struct mlx5_eswitch *esw, 842 struct mlx5_vport *vport) 843 { 844 struct mlx5_flow_act flow_act = {}; 845 struct mlx5_flow_destination dest; 846 u32 *match_v; 847 u32 *match_c; 848 int err = 0; 849 850 if (IS_ERR_OR_NULL(vport->egress.acl)) { 851 esw_warn(esw->dev, "vport[%d] configure rgress rules failed, egress acl is not initialized!\n", 852 vport->vport); 853 return -EPERM; 854 } 855 856 esw_vport_cleanup_egress_rules(esw, vport); 857 858 if (!vport->vlan && !vport->qos) 859 return 0; 860 861 esw_debug(esw->dev, 862 "vport[%d] configure egress rules, vlan(%d) qos(%d)\n", 863 vport->vport, vport->vlan, vport->qos); 864 865 match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); 866 match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); 867 if (!match_v || !match_c) { 868 err = -ENOMEM; 869 esw_warn(esw->dev, "vport[%d] configure egress rules failed, err(%d)\n", 870 vport->vport, err); 871 goto out; 872 } 873 874 /* Allowed vlan rule */ 875 MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.cvlan_tag); 876 MLX5_SET_TO_ONES(fte_match_param, match_v, outer_headers.cvlan_tag); 877 MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.first_vid); 878 MLX5_SET(fte_match_param, match_v, outer_headers.first_vid, vport->vlan); 879 880 dest.type = MLX5_FLOW_CONTEXT_DEST_TYPE_VPORT; 881 dest.vport_num = vport->vport; 882 883 vport->egress.allowed_vlan = 884 mlx5_add_flow_rule(vport->egress.acl, 885 MLX5_MATCH_OUTER_HEADERS, 886 match_c, 887 match_v, 888 MLX5_FLOW_RULE_FWD_ACTION_ALLOW, 889 &flow_act, &dest); 890 if (IS_ERR_OR_NULL(vport->egress.allowed_vlan)) { 891 err = PTR_ERR(vport->egress.allowed_vlan); 892 printf("mlx5_core: WARN: ""vport[%d] configure egress allowed vlan rule failed, err(%d)\n", vport->vport, err); 893 vport->egress.allowed_vlan = NULL; 894 goto out; 895 } 896 897 /* Drop others rule (star rule) */ 898 memset(match_c, 0, MLX5_ST_SZ_BYTES(fte_match_param)); 899 memset(match_v, 0, MLX5_ST_SZ_BYTES(fte_match_param)); 900 vport->egress.drop_rule = 901 mlx5_add_flow_rule(vport->egress.acl, 902 0, 903 match_c, 904 match_v, 905 MLX5_FLOW_RULE_FWD_ACTION_DROP, 906 &flow_act, &dest); 907 if (IS_ERR_OR_NULL(vport->egress.drop_rule)) { 908 err = PTR_ERR(vport->egress.drop_rule); 909 printf("mlx5_core: WARN: ""vport[%d] configure egress drop rule failed, err(%d)\n", vport->vport, err); 910 vport->egress.drop_rule = NULL; 911 } 912 out: 913 kfree(match_v); 914 kfree(match_c); 915 return err; 916 } 917 918 static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num, 919 int enable_events) 920 { 921 struct mlx5_vport *vport = &esw->vports[vport_num]; 922 unsigned long flags; 923 924 mutex_lock(&vport->state_lock); 925 WARN_ON(vport->enabled); 926 927 esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num); 928 929 if (vport_num) { /* Only VFs need ACLs for VST and spoofchk filtering */ 930 esw_vport_enable_ingress_acl(esw, vport); 931 esw_vport_enable_egress_acl(esw, vport); 932 esw_vport_ingress_config(esw, vport); 933 esw_vport_egress_config(esw, vport); 934 } 935 936 mlx5_modify_vport_admin_state(esw->dev, 937 MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT, 938 vport_num, 939 MLX5_ESW_VPORT_ADMIN_STATE_AUTO); 940 941 /* Sync with current vport context */ 942 vport->enabled_events = enable_events; 943 esw_vport_change_handler(&vport->vport_change_handler); 944 945 spin_lock_irqsave(&vport->lock, flags); 946 vport->enabled = true; 947 spin_unlock_irqrestore(&vport->lock, flags); 948 949 arm_vport_context_events_cmd(esw->dev, vport_num, enable_events); 950 951 esw->enabled_vports++; 952 esw_debug(esw->dev, "Enabled VPORT(%d)\n", vport_num); 953 mutex_unlock(&vport->state_lock); 954 } 955 956 static void esw_cleanup_vport(struct mlx5_eswitch *esw, u16 vport_num) 957 { 958 struct mlx5_vport *vport = &esw->vports[vport_num]; 959 struct l2addr_node *node; 960 struct vport_addr *addr; 961 struct hlist_node *tmp; 962 int hi; 963 964 for_each_l2hash_node(node, tmp, vport->uc_list, hi) { 965 addr = container_of(node, struct vport_addr, node); 966 addr->action = MLX5_ACTION_DEL; 967 } 968 esw_apply_vport_addr_list(esw, vport_num, MLX5_NIC_VPORT_LIST_TYPE_UC); 969 970 for_each_l2hash_node(node, tmp, vport->mc_list, hi) { 971 addr = container_of(node, struct vport_addr, node); 972 addr->action = MLX5_ACTION_DEL; 973 } 974 esw_apply_vport_addr_list(esw, vport_num, MLX5_NIC_VPORT_LIST_TYPE_MC); 975 } 976 977 static void esw_disable_vport(struct mlx5_eswitch *esw, int vport_num) 978 { 979 struct mlx5_vport *vport = &esw->vports[vport_num]; 980 unsigned long flags; 981 982 mutex_lock(&vport->state_lock); 983 if (!vport->enabled) { 984 mutex_unlock(&vport->state_lock); 985 return; 986 } 987 988 esw_debug(esw->dev, "Disabling vport(%d)\n", vport_num); 989 /* Mark this vport as disabled to discard new events */ 990 spin_lock_irqsave(&vport->lock, flags); 991 vport->enabled = false; 992 vport->enabled_events = 0; 993 spin_unlock_irqrestore(&vport->lock, flags); 994 995 mlx5_modify_vport_admin_state(esw->dev, 996 MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT, 997 vport_num, 998 MLX5_ESW_VPORT_ADMIN_STATE_DOWN); 999 /* Wait for current already scheduled events to complete */ 1000 flush_workqueue(esw->work_queue); 1001 /* Disable events from this vport */ 1002 arm_vport_context_events_cmd(esw->dev, vport->vport, 0); 1003 /* We don't assume VFs will cleanup after themselves */ 1004 esw_cleanup_vport(esw, vport_num); 1005 if (vport_num) { 1006 esw_vport_disable_egress_acl(esw, vport); 1007 esw_vport_disable_ingress_acl(esw, vport); 1008 } 1009 esw->enabled_vports--; 1010 mutex_unlock(&vport->state_lock); 1011 } 1012 1013 /* Public E-Switch API */ 1014 int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs) 1015 { 1016 int err; 1017 int i; 1018 1019 if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) || 1020 MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH) 1021 return 0; 1022 1023 if (!MLX5_CAP_GEN(esw->dev, eswitch_flow_table) || 1024 !MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) { 1025 esw_warn(esw->dev, "E-Switch FDB is not supported, aborting ...\n"); 1026 return -ENOTSUPP; 1027 } 1028 1029 if (!MLX5_CAP_ESW_INGRESS_ACL(esw->dev, ft_support)) 1030 esw_warn(esw->dev, "E-Switch ingress ACL is not supported by FW\n"); 1031 1032 if (!MLX5_CAP_ESW_EGRESS_ACL(esw->dev, ft_support)) 1033 esw_warn(esw->dev, "E-Switch engress ACL is not supported by FW\n"); 1034 1035 esw_info(esw->dev, "E-Switch enable SRIOV: nvfs(%d)\n", nvfs); 1036 1037 esw_disable_vport(esw, 0); 1038 1039 err = esw_create_fdb_table(esw); 1040 if (err) 1041 goto abort; 1042 1043 for (i = 0; i <= nvfs; i++) 1044 esw_enable_vport(esw, i, SRIOV_VPORT_EVENTS); 1045 1046 esw_info(esw->dev, "SRIOV enabled: active vports(%d)\n", 1047 esw->enabled_vports); 1048 return 0; 1049 1050 abort: 1051 esw_enable_vport(esw, 0, UC_ADDR_CHANGE); 1052 return err; 1053 } 1054 1055 void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw) 1056 { 1057 int i; 1058 1059 if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) || 1060 MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH) 1061 return; 1062 1063 esw_info(esw->dev, "disable SRIOV: active vports(%d)\n", 1064 esw->enabled_vports); 1065 1066 for (i = 0; i < esw->total_vports; i++) 1067 esw_disable_vport(esw, i); 1068 1069 esw_destroy_fdb_table(esw); 1070 1071 /* VPORT 0 (PF) must be enabled back with non-sriov configuration */ 1072 esw_enable_vport(esw, 0, UC_ADDR_CHANGE); 1073 } 1074 1075 int mlx5_eswitch_init(struct mlx5_core_dev *dev, int total_vports) 1076 { 1077 int l2_table_size = 1 << MLX5_CAP_GEN(dev, log_max_l2_table); 1078 struct mlx5_eswitch *esw; 1079 int vport_num; 1080 int err; 1081 1082 if (!MLX5_CAP_GEN(dev, vport_group_manager) || 1083 MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH) 1084 return 0; 1085 1086 esw_info(dev, 1087 "Total vports %d, l2 table size(%d), per vport: max uc(%d) max mc(%d)\n", 1088 total_vports, l2_table_size, 1089 MLX5_MAX_UC_PER_VPORT(dev), 1090 MLX5_MAX_MC_PER_VPORT(dev)); 1091 1092 esw = kzalloc(sizeof(*esw), GFP_KERNEL); 1093 if (!esw) 1094 return -ENOMEM; 1095 1096 esw->dev = dev; 1097 1098 esw->l2_table.bitmap = kcalloc(BITS_TO_LONGS(l2_table_size), 1099 sizeof(uintptr_t), GFP_KERNEL); 1100 if (!esw->l2_table.bitmap) { 1101 err = -ENOMEM; 1102 goto abort; 1103 } 1104 esw->l2_table.size = l2_table_size; 1105 1106 esw->work_queue = create_singlethread_workqueue("mlx5_esw_wq"); 1107 if (!esw->work_queue) { 1108 err = -ENOMEM; 1109 goto abort; 1110 } 1111 1112 esw->vports = kcalloc(total_vports, sizeof(struct mlx5_vport), 1113 GFP_KERNEL); 1114 if (!esw->vports) { 1115 err = -ENOMEM; 1116 goto abort; 1117 } 1118 1119 for (vport_num = 0; vport_num < total_vports; vport_num++) { 1120 struct mlx5_vport *vport = &esw->vports[vport_num]; 1121 1122 vport->vport = vport_num; 1123 vport->dev = dev; 1124 INIT_WORK(&vport->vport_change_handler, 1125 esw_vport_change_handler); 1126 spin_lock_init(&vport->lock); 1127 mutex_init(&vport->state_lock); 1128 } 1129 1130 esw->total_vports = total_vports; 1131 esw->enabled_vports = 0; 1132 1133 dev->priv.eswitch = esw; 1134 esw_enable_vport(esw, 0, UC_ADDR_CHANGE); 1135 /* VF Vports will be enabled when SRIOV is enabled */ 1136 return 0; 1137 abort: 1138 if (esw->work_queue) 1139 destroy_workqueue(esw->work_queue); 1140 kfree(esw->l2_table.bitmap); 1141 kfree(esw->vports); 1142 kfree(esw); 1143 return err; 1144 } 1145 1146 void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) 1147 { 1148 if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) || 1149 MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH) 1150 return; 1151 1152 esw_info(esw->dev, "cleanup\n"); 1153 esw_disable_vport(esw, 0); 1154 1155 esw->dev->priv.eswitch = NULL; 1156 destroy_workqueue(esw->work_queue); 1157 kfree(esw->l2_table.bitmap); 1158 kfree(esw->vports); 1159 kfree(esw); 1160 } 1161 1162 void mlx5_eswitch_vport_event(struct mlx5_eswitch *esw, struct mlx5_eqe *eqe) 1163 { 1164 struct mlx5_eqe_vport_change *vc_eqe = &eqe->data.vport_change; 1165 u16 vport_num = be16_to_cpu(vc_eqe->vport_num); 1166 struct mlx5_vport *vport; 1167 1168 if (!esw) { 1169 printf("mlx5_core: WARN: ""MLX5 E-Switch: vport %d got an event while eswitch is not initialized\n", vport_num); 1170 return; 1171 } 1172 1173 vport = &esw->vports[vport_num]; 1174 spin_lock(&vport->lock); 1175 if (vport->enabled) 1176 queue_work(esw->work_queue, &vport->vport_change_handler); 1177 spin_unlock(&vport->lock); 1178 } 1179 1180 /* Vport Administration */ 1181 #define ESW_ALLOWED(esw) \ 1182 (esw && MLX5_CAP_GEN(esw->dev, vport_group_manager) && mlx5_core_is_pf(esw->dev)) 1183 #define LEGAL_VPORT(esw, vport) (vport >= 0 && vport < esw->total_vports) 1184 1185 static void node_guid_gen_from_mac(u64 *node_guid, u8 mac[ETH_ALEN]) 1186 { 1187 ((u8 *)node_guid)[7] = mac[0]; 1188 ((u8 *)node_guid)[6] = mac[1]; 1189 ((u8 *)node_guid)[5] = mac[2]; 1190 ((u8 *)node_guid)[4] = 0xff; 1191 ((u8 *)node_guid)[3] = 0xfe; 1192 ((u8 *)node_guid)[2] = mac[3]; 1193 ((u8 *)node_guid)[1] = mac[4]; 1194 ((u8 *)node_guid)[0] = mac[5]; 1195 } 1196 1197 int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw, 1198 int vport, u8 mac[ETH_ALEN]) 1199 { 1200 int err = 0; 1201 u64 node_guid; 1202 1203 if (!ESW_ALLOWED(esw)) 1204 return -EPERM; 1205 if (!LEGAL_VPORT(esw, vport)) 1206 return -EINVAL; 1207 1208 err = mlx5_modify_nic_vport_mac_address(esw->dev, vport, mac); 1209 if (err) { 1210 mlx5_core_warn(esw->dev, 1211 "Failed to mlx5_modify_nic_vport_mac vport(%d) err=(%d)\n", 1212 vport, err); 1213 return err; 1214 } 1215 1216 node_guid_gen_from_mac(&node_guid, mac); 1217 err = mlx5_modify_nic_vport_node_guid(esw->dev, vport, node_guid); 1218 if (err) { 1219 mlx5_core_warn(esw->dev, 1220 "Failed to mlx5_modify_nic_vport_node_guid vport(%d) err=(%d)\n", 1221 vport, err); 1222 return err; 1223 } 1224 1225 return err; 1226 } 1227 1228 int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw, 1229 int vport, int link_state) 1230 { 1231 if (!ESW_ALLOWED(esw)) 1232 return -EPERM; 1233 if (!LEGAL_VPORT(esw, vport)) 1234 return -EINVAL; 1235 1236 return mlx5_modify_vport_admin_state(esw->dev, 1237 MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT, 1238 vport, link_state); 1239 } 1240 1241 int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw, 1242 int vport, struct mlx5_esw_vport_info *ivi) 1243 { 1244 u16 vlan; 1245 u8 qos; 1246 1247 if (!ESW_ALLOWED(esw)) 1248 return -EPERM; 1249 if (!LEGAL_VPORT(esw, vport)) 1250 return -EINVAL; 1251 1252 memset(ivi, 0, sizeof(*ivi)); 1253 ivi->vf = vport - 1; 1254 1255 mlx5_query_nic_vport_mac_address(esw->dev, vport, ivi->mac); 1256 ivi->linkstate = mlx5_query_vport_admin_state(esw->dev, 1257 MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT, 1258 vport); 1259 query_esw_vport_cvlan(esw->dev, vport, &vlan, &qos); 1260 ivi->vlan = vlan; 1261 ivi->qos = qos; 1262 ivi->spoofchk = 0; 1263 1264 return 0; 1265 } 1266 1267 int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw, 1268 int vport, u16 vlan, u8 qos) 1269 { 1270 struct mlx5_vport *evport; 1271 int err = 0; 1272 int set = 0; 1273 1274 if (!ESW_ALLOWED(esw)) 1275 return -EPERM; 1276 if (!LEGAL_VPORT(esw, vport) || (vlan > 4095) || (qos > 7)) 1277 return -EINVAL; 1278 1279 if (vlan || qos) 1280 set = 1; 1281 1282 evport = &esw->vports[vport]; 1283 1284 err = modify_esw_vport_cvlan(esw->dev, vport, vlan, qos, set); 1285 if (err) 1286 return err; 1287 1288 mutex_lock(&evport->state_lock); 1289 evport->vlan = vlan; 1290 evport->qos = qos; 1291 if (evport->enabled) { 1292 esw_vport_ingress_config(esw, evport); 1293 esw_vport_egress_config(esw, evport); 1294 } 1295 mutex_unlock(&evport->state_lock); 1296 return err; 1297 } 1298 1299