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