1219820Sjeff/* 2272027Shselasky * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff */ 32219820Sjeff 33300676Shselasky#define LINUXKPI_PARAM_PREFIX mlx4_ 34300676Shselasky 35219820Sjeff#include <linux/errno.h> 36219820Sjeff#include <linux/if_ether.h> 37272027Shselasky#include <linux/module.h> 38272027Shselasky#include <linux/err.h> 39219820Sjeff 40306486Shselasky#include <dev/mlx4/cmd.h> 41255932Salfred#include <linux/moduleparam.h> 42329159Shselasky 43329159Shselasky#include <rdma/ib_verbs.h> 44329159Shselasky 45219820Sjeff#include "mlx4.h" 46306486Shselasky#include <dev/mlx4/stats.h> 47219820Sjeff 48219820Sjeff#define MLX4_MAC_VALID (1ull << 63) 49219820Sjeff 50219820Sjeff#define MLX4_VLAN_VALID (1u << 31) 51219820Sjeff#define MLX4_VLAN_MASK 0xfff 52219820Sjeff 53329159Shselasky#define MLX4_STATS_TRAFFIC_COUNTERS_MASK 0xfULL 54329159Shselasky#define MLX4_STATS_TRAFFIC_DROPS_MASK 0xc0ULL 55329159Shselasky#define MLX4_STATS_ERROR_COUNTERS_MASK 0x1ffc30ULL 56329159Shselasky#define MLX4_STATS_PORT_COUNTERS_MASK 0x1fe00000ULL 57329159Shselasky 58329159Shselasky#define MLX4_FLAG_V_IGNORE_FCS_MASK 0x2 59329159Shselasky#define MLX4_IGNORE_FCS_MASK 0x1 60329159Shselasky#define MLX4_TC_MAX_NUMBER 8 61329159Shselasky 62219820Sjeffvoid mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table) 63219820Sjeff{ 64219820Sjeff int i; 65219820Sjeff 66219820Sjeff mutex_init(&table->mutex); 67219820Sjeff for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 68219820Sjeff table->entries[i] = 0; 69219820Sjeff table->refs[i] = 0; 70329159Shselasky table->is_dup[i] = false; 71219820Sjeff } 72219820Sjeff table->max = 1 << dev->caps.log_num_macs; 73219820Sjeff table->total = 0; 74219820Sjeff} 75219820Sjeff 76219820Sjeffvoid mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table) 77219820Sjeff{ 78219820Sjeff int i; 79219820Sjeff 80219820Sjeff mutex_init(&table->mutex); 81219820Sjeff for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 82219820Sjeff table->entries[i] = 0; 83219820Sjeff table->refs[i] = 0; 84329159Shselasky table->is_dup[i] = false; 85219820Sjeff } 86255932Salfred table->max = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR; 87219820Sjeff table->total = 0; 88219820Sjeff} 89219820Sjeff 90329159Shselaskyvoid mlx4_init_roce_gid_table(struct mlx4_dev *dev, 91329159Shselasky struct mlx4_roce_gid_table *table) 92329159Shselasky{ 93329159Shselasky int i; 94329159Shselasky 95329159Shselasky mutex_init(&table->mutex); 96329159Shselasky for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) 97329159Shselasky memset(table->roce_gids[i].raw, 0, MLX4_ROCE_GID_ENTRY_SIZE); 98329159Shselasky} 99329159Shselasky 100255932Salfredstatic int validate_index(struct mlx4_dev *dev, 101255932Salfred struct mlx4_mac_table *table, int index) 102255932Salfred{ 103255932Salfred int err = 0; 104255932Salfred 105329159Shselasky if (index < 0 || index >= table->max || !table->entries[index]) { 106255932Salfred mlx4_warn(dev, "No valid Mac entry for the given index\n"); 107255932Salfred err = -EINVAL; 108255932Salfred } 109255932Salfred return err; 110255932Salfred} 111255932Salfred 112255932Salfredstatic int find_index(struct mlx4_dev *dev, 113255932Salfred struct mlx4_mac_table *table, u64 mac) 114255932Salfred{ 115255932Salfred int i; 116255932Salfred 117255932Salfred for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 118329159Shselasky if (table->refs[i] && 119329159Shselasky (MLX4_MAC_MASK & mac) == 120255932Salfred (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) 121255932Salfred return i; 122255932Salfred } 123255932Salfred /* Mac not found */ 124255932Salfred return -EINVAL; 125255932Salfred} 126255932Salfred 127219820Sjeffstatic int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, 128219820Sjeff __be64 *entries) 129219820Sjeff{ 130219820Sjeff struct mlx4_cmd_mailbox *mailbox; 131219820Sjeff u32 in_mod; 132219820Sjeff int err; 133219820Sjeff 134219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 135219820Sjeff if (IS_ERR(mailbox)) 136219820Sjeff return PTR_ERR(mailbox); 137219820Sjeff 138219820Sjeff memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); 139219820Sjeff 140219820Sjeff in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; 141255932Salfred 142329159Shselasky err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 143329159Shselasky MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 144329159Shselasky MLX4_CMD_NATIVE); 145219820Sjeff 146219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 147219820Sjeff return err; 148219820Sjeff} 149219820Sjeff 150329159Shselaskyint mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx) 151329159Shselasky{ 152329159Shselasky struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 153329159Shselasky struct mlx4_mac_table *table = &info->mac_table; 154329159Shselasky int i; 155329159Shselasky 156329159Shselasky for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 157329159Shselasky if (!table->refs[i]) 158329159Shselasky continue; 159329159Shselasky 160329159Shselasky if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 161329159Shselasky *idx = i; 162329159Shselasky return 0; 163329159Shselasky } 164329159Shselasky } 165329159Shselasky 166329159Shselasky return -ENOENT; 167329159Shselasky} 168329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_find_cached_mac); 169329159Shselasky 170329159Shselaskystatic bool mlx4_need_mf_bond(struct mlx4_dev *dev) 171329159Shselasky{ 172329159Shselasky int i, num_eth_ports = 0; 173329159Shselasky 174329159Shselasky if (!mlx4_is_mfunc(dev)) 175329159Shselasky return false; 176329159Shselasky mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) 177329159Shselasky ++num_eth_ports; 178329159Shselasky 179329159Shselasky return (num_eth_ports == 2) ? true : false; 180329159Shselasky} 181329159Shselasky 182255932Salfredint __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 183219820Sjeff{ 184255932Salfred struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 185255932Salfred struct mlx4_mac_table *table = &info->mac_table; 186219820Sjeff int i, err = 0; 187219820Sjeff int free = -1; 188329159Shselasky int free_for_dup = -1; 189329159Shselasky bool dup = mlx4_is_mf_bonded(dev); 190329159Shselasky u8 dup_port = (port == 1) ? 2 : 1; 191329159Shselasky struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table; 192329159Shselasky bool need_mf_bond = mlx4_need_mf_bond(dev); 193329159Shselasky bool can_mf_bond = true; 194219820Sjeff 195329159Shselasky mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d %s duplicate\n", 196329159Shselasky (unsigned long long)mac, port, 197329159Shselasky dup ? "with" : "without"); 198255932Salfred 199329159Shselasky if (need_mf_bond) { 200329159Shselasky if (port == 1) { 201329159Shselasky mutex_lock(&table->mutex); 202329159Shselasky mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 203329159Shselasky } else { 204329159Shselasky mutex_lock(&dup_table->mutex); 205329159Shselasky mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 206329159Shselasky } 207329159Shselasky } else { 208329159Shselasky mutex_lock(&table->mutex); 209329159Shselasky } 210329159Shselasky 211329159Shselasky if (need_mf_bond) { 212329159Shselasky int index_at_port = -1; 213329159Shselasky int index_at_dup_port = -1; 214329159Shselasky 215329159Shselasky for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 216329159Shselasky if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))) 217329159Shselasky index_at_port = i; 218329159Shselasky if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i])))) 219329159Shselasky index_at_dup_port = i; 220329159Shselasky } 221329159Shselasky 222329159Shselasky /* check that same mac is not in the tables at different indices */ 223329159Shselasky if ((index_at_port != index_at_dup_port) && 224329159Shselasky (index_at_port >= 0) && 225329159Shselasky (index_at_dup_port >= 0)) 226329159Shselasky can_mf_bond = false; 227329159Shselasky 228329159Shselasky /* If the mac is already in the primary table, the slot must be 229329159Shselasky * available in the duplicate table as well. 230329159Shselasky */ 231329159Shselasky if (index_at_port >= 0 && index_at_dup_port < 0 && 232329159Shselasky dup_table->refs[index_at_port]) { 233329159Shselasky can_mf_bond = false; 234329159Shselasky } 235329159Shselasky /* If the mac is already in the duplicate table, check that the 236329159Shselasky * corresponding index is not occupied in the primary table, or 237329159Shselasky * the primary table already contains the mac at the same index. 238329159Shselasky * Otherwise, you cannot bond (primary contains a different mac 239329159Shselasky * at that index). 240329159Shselasky */ 241329159Shselasky if (index_at_dup_port >= 0) { 242329159Shselasky if (!table->refs[index_at_dup_port] || 243329159Shselasky ((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[index_at_dup_port])))) 244329159Shselasky free_for_dup = index_at_dup_port; 245329159Shselasky else 246329159Shselasky can_mf_bond = false; 247329159Shselasky } 248329159Shselasky } 249329159Shselasky 250255932Salfred for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 251329159Shselasky if (!table->refs[i]) { 252329159Shselasky if (free < 0) 253329159Shselasky free = i; 254329159Shselasky if (free_for_dup < 0 && need_mf_bond && can_mf_bond) { 255329159Shselasky if (!dup_table->refs[i]) 256329159Shselasky free_for_dup = i; 257329159Shselasky } 258219820Sjeff continue; 259219820Sjeff } 260219820Sjeff 261329159Shselasky if ((MLX4_MAC_MASK & mac) == 262329159Shselasky (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 263329159Shselasky /* MAC already registered, increment ref count */ 264272027Shselasky err = i; 265219820Sjeff ++table->refs[i]; 266329159Shselasky if (dup) { 267329159Shselasky u64 dup_mac = MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]); 268329159Shselasky 269329159Shselasky if (dup_mac != mac || !dup_table->is_dup[i]) { 270329159Shselasky mlx4_warn(dev, "register mac: expect duplicate mac 0x%llx on port %d index %d\n", 271329159Shselasky (long long)mac, dup_port, i); 272329159Shselasky } 273329159Shselasky } 274219820Sjeff goto out; 275219820Sjeff } 276219820Sjeff } 277219820Sjeff 278329159Shselasky if (need_mf_bond && (free_for_dup < 0)) { 279329159Shselasky if (dup) { 280329159Shselasky mlx4_warn(dev, "Fail to allocate duplicate MAC table entry\n"); 281329159Shselasky mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n"); 282329159Shselasky dup = false; 283329159Shselasky } 284329159Shselasky can_mf_bond = false; 285329159Shselasky } 286329159Shselasky 287329159Shselasky if (need_mf_bond && can_mf_bond) 288329159Shselasky free = free_for_dup; 289329159Shselasky 290219820Sjeff mlx4_dbg(dev, "Free MAC index is %d\n", free); 291219820Sjeff 292219820Sjeff if (table->total == table->max) { 293219820Sjeff /* No free mac entries */ 294219820Sjeff err = -ENOSPC; 295219820Sjeff goto out; 296219820Sjeff } 297219820Sjeff 298219820Sjeff /* Register new MAC */ 299219820Sjeff table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); 300219820Sjeff 301219820Sjeff err = mlx4_set_port_mac_table(dev, port, table->entries); 302219820Sjeff if (unlikely(err)) { 303255932Salfred mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 304255932Salfred (unsigned long long) mac); 305219820Sjeff table->entries[free] = 0; 306219820Sjeff goto out; 307219820Sjeff } 308255932Salfred table->refs[free] = 1; 309329159Shselasky table->is_dup[free] = false; 310329159Shselasky ++table->total; 311329159Shselasky if (dup) { 312329159Shselasky dup_table->refs[free] = 0; 313329159Shselasky dup_table->is_dup[free] = true; 314329159Shselasky dup_table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); 315219820Sjeff 316329159Shselasky err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries); 317329159Shselasky if (unlikely(err)) { 318329159Shselasky mlx4_warn(dev, "Failed adding duplicate mac: 0x%llx\n", (long long)mac); 319329159Shselasky dup_table->is_dup[free] = false; 320329159Shselasky dup_table->entries[free] = 0; 321329159Shselasky goto out; 322329159Shselasky } 323329159Shselasky ++dup_table->total; 324329159Shselasky } 325255932Salfred err = free; 326219820Sjeffout: 327329159Shselasky if (need_mf_bond) { 328329159Shselasky if (port == 2) { 329329159Shselasky mutex_unlock(&table->mutex); 330329159Shselasky mutex_unlock(&dup_table->mutex); 331329159Shselasky } else { 332329159Shselasky mutex_unlock(&dup_table->mutex); 333329159Shselasky mutex_unlock(&table->mutex); 334329159Shselasky } 335329159Shselasky } else { 336329159Shselasky mutex_unlock(&table->mutex); 337329159Shselasky } 338219820Sjeff return err; 339219820Sjeff} 340255932SalfredEXPORT_SYMBOL_GPL(__mlx4_register_mac); 341255932Salfred 342255932Salfredint mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 343255932Salfred{ 344255932Salfred u64 out_param = 0; 345272027Shselasky int err = -EINVAL; 346255932Salfred 347255932Salfred if (mlx4_is_mfunc(dev)) { 348272027Shselasky if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 349272027Shselasky err = mlx4_cmd_imm(dev, mac, &out_param, 350272027Shselasky ((u32) port) << 8 | (u32) RES_MAC, 351272027Shselasky RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 352272027Shselasky MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 353272027Shselasky } 354272027Shselasky if (err && err == -EINVAL && mlx4_is_slave(dev)) { 355272027Shselasky /* retry using old REG_MAC format */ 356272027Shselasky set_param_l(&out_param, port); 357272027Shselasky err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 358272027Shselasky RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 359272027Shselasky MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 360272027Shselasky if (!err) 361272027Shselasky dev->flags |= MLX4_FLAG_OLD_REG_MAC; 362272027Shselasky } 363255932Salfred if (err) 364255932Salfred return err; 365255932Salfred 366255932Salfred return get_param_l(&out_param); 367255932Salfred } 368255932Salfred return __mlx4_register_mac(dev, port, mac); 369255932Salfred} 370219820SjeffEXPORT_SYMBOL_GPL(mlx4_register_mac); 371219820Sjeff 372255932Salfredint mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port) 373219820Sjeff{ 374255932Salfred return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] + 375255932Salfred (port - 1) * (1 << dev->caps.log_num_macs); 376255932Salfred} 377255932SalfredEXPORT_SYMBOL_GPL(mlx4_get_base_qpn); 378219820Sjeff 379255932Salfredvoid __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 380255932Salfred{ 381255932Salfred struct mlx4_port_info *info; 382255932Salfred struct mlx4_mac_table *table; 383255932Salfred int index; 384329159Shselasky bool dup = mlx4_is_mf_bonded(dev); 385329159Shselasky u8 dup_port = (port == 1) ? 2 : 1; 386329159Shselasky struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table; 387255932Salfred 388255932Salfred if (port < 1 || port > dev->caps.num_ports) { 389255932Salfred mlx4_warn(dev, "invalid port number (%d), aborting...\n", port); 390255932Salfred return; 391255932Salfred } 392255932Salfred info = &mlx4_priv(dev)->port[port]; 393255932Salfred table = &info->mac_table; 394255932Salfred 395329159Shselasky if (dup) { 396329159Shselasky if (port == 1) { 397329159Shselasky mutex_lock(&table->mutex); 398329159Shselasky mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 399329159Shselasky } else { 400329159Shselasky mutex_lock(&dup_table->mutex); 401329159Shselasky mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 402329159Shselasky } 403329159Shselasky } else { 404329159Shselasky mutex_lock(&table->mutex); 405329159Shselasky } 406329159Shselasky 407255932Salfred index = find_index(dev, table, mac); 408255932Salfred 409255932Salfred if (validate_index(dev, table, index)) 410219820Sjeff goto out; 411255932Salfred 412329159Shselasky if (--table->refs[index] || table->is_dup[index]) { 413329159Shselasky mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n", 414329159Shselasky index); 415329159Shselasky if (!table->refs[index]) 416329159Shselasky dup_table->is_dup[index] = false; 417219820Sjeff goto out; 418219820Sjeff } 419255932Salfred 420219820Sjeff table->entries[index] = 0; 421329159Shselasky if (mlx4_set_port_mac_table(dev, port, table->entries)) 422329159Shselasky mlx4_warn(dev, "Fail to set mac in port %d during unregister\n", port); 423219820Sjeff --table->total; 424329159Shselasky 425329159Shselasky if (dup) { 426329159Shselasky dup_table->is_dup[index] = false; 427329159Shselasky if (dup_table->refs[index]) 428329159Shselasky goto out; 429329159Shselasky dup_table->entries[index] = 0; 430329159Shselasky if (mlx4_set_port_mac_table(dev, dup_port, dup_table->entries)) 431329159Shselasky mlx4_warn(dev, "Fail to set mac in duplicate port %d during unregister\n", dup_port); 432329159Shselasky 433329159Shselasky --table->total; 434329159Shselasky } 435219820Sjeffout: 436329159Shselasky if (dup) { 437329159Shselasky if (port == 2) { 438329159Shselasky mutex_unlock(&table->mutex); 439329159Shselasky mutex_unlock(&dup_table->mutex); 440329159Shselasky } else { 441329159Shselasky mutex_unlock(&dup_table->mutex); 442329159Shselasky mutex_unlock(&table->mutex); 443329159Shselasky } 444329159Shselasky } else { 445329159Shselasky mutex_unlock(&table->mutex); 446329159Shselasky } 447219820Sjeff} 448255932SalfredEXPORT_SYMBOL_GPL(__mlx4_unregister_mac); 449255932Salfred 450255932Salfredvoid mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 451255932Salfred{ 452255932Salfred u64 out_param = 0; 453255932Salfred 454255932Salfred if (mlx4_is_mfunc(dev)) { 455272027Shselasky if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 456272027Shselasky (void) mlx4_cmd_imm(dev, mac, &out_param, 457272027Shselasky ((u32) port) << 8 | (u32) RES_MAC, 458272027Shselasky RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 459272027Shselasky MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 460272027Shselasky } else { 461272027Shselasky /* use old unregister mac format */ 462272027Shselasky set_param_l(&out_param, port); 463272027Shselasky (void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 464272027Shselasky RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 465272027Shselasky MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 466272027Shselasky } 467255932Salfred return; 468255932Salfred } 469255932Salfred __mlx4_unregister_mac(dev, port, mac); 470255932Salfred return; 471255932Salfred} 472219820SjeffEXPORT_SYMBOL_GPL(mlx4_unregister_mac); 473219820Sjeff 474255932Salfredint __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac) 475255932Salfred{ 476255932Salfred struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 477255932Salfred struct mlx4_mac_table *table = &info->mac_table; 478255932Salfred int index = qpn - info->base_qpn; 479255932Salfred int err = 0; 480329159Shselasky bool dup = mlx4_is_mf_bonded(dev); 481329159Shselasky u8 dup_port = (port == 1) ? 2 : 1; 482329159Shselasky struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table; 483255932Salfred 484255932Salfred /* CX1 doesn't support multi-functions */ 485329159Shselasky if (dup) { 486329159Shselasky if (port == 1) { 487329159Shselasky mutex_lock(&table->mutex); 488329159Shselasky mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 489329159Shselasky } else { 490329159Shselasky mutex_lock(&dup_table->mutex); 491329159Shselasky mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 492329159Shselasky } 493329159Shselasky } else { 494329159Shselasky mutex_lock(&table->mutex); 495329159Shselasky } 496255932Salfred 497255932Salfred err = validate_index(dev, table, index); 498255932Salfred if (err) 499255932Salfred goto out; 500255932Salfred 501255932Salfred table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); 502255932Salfred 503255932Salfred err = mlx4_set_port_mac_table(dev, port, table->entries); 504255932Salfred if (unlikely(err)) { 505255932Salfred mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 506255932Salfred (unsigned long long) new_mac); 507255932Salfred table->entries[index] = 0; 508329159Shselasky } else { 509329159Shselasky if (dup) { 510329159Shselasky dup_table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); 511329159Shselasky 512329159Shselasky err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries); 513329159Shselasky if (unlikely(err)) { 514329159Shselasky mlx4_err(dev, "Failed adding duplicate MAC: 0x%llx\n", 515329159Shselasky (unsigned long long)new_mac); 516329159Shselasky dup_table->entries[index] = 0; 517329159Shselasky } 518329159Shselasky } 519255932Salfred } 520255932Salfredout: 521329159Shselasky if (dup) { 522329159Shselasky if (port == 2) { 523329159Shselasky mutex_unlock(&table->mutex); 524329159Shselasky mutex_unlock(&dup_table->mutex); 525329159Shselasky } else { 526329159Shselasky mutex_unlock(&dup_table->mutex); 527329159Shselasky mutex_unlock(&table->mutex); 528329159Shselasky } 529329159Shselasky } else { 530329159Shselasky mutex_unlock(&table->mutex); 531329159Shselasky } 532255932Salfred return err; 533255932Salfred} 534255932SalfredEXPORT_SYMBOL_GPL(__mlx4_replace_mac); 535255932Salfred 536219820Sjeffstatic int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, 537219820Sjeff __be32 *entries) 538219820Sjeff{ 539219820Sjeff struct mlx4_cmd_mailbox *mailbox; 540219820Sjeff u32 in_mod; 541219820Sjeff int err; 542219820Sjeff 543219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 544219820Sjeff if (IS_ERR(mailbox)) 545219820Sjeff return PTR_ERR(mailbox); 546219820Sjeff 547219820Sjeff memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); 548219820Sjeff in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; 549329159Shselasky err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 550329159Shselasky MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 551329159Shselasky MLX4_CMD_NATIVE); 552219820Sjeff 553219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 554219820Sjeff 555219820Sjeff return err; 556219820Sjeff} 557219820Sjeff 558219820Sjeffint mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx) 559219820Sjeff{ 560219820Sjeff struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 561219820Sjeff int i; 562219820Sjeff 563219820Sjeff for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) { 564219820Sjeff if (table->refs[i] && 565219820Sjeff (vid == (MLX4_VLAN_MASK & 566219820Sjeff be32_to_cpu(table->entries[i])))) { 567255932Salfred /* VLAN already registered, increase reference count */ 568219820Sjeff *idx = i; 569219820Sjeff return 0; 570219820Sjeff } 571219820Sjeff } 572219820Sjeff 573219820Sjeff return -ENOENT; 574219820Sjeff} 575219820SjeffEXPORT_SYMBOL_GPL(mlx4_find_cached_vlan); 576219820Sjeff 577255932Salfredint __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, 578255932Salfred int *index) 579219820Sjeff{ 580219820Sjeff struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 581219820Sjeff int i, err = 0; 582219820Sjeff int free = -1; 583329159Shselasky int free_for_dup = -1; 584329159Shselasky bool dup = mlx4_is_mf_bonded(dev); 585329159Shselasky u8 dup_port = (port == 1) ? 2 : 1; 586329159Shselasky struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table; 587329159Shselasky bool need_mf_bond = mlx4_need_mf_bond(dev); 588329159Shselasky bool can_mf_bond = true; 589219820Sjeff 590329159Shselasky mlx4_dbg(dev, "Registering VLAN: %d for port %d %s duplicate\n", 591329159Shselasky vlan, port, 592329159Shselasky dup ? "with" : "without"); 593255932Salfred 594329159Shselasky if (need_mf_bond) { 595329159Shselasky if (port == 1) { 596329159Shselasky mutex_lock(&table->mutex); 597329159Shselasky mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 598329159Shselasky } else { 599329159Shselasky mutex_lock(&dup_table->mutex); 600329159Shselasky mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 601329159Shselasky } 602329159Shselasky } else { 603329159Shselasky mutex_lock(&table->mutex); 604329159Shselasky } 605329159Shselasky 606255932Salfred if (table->total == table->max) { 607255932Salfred /* No free vlan entries */ 608255932Salfred err = -ENOSPC; 609255932Salfred goto out; 610255932Salfred } 611255932Salfred 612329159Shselasky if (need_mf_bond) { 613329159Shselasky int index_at_port = -1; 614329159Shselasky int index_at_dup_port = -1; 615329159Shselasky 616329159Shselasky for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 617329159Shselasky if (vlan == (MLX4_VLAN_MASK & be32_to_cpu(table->entries[i]))) 618329159Shselasky index_at_port = i; 619329159Shselasky if (vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i]))) 620329159Shselasky index_at_dup_port = i; 621329159Shselasky } 622329159Shselasky /* check that same vlan is not in the tables at different indices */ 623329159Shselasky if ((index_at_port != index_at_dup_port) && 624329159Shselasky (index_at_port >= 0) && 625329159Shselasky (index_at_dup_port >= 0)) 626329159Shselasky can_mf_bond = false; 627329159Shselasky 628329159Shselasky /* If the vlan is already in the primary table, the slot must be 629329159Shselasky * available in the duplicate table as well. 630329159Shselasky */ 631329159Shselasky if (index_at_port >= 0 && index_at_dup_port < 0 && 632329159Shselasky dup_table->refs[index_at_port]) { 633329159Shselasky can_mf_bond = false; 634329159Shselasky } 635329159Shselasky /* If the vlan is already in the duplicate table, check that the 636329159Shselasky * corresponding index is not occupied in the primary table, or 637329159Shselasky * the primary table already contains the vlan at the same index. 638329159Shselasky * Otherwise, you cannot bond (primary contains a different vlan 639329159Shselasky * at that index). 640329159Shselasky */ 641329159Shselasky if (index_at_dup_port >= 0) { 642329159Shselasky if (!table->refs[index_at_dup_port] || 643329159Shselasky (vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[index_at_dup_port])))) 644329159Shselasky free_for_dup = index_at_dup_port; 645329159Shselasky else 646329159Shselasky can_mf_bond = false; 647329159Shselasky } 648329159Shselasky } 649329159Shselasky 650219820Sjeff for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 651329159Shselasky if (!table->refs[i]) { 652329159Shselasky if (free < 0) 653329159Shselasky free = i; 654329159Shselasky if (free_for_dup < 0 && need_mf_bond && can_mf_bond) { 655329159Shselasky if (!dup_table->refs[i]) 656329159Shselasky free_for_dup = i; 657329159Shselasky } 658219820Sjeff } 659219820Sjeff 660329159Shselasky if ((table->refs[i] || table->is_dup[i]) && 661219820Sjeff (vlan == (MLX4_VLAN_MASK & 662219820Sjeff be32_to_cpu(table->entries[i])))) { 663255932Salfred /* Vlan already registered, increase references count */ 664329159Shselasky mlx4_dbg(dev, "vlan %u is already registered.\n", vlan); 665219820Sjeff *index = i; 666219820Sjeff ++table->refs[i]; 667329159Shselasky if (dup) { 668329159Shselasky u16 dup_vlan = MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i]); 669329159Shselasky 670329159Shselasky if (dup_vlan != vlan || !dup_table->is_dup[i]) { 671329159Shselasky mlx4_warn(dev, "register vlan: expected duplicate vlan %u on port %d index %d\n", 672329159Shselasky vlan, dup_port, i); 673329159Shselasky } 674329159Shselasky } 675219820Sjeff goto out; 676219820Sjeff } 677219820Sjeff } 678219820Sjeff 679329159Shselasky if (need_mf_bond && (free_for_dup < 0)) { 680329159Shselasky if (dup) { 681329159Shselasky mlx4_warn(dev, "Fail to allocate duplicate VLAN table entry\n"); 682329159Shselasky mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n"); 683329159Shselasky dup = false; 684329159Shselasky } 685329159Shselasky can_mf_bond = false; 686329159Shselasky } 687329159Shselasky 688329159Shselasky if (need_mf_bond && can_mf_bond) 689329159Shselasky free = free_for_dup; 690329159Shselasky 691219820Sjeff if (free < 0) { 692219820Sjeff err = -ENOMEM; 693219820Sjeff goto out; 694219820Sjeff } 695219820Sjeff 696255932Salfred /* Register new VLAN */ 697219820Sjeff table->refs[free] = 1; 698329159Shselasky table->is_dup[free] = false; 699219820Sjeff table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 700219820Sjeff 701219820Sjeff err = mlx4_set_port_vlan_table(dev, port, table->entries); 702219820Sjeff if (unlikely(err)) { 703219820Sjeff mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); 704219820Sjeff table->refs[free] = 0; 705219820Sjeff table->entries[free] = 0; 706219820Sjeff goto out; 707219820Sjeff } 708329159Shselasky ++table->total; 709329159Shselasky if (dup) { 710329159Shselasky dup_table->refs[free] = 0; 711329159Shselasky dup_table->is_dup[free] = true; 712329159Shselasky dup_table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 713219820Sjeff 714329159Shselasky err = mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries); 715329159Shselasky if (unlikely(err)) { 716329159Shselasky mlx4_warn(dev, "Failed adding duplicate vlan: %u\n", vlan); 717329159Shselasky dup_table->is_dup[free] = false; 718329159Shselasky dup_table->entries[free] = 0; 719329159Shselasky goto out; 720329159Shselasky } 721329159Shselasky ++dup_table->total; 722329159Shselasky } 723329159Shselasky 724219820Sjeff *index = free; 725219820Sjeffout: 726329159Shselasky if (need_mf_bond) { 727329159Shselasky if (port == 2) { 728329159Shselasky mutex_unlock(&table->mutex); 729329159Shselasky mutex_unlock(&dup_table->mutex); 730329159Shselasky } else { 731329159Shselasky mutex_unlock(&dup_table->mutex); 732329159Shselasky mutex_unlock(&table->mutex); 733329159Shselasky } 734329159Shselasky } else { 735329159Shselasky mutex_unlock(&table->mutex); 736329159Shselasky } 737219820Sjeff return err; 738219820Sjeff} 739255932Salfred 740255932Salfredint mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) 741255932Salfred{ 742255932Salfred u64 out_param = 0; 743255932Salfred int err; 744255932Salfred 745255932Salfred if (vlan > 4095) 746255932Salfred return -EINVAL; 747255932Salfred 748255932Salfred if (mlx4_is_mfunc(dev)) { 749255932Salfred err = mlx4_cmd_imm(dev, vlan, &out_param, 750255932Salfred ((u32) port) << 8 | (u32) RES_VLAN, 751255932Salfred RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 752255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 753255932Salfred if (!err) 754255932Salfred *index = get_param_l(&out_param); 755255932Salfred 756255932Salfred return err; 757255932Salfred } 758255932Salfred return __mlx4_register_vlan(dev, port, vlan, index); 759255932Salfred} 760219820SjeffEXPORT_SYMBOL_GPL(mlx4_register_vlan); 761219820Sjeff 762255932Salfredvoid __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 763219820Sjeff{ 764219820Sjeff struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 765255932Salfred int index; 766329159Shselasky bool dup = mlx4_is_mf_bonded(dev); 767329159Shselasky u8 dup_port = (port == 1) ? 2 : 1; 768329159Shselasky struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table; 769219820Sjeff 770329159Shselasky if (dup) { 771329159Shselasky if (port == 1) { 772329159Shselasky mutex_lock(&table->mutex); 773329159Shselasky mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 774329159Shselasky } else { 775329159Shselasky mutex_lock(&dup_table->mutex); 776329159Shselasky mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 777329159Shselasky } 778329159Shselasky } else { 779329159Shselasky mutex_lock(&table->mutex); 780329159Shselasky } 781329159Shselasky 782255932Salfred if (mlx4_find_cached_vlan(dev, port, vlan, &index)) { 783255932Salfred mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan); 784255932Salfred goto out; 785255932Salfred } 786255932Salfred 787219820Sjeff if (index < MLX4_VLAN_REGULAR) { 788219820Sjeff mlx4_warn(dev, "Trying to free special vlan index %d\n", index); 789255932Salfred goto out; 790219820Sjeff } 791219820Sjeff 792329159Shselasky if (--table->refs[index] || table->is_dup[index]) { 793329159Shselasky mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n", 794329159Shselasky table->refs[index], index); 795329159Shselasky if (!table->refs[index]) 796329159Shselasky dup_table->is_dup[index] = false; 797219820Sjeff goto out; 798219820Sjeff } 799219820Sjeff table->entries[index] = 0; 800329159Shselasky if (mlx4_set_port_vlan_table(dev, port, table->entries)) 801329159Shselasky mlx4_warn(dev, "Fail to set vlan in port %d during unregister\n", port); 802219820Sjeff --table->total; 803329159Shselasky if (dup) { 804329159Shselasky dup_table->is_dup[index] = false; 805329159Shselasky if (dup_table->refs[index]) 806329159Shselasky goto out; 807329159Shselasky dup_table->entries[index] = 0; 808329159Shselasky if (mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries)) 809329159Shselasky mlx4_warn(dev, "Fail to set vlan in duplicate port %d during unregister\n", dup_port); 810329159Shselasky --dup_table->total; 811329159Shselasky } 812219820Sjeffout: 813329159Shselasky if (dup) { 814329159Shselasky if (port == 2) { 815329159Shselasky mutex_unlock(&table->mutex); 816329159Shselasky mutex_unlock(&dup_table->mutex); 817329159Shselasky } else { 818329159Shselasky mutex_unlock(&dup_table->mutex); 819329159Shselasky mutex_unlock(&table->mutex); 820329159Shselasky } 821329159Shselasky } else { 822329159Shselasky mutex_unlock(&table->mutex); 823329159Shselasky } 824219820Sjeff} 825255932Salfred 826255932Salfredvoid mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 827255932Salfred{ 828255932Salfred u64 out_param = 0; 829255932Salfred 830255932Salfred if (mlx4_is_mfunc(dev)) { 831255932Salfred (void) mlx4_cmd_imm(dev, vlan, &out_param, 832255932Salfred ((u32) port) << 8 | (u32) RES_VLAN, 833255932Salfred RES_OP_RESERVE_AND_MAP, 834255932Salfred MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, 835255932Salfred MLX4_CMD_WRAPPED); 836255932Salfred return; 837255932Salfred } 838255932Salfred __mlx4_unregister_vlan(dev, port, vlan); 839255932Salfred} 840219820SjeffEXPORT_SYMBOL_GPL(mlx4_unregister_vlan); 841219820Sjeff 842329159Shselaskyint mlx4_bond_mac_table(struct mlx4_dev *dev) 843329159Shselasky{ 844329159Shselasky struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table; 845329159Shselasky struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table; 846329159Shselasky int ret = 0; 847329159Shselasky int i; 848329159Shselasky bool update1 = false; 849329159Shselasky bool update2 = false; 850329159Shselasky 851329159Shselasky mutex_lock(&t1->mutex); 852329159Shselasky mutex_lock(&t2->mutex); 853329159Shselasky for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 854329159Shselasky if ((t1->entries[i] != t2->entries[i]) && 855329159Shselasky t1->entries[i] && t2->entries[i]) { 856329159Shselasky mlx4_warn(dev, "can't duplicate entry %d in mac table\n", i); 857329159Shselasky ret = -EINVAL; 858329159Shselasky goto unlock; 859329159Shselasky } 860329159Shselasky } 861329159Shselasky 862329159Shselasky for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 863329159Shselasky if (t1->entries[i] && !t2->entries[i]) { 864329159Shselasky t2->entries[i] = t1->entries[i]; 865329159Shselasky t2->is_dup[i] = true; 866329159Shselasky update2 = true; 867329159Shselasky } else if (!t1->entries[i] && t2->entries[i]) { 868329159Shselasky t1->entries[i] = t2->entries[i]; 869329159Shselasky t1->is_dup[i] = true; 870329159Shselasky update1 = true; 871329159Shselasky } else if (t1->entries[i] && t2->entries[i]) { 872329159Shselasky t1->is_dup[i] = true; 873329159Shselasky t2->is_dup[i] = true; 874329159Shselasky } 875329159Shselasky } 876329159Shselasky 877329159Shselasky if (update1) { 878329159Shselasky ret = mlx4_set_port_mac_table(dev, 1, t1->entries); 879329159Shselasky if (ret) 880329159Shselasky mlx4_warn(dev, "failed to set MAC table for port 1 (%d)\n", ret); 881329159Shselasky } 882329159Shselasky if (!ret && update2) { 883329159Shselasky ret = mlx4_set_port_mac_table(dev, 2, t2->entries); 884329159Shselasky if (ret) 885329159Shselasky mlx4_warn(dev, "failed to set MAC table for port 2 (%d)\n", ret); 886329159Shselasky } 887329159Shselasky 888329159Shselasky if (ret) 889329159Shselasky mlx4_warn(dev, "failed to create mirror MAC tables\n"); 890329159Shselaskyunlock: 891329159Shselasky mutex_unlock(&t2->mutex); 892329159Shselasky mutex_unlock(&t1->mutex); 893329159Shselasky return ret; 894329159Shselasky} 895329159Shselasky 896329159Shselaskyint mlx4_unbond_mac_table(struct mlx4_dev *dev) 897329159Shselasky{ 898329159Shselasky struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table; 899329159Shselasky struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table; 900329159Shselasky int ret = 0; 901329159Shselasky int ret1; 902329159Shselasky int i; 903329159Shselasky bool update1 = false; 904329159Shselasky bool update2 = false; 905329159Shselasky 906329159Shselasky mutex_lock(&t1->mutex); 907329159Shselasky mutex_lock(&t2->mutex); 908329159Shselasky for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 909329159Shselasky if (t1->entries[i] != t2->entries[i]) { 910329159Shselasky mlx4_warn(dev, "mac table is in an unexpected state when trying to unbond\n"); 911329159Shselasky ret = -EINVAL; 912329159Shselasky goto unlock; 913329159Shselasky } 914329159Shselasky } 915329159Shselasky 916329159Shselasky for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 917329159Shselasky if (!t1->entries[i]) 918329159Shselasky continue; 919329159Shselasky t1->is_dup[i] = false; 920329159Shselasky if (!t1->refs[i]) { 921329159Shselasky t1->entries[i] = 0; 922329159Shselasky update1 = true; 923329159Shselasky } 924329159Shselasky t2->is_dup[i] = false; 925329159Shselasky if (!t2->refs[i]) { 926329159Shselasky t2->entries[i] = 0; 927329159Shselasky update2 = true; 928329159Shselasky } 929329159Shselasky } 930329159Shselasky 931329159Shselasky if (update1) { 932329159Shselasky ret = mlx4_set_port_mac_table(dev, 1, t1->entries); 933329159Shselasky if (ret) 934329159Shselasky mlx4_warn(dev, "failed to unmirror MAC tables for port 1(%d)\n", ret); 935329159Shselasky } 936329159Shselasky if (update2) { 937329159Shselasky ret1 = mlx4_set_port_mac_table(dev, 2, t2->entries); 938329159Shselasky if (ret1) { 939329159Shselasky mlx4_warn(dev, "failed to unmirror MAC tables for port 2(%d)\n", ret1); 940329159Shselasky ret = ret1; 941329159Shselasky } 942329159Shselasky } 943329159Shselaskyunlock: 944329159Shselasky mutex_unlock(&t2->mutex); 945329159Shselasky mutex_unlock(&t1->mutex); 946329159Shselasky return ret; 947329159Shselasky} 948329159Shselasky 949329159Shselaskyint mlx4_bond_vlan_table(struct mlx4_dev *dev) 950329159Shselasky{ 951329159Shselasky struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table; 952329159Shselasky struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table; 953329159Shselasky int ret = 0; 954329159Shselasky int i; 955329159Shselasky bool update1 = false; 956329159Shselasky bool update2 = false; 957329159Shselasky 958329159Shselasky mutex_lock(&t1->mutex); 959329159Shselasky mutex_lock(&t2->mutex); 960329159Shselasky for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 961329159Shselasky if ((t1->entries[i] != t2->entries[i]) && 962329159Shselasky t1->entries[i] && t2->entries[i]) { 963329159Shselasky mlx4_warn(dev, "can't duplicate entry %d in vlan table\n", i); 964329159Shselasky ret = -EINVAL; 965329159Shselasky goto unlock; 966329159Shselasky } 967329159Shselasky } 968329159Shselasky 969329159Shselasky for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 970329159Shselasky if (t1->entries[i] && !t2->entries[i]) { 971329159Shselasky t2->entries[i] = t1->entries[i]; 972329159Shselasky t2->is_dup[i] = true; 973329159Shselasky update2 = true; 974329159Shselasky } else if (!t1->entries[i] && t2->entries[i]) { 975329159Shselasky t1->entries[i] = t2->entries[i]; 976329159Shselasky t1->is_dup[i] = true; 977329159Shselasky update1 = true; 978329159Shselasky } else if (t1->entries[i] && t2->entries[i]) { 979329159Shselasky t1->is_dup[i] = true; 980329159Shselasky t2->is_dup[i] = true; 981329159Shselasky } 982329159Shselasky } 983329159Shselasky 984329159Shselasky if (update1) { 985329159Shselasky ret = mlx4_set_port_vlan_table(dev, 1, t1->entries); 986329159Shselasky if (ret) 987329159Shselasky mlx4_warn(dev, "failed to set VLAN table for port 1 (%d)\n", ret); 988329159Shselasky } 989329159Shselasky if (!ret && update2) { 990329159Shselasky ret = mlx4_set_port_vlan_table(dev, 2, t2->entries); 991329159Shselasky if (ret) 992329159Shselasky mlx4_warn(dev, "failed to set VLAN table for port 2 (%d)\n", ret); 993329159Shselasky } 994329159Shselasky 995329159Shselasky if (ret) 996329159Shselasky mlx4_warn(dev, "failed to create mirror VLAN tables\n"); 997329159Shselaskyunlock: 998329159Shselasky mutex_unlock(&t2->mutex); 999329159Shselasky mutex_unlock(&t1->mutex); 1000329159Shselasky return ret; 1001329159Shselasky} 1002329159Shselasky 1003329159Shselaskyint mlx4_unbond_vlan_table(struct mlx4_dev *dev) 1004329159Shselasky{ 1005329159Shselasky struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table; 1006329159Shselasky struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table; 1007329159Shselasky int ret = 0; 1008329159Shselasky int ret1; 1009329159Shselasky int i; 1010329159Shselasky bool update1 = false; 1011329159Shselasky bool update2 = false; 1012329159Shselasky 1013329159Shselasky mutex_lock(&t1->mutex); 1014329159Shselasky mutex_lock(&t2->mutex); 1015329159Shselasky for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 1016329159Shselasky if (t1->entries[i] != t2->entries[i]) { 1017329159Shselasky mlx4_warn(dev, "vlan table is in an unexpected state when trying to unbond\n"); 1018329159Shselasky ret = -EINVAL; 1019329159Shselasky goto unlock; 1020329159Shselasky } 1021329159Shselasky } 1022329159Shselasky 1023329159Shselasky for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 1024329159Shselasky if (!t1->entries[i]) 1025329159Shselasky continue; 1026329159Shselasky t1->is_dup[i] = false; 1027329159Shselasky if (!t1->refs[i]) { 1028329159Shselasky t1->entries[i] = 0; 1029329159Shselasky update1 = true; 1030329159Shselasky } 1031329159Shselasky t2->is_dup[i] = false; 1032329159Shselasky if (!t2->refs[i]) { 1033329159Shselasky t2->entries[i] = 0; 1034329159Shselasky update2 = true; 1035329159Shselasky } 1036329159Shselasky } 1037329159Shselasky 1038329159Shselasky if (update1) { 1039329159Shselasky ret = mlx4_set_port_vlan_table(dev, 1, t1->entries); 1040329159Shselasky if (ret) 1041329159Shselasky mlx4_warn(dev, "failed to unmirror VLAN tables for port 1(%d)\n", ret); 1042329159Shselasky } 1043329159Shselasky if (update2) { 1044329159Shselasky ret1 = mlx4_set_port_vlan_table(dev, 2, t2->entries); 1045329159Shselasky if (ret1) { 1046329159Shselasky mlx4_warn(dev, "failed to unmirror VLAN tables for port 2(%d)\n", ret1); 1047329159Shselasky ret = ret1; 1048329159Shselasky } 1049329159Shselasky } 1050329159Shselaskyunlock: 1051329159Shselasky mutex_unlock(&t2->mutex); 1052329159Shselasky mutex_unlock(&t1->mutex); 1053329159Shselasky return ret; 1054329159Shselasky} 1055329159Shselasky 1056219820Sjeffint mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) 1057219820Sjeff{ 1058219820Sjeff struct mlx4_cmd_mailbox *inmailbox, *outmailbox; 1059219820Sjeff u8 *inbuf, *outbuf; 1060219820Sjeff int err; 1061219820Sjeff 1062219820Sjeff inmailbox = mlx4_alloc_cmd_mailbox(dev); 1063219820Sjeff if (IS_ERR(inmailbox)) 1064219820Sjeff return PTR_ERR(inmailbox); 1065219820Sjeff 1066219820Sjeff outmailbox = mlx4_alloc_cmd_mailbox(dev); 1067219820Sjeff if (IS_ERR(outmailbox)) { 1068219820Sjeff mlx4_free_cmd_mailbox(dev, inmailbox); 1069219820Sjeff return PTR_ERR(outmailbox); 1070219820Sjeff } 1071219820Sjeff 1072219820Sjeff inbuf = inmailbox->buf; 1073219820Sjeff outbuf = outmailbox->buf; 1074219820Sjeff inbuf[0] = 1; 1075219820Sjeff inbuf[1] = 1; 1076219820Sjeff inbuf[2] = 1; 1077219820Sjeff inbuf[3] = 1; 1078219820Sjeff *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015); 1079219820Sjeff *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); 1080219820Sjeff 1081219820Sjeff err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, 1082255932Salfred MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 1083255932Salfred MLX4_CMD_NATIVE); 1084219820Sjeff if (!err) 1085219820Sjeff *caps = *(__be32 *) (outbuf + 84); 1086219820Sjeff mlx4_free_cmd_mailbox(dev, inmailbox); 1087219820Sjeff mlx4_free_cmd_mailbox(dev, outmailbox); 1088219820Sjeff return err; 1089219820Sjeff} 1090255932Salfredstatic struct mlx4_roce_gid_entry zgid_entry; 1091219820Sjeff 1092329159Shselaskyint mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port) 1093219820Sjeff{ 1094329159Shselasky int vfs; 1095329159Shselasky int slave_gid = slave; 1096329159Shselasky unsigned i; 1097329159Shselasky struct mlx4_slaves_pport slaves_pport; 1098329159Shselasky struct mlx4_active_ports actv_ports; 1099329159Shselasky unsigned max_port_p_one; 1100329159Shselasky 1101255932Salfred if (slave == 0) 1102255932Salfred return MLX4_ROCE_PF_GIDS; 1103329159Shselasky 1104329159Shselasky /* Slave is a VF */ 1105329159Shselasky slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1106329159Shselasky actv_ports = mlx4_get_active_ports(dev, slave); 1107329159Shselasky max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 1108329159Shselasky bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 1109329159Shselasky 1110329159Shselasky for (i = 1; i < max_port_p_one; i++) { 1111329159Shselasky struct mlx4_active_ports exclusive_ports; 1112329159Shselasky struct mlx4_slaves_pport slaves_pport_actv; 1113329159Shselasky bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 1114329159Shselasky set_bit(i - 1, exclusive_ports.ports); 1115329159Shselasky if (i == port) 1116329159Shselasky continue; 1117329159Shselasky slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 1118329159Shselasky dev, &exclusive_ports); 1119329159Shselasky slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 1120329159Shselasky dev->persist->num_vfs + 1); 1121329159Shselasky } 1122329159Shselasky vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; 1123329159Shselasky if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs)) 1124329159Shselasky return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1; 1125329159Shselasky return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs; 1126255932Salfred} 1127255932Salfred 1128329159Shselaskyint mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port) 1129255932Salfred{ 1130255932Salfred int gids; 1131329159Shselasky unsigned i; 1132329159Shselasky int slave_gid = slave; 1133255932Salfred int vfs; 1134255932Salfred 1135329159Shselasky struct mlx4_slaves_pport slaves_pport; 1136329159Shselasky struct mlx4_active_ports actv_ports; 1137329159Shselasky unsigned max_port_p_one; 1138255932Salfred 1139255932Salfred if (slave == 0) 1140255932Salfred return 0; 1141255932Salfred 1142329159Shselasky slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1143329159Shselasky actv_ports = mlx4_get_active_ports(dev, slave); 1144329159Shselasky max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 1145329159Shselasky bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 1146329159Shselasky 1147329159Shselasky for (i = 1; i < max_port_p_one; i++) { 1148329159Shselasky struct mlx4_active_ports exclusive_ports; 1149329159Shselasky struct mlx4_slaves_pport slaves_pport_actv; 1150329159Shselasky bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 1151329159Shselasky set_bit(i - 1, exclusive_ports.ports); 1152329159Shselasky if (i == port) 1153329159Shselasky continue; 1154329159Shselasky slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 1155329159Shselasky dev, &exclusive_ports); 1156329159Shselasky slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 1157329159Shselasky dev->persist->num_vfs + 1); 1158329159Shselasky } 1159329159Shselasky gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 1160329159Shselasky vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; 1161329159Shselasky if (slave_gid <= gids % vfs) 1162329159Shselasky return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1); 1163329159Shselasky 1164329159Shselasky return MLX4_ROCE_PF_GIDS + (gids % vfs) + 1165329159Shselasky ((gids / vfs) * (slave_gid - 1)); 1166255932Salfred} 1167329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix); 1168255932Salfred 1169329159Shselaskystatic int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave, 1170329159Shselasky int port, struct mlx4_cmd_mailbox *mailbox) 1171329159Shselasky{ 1172329159Shselasky struct mlx4_roce_gid_entry *gid_entry_mbox; 1173329159Shselasky struct mlx4_priv *priv = mlx4_priv(dev); 1174329159Shselasky int num_gids, base, offset; 1175329159Shselasky int i, err; 1176329159Shselasky 1177329159Shselasky num_gids = mlx4_get_slave_num_gids(dev, slave, port); 1178329159Shselasky base = mlx4_get_base_gid_ix(dev, slave, port); 1179329159Shselasky 1180329159Shselasky memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE); 1181329159Shselasky 1182329159Shselasky mutex_lock(&(priv->port[port].gid_table.mutex)); 1183329159Shselasky /* Zero-out gids belonging to that slave in the port GID table */ 1184329159Shselasky for (i = 0, offset = base; i < num_gids; offset++, i++) 1185329159Shselasky memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 1186329159Shselasky zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE); 1187329159Shselasky 1188329159Shselasky /* Now, copy roce port gids table to mailbox for passing to FW */ 1189329159Shselasky gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf; 1190329159Shselasky for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 1191329159Shselasky memcpy(gid_entry_mbox->raw, 1192329159Shselasky priv->port[port].gid_table.roce_gids[i].raw, 1193329159Shselasky MLX4_ROCE_GID_ENTRY_SIZE); 1194329159Shselasky 1195329159Shselasky err = mlx4_cmd(dev, mailbox->dma, 1196329159Shselasky ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8), 1197329159Shselasky MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT, 1198329159Shselasky MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1199329159Shselasky mutex_unlock(&(priv->port[port].gid_table.mutex)); 1200329159Shselasky return err; 1201329159Shselasky} 1202329159Shselasky 1203329159Shselasky 1204329159Shselaskyvoid mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave) 1205329159Shselasky{ 1206329159Shselasky struct mlx4_active_ports actv_ports; 1207329159Shselasky struct mlx4_cmd_mailbox *mailbox; 1208329159Shselasky int num_eth_ports, err; 1209329159Shselasky int i; 1210329159Shselasky 1211329159Shselasky if (slave < 0 || slave > dev->persist->num_vfs) 1212329159Shselasky return; 1213329159Shselasky 1214329159Shselasky actv_ports = mlx4_get_active_ports(dev, slave); 1215329159Shselasky 1216329159Shselasky for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) { 1217329159Shselasky if (test_bit(i, actv_ports.ports)) { 1218329159Shselasky if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 1219329159Shselasky continue; 1220329159Shselasky num_eth_ports++; 1221329159Shselasky } 1222329159Shselasky } 1223329159Shselasky 1224329159Shselasky if (!num_eth_ports) 1225329159Shselasky return; 1226329159Shselasky 1227329159Shselasky /* have ETH ports. Alloc mailbox for SET_PORT command */ 1228329159Shselasky mailbox = mlx4_alloc_cmd_mailbox(dev); 1229329159Shselasky if (IS_ERR(mailbox)) 1230329159Shselasky return; 1231329159Shselasky 1232329159Shselasky for (i = 0; i < dev->caps.num_ports; i++) { 1233329159Shselasky if (test_bit(i, actv_ports.ports)) { 1234329159Shselasky if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 1235329159Shselasky continue; 1236329159Shselasky err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox); 1237329159Shselasky if (err) 1238329159Shselasky mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n", 1239329159Shselasky slave, i + 1, err); 1240329159Shselasky } 1241329159Shselasky } 1242329159Shselasky 1243329159Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 1244329159Shselasky return; 1245329159Shselasky} 1246329159Shselasky 1247255932Salfredstatic int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, 1248255932Salfred u8 op_mod, struct mlx4_cmd_mailbox *inbox) 1249255932Salfred{ 1250255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1251255932Salfred struct mlx4_port_info *port_info; 1252255932Salfred struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; 1253255932Salfred struct mlx4_slave_state *slave_st = &master->slave_state[slave]; 1254255932Salfred struct mlx4_set_port_rqp_calc_context *qpn_context; 1255255932Salfred struct mlx4_set_port_general_context *gen_context; 1256255932Salfred struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1; 1257255932Salfred int reset_qkey_viols; 1258255932Salfred int port; 1259255932Salfred int is_eth; 1260255932Salfred int num_gids; 1261255932Salfred int base; 1262255932Salfred u32 in_modifier; 1263255932Salfred u32 promisc; 1264255932Salfred u16 mtu, prev_mtu; 1265219820Sjeff int err; 1266255932Salfred int i, j; 1267255932Salfred int offset; 1268255932Salfred __be32 agg_cap_mask; 1269255932Salfred __be32 slave_cap_mask; 1270255932Salfred __be32 new_cap_mask; 1271219820Sjeff 1272255932Salfred port = in_mod & 0xff; 1273329159Shselasky in_modifier = in_mod >> 8; 1274255932Salfred is_eth = op_mod; 1275255932Salfred port_info = &priv->port[port]; 1276255932Salfred 1277255932Salfred /* Slaves cannot perform SET_PORT operations except changing MTU */ 1278255932Salfred if (is_eth) { 1279255932Salfred if (slave != dev->caps.function && 1280255932Salfred in_modifier != MLX4_SET_PORT_GENERAL && 1281255932Salfred in_modifier != MLX4_SET_PORT_GID_TABLE) { 1282329159Shselasky mlx4_warn(dev, "denying SET_PORT for slave:%d\n", 1283329159Shselasky slave); 1284255932Salfred return -EINVAL; 1285255932Salfred } 1286255932Salfred switch (in_modifier) { 1287255932Salfred case MLX4_SET_PORT_RQP_CALC: 1288255932Salfred qpn_context = inbox->buf; 1289255932Salfred qpn_context->base_qpn = 1290255932Salfred cpu_to_be32(port_info->base_qpn); 1291255932Salfred qpn_context->n_mac = 0x7; 1292255932Salfred promisc = be32_to_cpu(qpn_context->promisc) >> 1293255932Salfred SET_PORT_PROMISC_SHIFT; 1294255932Salfred qpn_context->promisc = cpu_to_be32( 1295255932Salfred promisc << SET_PORT_PROMISC_SHIFT | 1296255932Salfred port_info->base_qpn); 1297255932Salfred promisc = be32_to_cpu(qpn_context->mcast) >> 1298255932Salfred SET_PORT_MC_PROMISC_SHIFT; 1299255932Salfred qpn_context->mcast = cpu_to_be32( 1300255932Salfred promisc << SET_PORT_MC_PROMISC_SHIFT | 1301255932Salfred port_info->base_qpn); 1302255932Salfred break; 1303255932Salfred case MLX4_SET_PORT_GENERAL: 1304255932Salfred gen_context = inbox->buf; 1305255932Salfred /* Mtu is configured as the max MTU among all the 1306255932Salfred * the functions on the port. */ 1307255932Salfred mtu = be16_to_cpu(gen_context->mtu); 1308272027Shselasky mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] + 1309272027Shselasky ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); 1310255932Salfred prev_mtu = slave_st->mtu[port]; 1311255932Salfred slave_st->mtu[port] = mtu; 1312255932Salfred if (mtu > master->max_mtu[port]) 1313255932Salfred master->max_mtu[port] = mtu; 1314255932Salfred if (mtu < prev_mtu && prev_mtu == 1315255932Salfred master->max_mtu[port]) { 1316255932Salfred slave_st->mtu[port] = mtu; 1317255932Salfred master->max_mtu[port] = mtu; 1318255932Salfred for (i = 0; i < dev->num_slaves; i++) { 1319255932Salfred master->max_mtu[port] = 1320255932Salfred max(master->max_mtu[port], 1321255932Salfred master->slave_state[i].mtu[port]); 1322255932Salfred } 1323255932Salfred } 1324255932Salfred 1325255932Salfred gen_context->mtu = cpu_to_be16(master->max_mtu[port]); 1326329159Shselasky /* Slave cannot change Global Pause configuration */ 1327329159Shselasky if (slave != mlx4_master_func_num(dev) && 1328329159Shselasky ((gen_context->pptx != master->pptx) || 1329329159Shselasky (gen_context->pprx != master->pprx))) { 1330329159Shselasky gen_context->pptx = master->pptx; 1331329159Shselasky gen_context->pprx = master->pprx; 1332329159Shselasky mlx4_warn(dev, 1333329159Shselasky "denying Global Pause change for slave:%d\n", 1334329159Shselasky slave); 1335329159Shselasky } else { 1336329159Shselasky master->pptx = gen_context->pptx; 1337329159Shselasky master->pprx = gen_context->pprx; 1338329159Shselasky } 1339255932Salfred break; 1340255932Salfred case MLX4_SET_PORT_GID_TABLE: 1341255932Salfred /* change to MULTIPLE entries: number of guest's gids 1342255932Salfred * need a FOR-loop here over number of gids the guest has. 1343255932Salfred * 1. Check no duplicates in gids passed by slave 1344255932Salfred */ 1345329159Shselasky num_gids = mlx4_get_slave_num_gids(dev, slave, port); 1346329159Shselasky base = mlx4_get_base_gid_ix(dev, slave, port); 1347329159Shselasky gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1348255932Salfred for (i = 0; i < num_gids; gid_entry_mbox++, i++) { 1349255932Salfred if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 1350255932Salfred sizeof(zgid_entry))) 1351255932Salfred continue; 1352255932Salfred gid_entry_mb1 = gid_entry_mbox + 1; 1353255932Salfred for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) { 1354255932Salfred if (!memcmp(gid_entry_mb1->raw, 1355255932Salfred zgid_entry.raw, sizeof(zgid_entry))) 1356255932Salfred continue; 1357255932Salfred if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw, 1358255932Salfred sizeof(gid_entry_mbox->raw))) { 1359255932Salfred /* found duplicate */ 1360255932Salfred return -EINVAL; 1361255932Salfred } 1362255932Salfred } 1363255932Salfred } 1364255932Salfred 1365255932Salfred /* 2. Check that do not have duplicates in OTHER 1366255932Salfred * entries in the port GID table 1367255932Salfred */ 1368329159Shselasky 1369329159Shselasky mutex_lock(&(priv->port[port].gid_table.mutex)); 1370255932Salfred for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 1371255932Salfred if (i >= base && i < base + num_gids) 1372255932Salfred continue; /* don't compare to slave's current gids */ 1373329159Shselasky gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i]; 1374255932Salfred if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry))) 1375255932Salfred continue; 1376329159Shselasky gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1377255932Salfred for (j = 0; j < num_gids; gid_entry_mbox++, j++) { 1378255932Salfred if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 1379255932Salfred sizeof(zgid_entry))) 1380255932Salfred continue; 1381255932Salfred if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw, 1382255932Salfred sizeof(gid_entry_tbl->raw))) { 1383255932Salfred /* found duplicate */ 1384329159Shselasky mlx4_warn(dev, "requested gid entry for slave:%d is a duplicate of gid at index %d\n", 1385255932Salfred slave, i); 1386329159Shselasky mutex_unlock(&(priv->port[port].gid_table.mutex)); 1387255932Salfred return -EINVAL; 1388255932Salfred } 1389255932Salfred } 1390255932Salfred } 1391255932Salfred 1392255932Salfred /* insert slave GIDs with memcpy, starting at slave's base index */ 1393329159Shselasky gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1394255932Salfred for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++) 1395329159Shselasky memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 1396329159Shselasky gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE); 1397255932Salfred 1398255932Salfred /* Now, copy roce port gids table to current mailbox for passing to FW */ 1399329159Shselasky gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1400255932Salfred for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 1401329159Shselasky memcpy(gid_entry_mbox->raw, 1402329159Shselasky priv->port[port].gid_table.roce_gids[i].raw, 1403329159Shselasky MLX4_ROCE_GID_ENTRY_SIZE); 1404255932Salfred 1405329159Shselasky err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 1406329159Shselasky MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1407329159Shselasky MLX4_CMD_NATIVE); 1408329159Shselasky mutex_unlock(&(priv->port[port].gid_table.mutex)); 1409329159Shselasky return err; 1410255932Salfred } 1411329159Shselasky 1412272027Shselasky return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 1413255932Salfred MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1414255932Salfred MLX4_CMD_NATIVE); 1415255932Salfred } 1416255932Salfred 1417329159Shselasky /* Slaves are not allowed to SET_PORT beacon (LED) blink */ 1418329159Shselasky if (op_mod == MLX4_SET_PORT_BEACON_OPCODE) { 1419329159Shselasky mlx4_warn(dev, "denying SET_PORT Beacon slave:%d\n", slave); 1420329159Shselasky return -EPERM; 1421329159Shselasky } 1422329159Shselasky 1423255932Salfred /* For IB, we only consider: 1424255932Salfred * - The capability mask, which is set to the aggregate of all 1425255932Salfred * slave function capabilities 1426255932Salfred * - The QKey violatin counter - reset according to each request. 1427255932Salfred */ 1428255932Salfred 1429255932Salfred if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 1430255932Salfred reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40; 1431255932Salfred new_cap_mask = ((__be32 *) inbox->buf)[2]; 1432255932Salfred } else { 1433255932Salfred reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1; 1434255932Salfred new_cap_mask = ((__be32 *) inbox->buf)[1]; 1435255932Salfred } 1436255932Salfred 1437255932Salfred /* slave may not set the IS_SM capability for the port */ 1438255932Salfred if (slave != mlx4_master_func_num(dev) && 1439255932Salfred (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM)) 1440255932Salfred return -EINVAL; 1441255932Salfred 1442255932Salfred /* No DEV_MGMT in multifunc mode */ 1443255932Salfred if (mlx4_is_mfunc(dev) && 1444255932Salfred (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP)) 1445255932Salfred return -EINVAL; 1446255932Salfred 1447255932Salfred agg_cap_mask = 0; 1448255932Salfred slave_cap_mask = 1449255932Salfred priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; 1450255932Salfred priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask; 1451255932Salfred for (i = 0; i < dev->num_slaves; i++) 1452255932Salfred agg_cap_mask |= 1453255932Salfred priv->mfunc.master.slave_state[i].ib_cap_mask[port]; 1454255932Salfred 1455255932Salfred /* only clear mailbox for guests. Master may be setting 1456255932Salfred * MTU or PKEY table size 1457255932Salfred */ 1458255932Salfred if (slave != dev->caps.function) 1459255932Salfred memset(inbox->buf, 0, 256); 1460255932Salfred if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 1461255932Salfred *(u8 *) inbox->buf |= !!reset_qkey_viols << 6; 1462255932Salfred ((__be32 *) inbox->buf)[2] = agg_cap_mask; 1463255932Salfred } else { 1464255932Salfred ((u8 *) inbox->buf)[3] |= !!reset_qkey_viols; 1465255932Salfred ((__be32 *) inbox->buf)[1] = agg_cap_mask; 1466255932Salfred } 1467255932Salfred 1468255932Salfred err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT, 1469255932Salfred MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1470255932Salfred if (err) 1471255932Salfred priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = 1472255932Salfred slave_cap_mask; 1473255932Salfred return err; 1474255932Salfred} 1475255932Salfred 1476255932Salfredint mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, 1477255932Salfred struct mlx4_vhcr *vhcr, 1478255932Salfred struct mlx4_cmd_mailbox *inbox, 1479255932Salfred struct mlx4_cmd_mailbox *outbox, 1480255932Salfred struct mlx4_cmd_info *cmd) 1481255932Salfred{ 1482329159Shselasky int port = mlx4_slave_convert_port( 1483329159Shselasky dev, slave, vhcr->in_modifier & 0xFF); 1484329159Shselasky 1485329159Shselasky if (port < 0) 1486329159Shselasky return -EINVAL; 1487329159Shselasky 1488329159Shselasky vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) | 1489329159Shselasky (port & 0xFF); 1490329159Shselasky 1491255932Salfred return mlx4_common_set_port(dev, slave, vhcr->in_modifier, 1492255932Salfred vhcr->op_modifier, inbox); 1493255932Salfred} 1494255932Salfred 1495255932Salfred/* bit locations for set port command with zero op modifier */ 1496255932Salfredenum { 1497255932Salfred MLX4_SET_PORT_VL_CAP = 4, /* bits 7:4 */ 1498255932Salfred MLX4_SET_PORT_MTU_CAP = 12, /* bits 15:12 */ 1499255932Salfred MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20, 1500255932Salfred MLX4_CHANGE_PORT_VL_CAP = 21, 1501255932Salfred MLX4_CHANGE_PORT_MTU_CAP = 22, 1502255932Salfred}; 1503255932Salfred 1504255932Salfredint mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz) 1505255932Salfred{ 1506255932Salfred struct mlx4_cmd_mailbox *mailbox; 1507329159Shselasky int err, vl_cap, pkey_tbl_flag = 0; 1508255932Salfred 1509329159Shselasky if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) 1510219820Sjeff return 0; 1511219820Sjeff 1512219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 1513219820Sjeff if (IS_ERR(mailbox)) 1514219820Sjeff return PTR_ERR(mailbox); 1515219820Sjeff 1516329159Shselasky ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; 1517219820Sjeff 1518329159Shselasky if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) { 1519329159Shselasky pkey_tbl_flag = 1; 1520329159Shselasky ((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz); 1521329159Shselasky } 1522219820Sjeff 1523329159Shselasky /* IB VL CAP enum isn't used by the firmware, just numerical values */ 1524329159Shselasky for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) { 1525329159Shselasky ((__be32 *) mailbox->buf)[0] = cpu_to_be32( 1526329159Shselasky (1 << MLX4_CHANGE_PORT_MTU_CAP) | 1527329159Shselasky (1 << MLX4_CHANGE_PORT_VL_CAP) | 1528329159Shselasky (pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) | 1529329159Shselasky (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) | 1530329159Shselasky (vl_cap << MLX4_SET_PORT_VL_CAP)); 1531329159Shselasky err = mlx4_cmd(dev, mailbox->dma, port, 1532329159Shselasky MLX4_SET_PORT_IB_OPCODE, MLX4_CMD_SET_PORT, 1533329159Shselasky MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 1534329159Shselasky if (err != -ENOMEM) 1535329159Shselasky break; 1536255932Salfred } 1537255932Salfred 1538219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 1539219820Sjeff return err; 1540219820Sjeff} 1541255932Salfred 1542329159Shselasky#define SET_PORT_ROCE_2_FLAGS 0x10 1543329159Shselasky#define MLX4_SET_PORT_ROCE_V1_V2 0x2 1544255932Salfredint mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, 1545255932Salfred u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx) 1546255932Salfred{ 1547255932Salfred struct mlx4_cmd_mailbox *mailbox; 1548255932Salfred struct mlx4_set_port_general_context *context; 1549255932Salfred int err; 1550255932Salfred u32 in_mod; 1551255932Salfred 1552255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 1553255932Salfred if (IS_ERR(mailbox)) 1554255932Salfred return PTR_ERR(mailbox); 1555255932Salfred context = mailbox->buf; 1556255932Salfred context->flags = SET_PORT_GEN_ALL_VALID; 1557255932Salfred context->mtu = cpu_to_be16(mtu); 1558255932Salfred context->pptx = (pptx * (!pfctx)) << 7; 1559255932Salfred context->pfctx = pfctx; 1560255932Salfred context->pprx = (pprx * (!pfcrx)) << 7; 1561255932Salfred context->pfcrx = pfcrx; 1562255932Salfred 1563329159Shselasky if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2) { 1564329159Shselasky context->flags |= SET_PORT_ROCE_2_FLAGS; 1565329159Shselasky context->roce_mode |= 1566329159Shselasky MLX4_SET_PORT_ROCE_V1_V2 << 4; 1567329159Shselasky } 1568255932Salfred in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 1569329159Shselasky err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1570329159Shselasky MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1571329159Shselasky MLX4_CMD_WRAPPED); 1572255932Salfred 1573255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 1574255932Salfred return err; 1575255932Salfred} 1576255932SalfredEXPORT_SYMBOL(mlx4_SET_PORT_general); 1577255932Salfred 1578255932Salfredint mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, 1579255932Salfred u8 promisc) 1580255932Salfred{ 1581255932Salfred struct mlx4_cmd_mailbox *mailbox; 1582255932Salfred struct mlx4_set_port_rqp_calc_context *context; 1583255932Salfred int err; 1584255932Salfred u32 in_mod; 1585255932Salfred u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ? 1586255932Salfred MCAST_DIRECT : MCAST_DEFAULT; 1587272027Shselasky 1588255932Salfred if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) 1589255932Salfred return 0; 1590255932Salfred 1591255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 1592255932Salfred if (IS_ERR(mailbox)) 1593255932Salfred return PTR_ERR(mailbox); 1594255932Salfred context = mailbox->buf; 1595255932Salfred context->base_qpn = cpu_to_be32(base_qpn); 1596272027Shselasky context->n_mac = dev->caps.log_num_macs; 1597255932Salfred context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | 1598255932Salfred base_qpn); 1599255932Salfred context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | 1600255932Salfred base_qpn); 1601255932Salfred context->intra_no_vlan = 0; 1602255932Salfred context->no_vlan = MLX4_NO_VLAN_IDX; 1603255932Salfred context->intra_vlan_miss = 0; 1604255932Salfred context->vlan_miss = MLX4_VLAN_MISS_IDX; 1605255932Salfred 1606255932Salfred in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port; 1607329159Shselasky err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1608329159Shselasky MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1609329159Shselasky MLX4_CMD_WRAPPED); 1610255932Salfred 1611255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 1612255932Salfred return err; 1613255932Salfred} 1614255932SalfredEXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); 1615255932Salfred 1616329159Shselaskyint mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, u8 ignore_fcs_value) 1617255932Salfred{ 1618255932Salfred struct mlx4_cmd_mailbox *mailbox; 1619329159Shselasky struct mlx4_set_port_general_context *context; 1620329159Shselasky u32 in_mod; 1621255932Salfred int err; 1622255932Salfred 1623255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 1624255932Salfred if (IS_ERR(mailbox)) 1625255932Salfred return PTR_ERR(mailbox); 1626255932Salfred context = mailbox->buf; 1627329159Shselasky context->v_ignore_fcs |= MLX4_FLAG_V_IGNORE_FCS_MASK; 1628329159Shselasky if (ignore_fcs_value) 1629329159Shselasky context->ignore_fcs |= MLX4_IGNORE_FCS_MASK; 1630329159Shselasky else 1631329159Shselasky context->ignore_fcs &= ~MLX4_IGNORE_FCS_MASK; 1632255932Salfred 1633329159Shselasky in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 1634255932Salfred err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 1635255932Salfred MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1636255932Salfred 1637255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 1638255932Salfred return err; 1639255932Salfred} 1640329159ShselaskyEXPORT_SYMBOL(mlx4_SET_PORT_fcs_check); 1641255932Salfred 1642329159Shselaskyenum { 1643329159Shselasky VXLAN_ENABLE_MODIFY = 1 << 7, 1644329159Shselasky VXLAN_STEERING_MODIFY = 1 << 6, 1645329159Shselasky 1646329159Shselasky VXLAN_ENABLE = 1 << 7, 1647329159Shselasky}; 1648329159Shselasky 1649329159Shselaskystruct mlx4_set_port_vxlan_context { 1650329159Shselasky u32 reserved1; 1651329159Shselasky u8 modify_flags; 1652329159Shselasky u8 reserved2; 1653329159Shselasky u8 enable_flags; 1654329159Shselasky u8 steering; 1655329159Shselasky}; 1656329159Shselasky 1657329159Shselaskyint mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable) 1658255932Salfred{ 1659255932Salfred int err; 1660255932Salfred u32 in_mod; 1661329159Shselasky struct mlx4_cmd_mailbox *mailbox; 1662329159Shselasky struct mlx4_set_port_vxlan_context *context; 1663255932Salfred 1664255932Salfred mailbox = mlx4_alloc_cmd_mailbox(dev); 1665255932Salfred if (IS_ERR(mailbox)) 1666255932Salfred return PTR_ERR(mailbox); 1667255932Salfred context = mailbox->buf; 1668329159Shselasky memset(context, 0, sizeof(*context)); 1669255932Salfred 1670329159Shselasky context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY; 1671329159Shselasky if (enable) 1672329159Shselasky context->enable_flags = VXLAN_ENABLE; 1673329159Shselasky context->steering = steering; 1674255932Salfred 1675329159Shselasky in_mod = MLX4_SET_PORT_VXLAN << 8 | port; 1676329159Shselasky err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1677329159Shselasky MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1678329159Shselasky MLX4_CMD_NATIVE); 1679255932Salfred 1680329159Shselasky mlx4_free_cmd_mailbox(dev, mailbox); 1681329159Shselasky return err; 1682329159Shselasky} 1683329159ShselaskyEXPORT_SYMBOL(mlx4_SET_PORT_VXLAN); 1684255932Salfred 1685329159Shselaskyint mlx4_SET_PORT_BEACON(struct mlx4_dev *dev, u8 port, u16 time) 1686329159Shselasky{ 1687329159Shselasky int err; 1688329159Shselasky struct mlx4_cmd_mailbox *mailbox; 1689329159Shselasky 1690329159Shselasky mailbox = mlx4_alloc_cmd_mailbox(dev); 1691329159Shselasky if (IS_ERR(mailbox)) 1692329159Shselasky return PTR_ERR(mailbox); 1693329159Shselasky 1694329159Shselasky *((__be32 *)mailbox->buf) = cpu_to_be32(time); 1695329159Shselasky 1696329159Shselasky err = mlx4_cmd(dev, mailbox->dma, port, MLX4_SET_PORT_BEACON_OPCODE, 1697329159Shselasky MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1698329159Shselasky MLX4_CMD_NATIVE); 1699329159Shselasky 1700255932Salfred mlx4_free_cmd_mailbox(dev, mailbox); 1701255932Salfred return err; 1702255932Salfred} 1703329159ShselaskyEXPORT_SYMBOL(mlx4_SET_PORT_BEACON); 1704255932Salfred 1705255932Salfredint mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1706255932Salfred struct mlx4_vhcr *vhcr, 1707255932Salfred struct mlx4_cmd_mailbox *inbox, 1708255932Salfred struct mlx4_cmd_mailbox *outbox, 1709255932Salfred struct mlx4_cmd_info *cmd) 1710255932Salfred{ 1711255932Salfred int err = 0; 1712255932Salfred 1713255932Salfred return err; 1714255932Salfred} 1715255932Salfred 1716255932Salfredint mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, 1717255932Salfred u64 mac, u64 clear, u8 mode) 1718255932Salfred{ 1719255932Salfred return mlx4_cmd(dev, (mac | (clear << 63)), port, mode, 1720255932Salfred MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B, 1721255932Salfred MLX4_CMD_WRAPPED); 1722255932Salfred} 1723255932SalfredEXPORT_SYMBOL(mlx4_SET_MCAST_FLTR); 1724255932Salfred 1725255932Salfredint mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1726255932Salfred struct mlx4_vhcr *vhcr, 1727255932Salfred struct mlx4_cmd_mailbox *inbox, 1728255932Salfred struct mlx4_cmd_mailbox *outbox, 1729255932Salfred struct mlx4_cmd_info *cmd) 1730255932Salfred{ 1731255932Salfred int err = 0; 1732255932Salfred 1733255932Salfred return err; 1734255932Salfred} 1735255932Salfred 1736255932Salfredint mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, 1737255932Salfred struct mlx4_vhcr *vhcr, 1738255932Salfred struct mlx4_cmd_mailbox *inbox, 1739255932Salfred struct mlx4_cmd_mailbox *outbox, 1740255932Salfred struct mlx4_cmd_info *cmd) 1741255932Salfred{ 1742272027Shselasky return 0; 1743255932Salfred} 1744255932Salfred 1745329159Shselaskyint mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, 1746329159Shselasky int *slave_id) 1747255932Salfred{ 1748255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1749255932Salfred int i, found_ix = -1; 1750255932Salfred int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 1751329159Shselasky struct mlx4_slaves_pport slaves_pport; 1752329159Shselasky unsigned num_vfs; 1753329159Shselasky int slave_gid; 1754255932Salfred 1755255932Salfred if (!mlx4_is_mfunc(dev)) 1756255932Salfred return -EINVAL; 1757255932Salfred 1758329159Shselasky slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1759329159Shselasky num_vfs = bitmap_weight(slaves_pport.slaves, 1760329159Shselasky dev->persist->num_vfs + 1) - 1; 1761329159Shselasky 1762255932Salfred for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 1763329159Shselasky if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid, 1764329159Shselasky MLX4_ROCE_GID_ENTRY_SIZE)) { 1765255932Salfred found_ix = i; 1766255932Salfred break; 1767255932Salfred } 1768255932Salfred } 1769255932Salfred 1770255932Salfred if (found_ix >= 0) { 1771329159Shselasky /* Calculate a slave_gid which is the slave number in the gid 1772329159Shselasky * table and not a globally unique slave number. 1773329159Shselasky */ 1774255932Salfred if (found_ix < MLX4_ROCE_PF_GIDS) 1775329159Shselasky slave_gid = 0; 1776329159Shselasky else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) * 1777329159Shselasky (vf_gids / num_vfs + 1)) 1778329159Shselasky slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) / 1779329159Shselasky (vf_gids / num_vfs + 1)) + 1; 1780255932Salfred else 1781329159Shselasky slave_gid = 1782255932Salfred ((found_ix - MLX4_ROCE_PF_GIDS - 1783329159Shselasky ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) / 1784329159Shselasky (vf_gids / num_vfs)) + vf_gids % num_vfs + 1; 1785329159Shselasky 1786329159Shselasky /* Calculate the globally unique slave id */ 1787329159Shselasky if (slave_gid) { 1788329159Shselasky struct mlx4_active_ports exclusive_ports; 1789329159Shselasky struct mlx4_active_ports actv_ports; 1790329159Shselasky struct mlx4_slaves_pport slaves_pport_actv; 1791329159Shselasky unsigned max_port_p_one; 1792329159Shselasky int num_vfs_before = 0; 1793329159Shselasky int candidate_slave_gid; 1794329159Shselasky 1795329159Shselasky /* Calculate how many VFs are on the previous port, if exists */ 1796329159Shselasky for (i = 1; i < port; i++) { 1797329159Shselasky bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 1798329159Shselasky set_bit(i - 1, exclusive_ports.ports); 1799329159Shselasky slaves_pport_actv = 1800329159Shselasky mlx4_phys_to_slaves_pport_actv( 1801329159Shselasky dev, &exclusive_ports); 1802329159Shselasky num_vfs_before += bitmap_weight( 1803329159Shselasky slaves_pport_actv.slaves, 1804329159Shselasky dev->persist->num_vfs + 1); 1805329159Shselasky } 1806329159Shselasky 1807329159Shselasky /* candidate_slave_gid isn't necessarily the correct slave, but 1808329159Shselasky * it has the same number of ports and is assigned to the same 1809329159Shselasky * ports as the real slave we're looking for. On dual port VF, 1810329159Shselasky * slave_gid = [single port VFs on port <port>] + 1811329159Shselasky * [offset of the current slave from the first dual port VF] + 1812329159Shselasky * 1 (for the PF). 1813329159Shselasky */ 1814329159Shselasky candidate_slave_gid = slave_gid + num_vfs_before; 1815329159Shselasky 1816329159Shselasky actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid); 1817329159Shselasky max_port_p_one = find_first_bit( 1818329159Shselasky actv_ports.ports, dev->caps.num_ports) + 1819329159Shselasky bitmap_weight(actv_ports.ports, 1820329159Shselasky dev->caps.num_ports) + 1; 1821329159Shselasky 1822329159Shselasky /* Calculate the real slave number */ 1823329159Shselasky for (i = 1; i < max_port_p_one; i++) { 1824329159Shselasky if (i == port) 1825329159Shselasky continue; 1826329159Shselasky bitmap_zero(exclusive_ports.ports, 1827329159Shselasky dev->caps.num_ports); 1828329159Shselasky set_bit(i - 1, exclusive_ports.ports); 1829329159Shselasky slaves_pport_actv = 1830329159Shselasky mlx4_phys_to_slaves_pport_actv( 1831329159Shselasky dev, &exclusive_ports); 1832329159Shselasky slave_gid += bitmap_weight( 1833329159Shselasky slaves_pport_actv.slaves, 1834329159Shselasky dev->persist->num_vfs + 1); 1835329159Shselasky } 1836329159Shselasky } 1837329159Shselasky *slave_id = slave_gid; 1838255932Salfred } 1839255932Salfred 1840255932Salfred return (found_ix >= 0) ? 0 : -EINVAL; 1841255932Salfred} 1842255932SalfredEXPORT_SYMBOL(mlx4_get_slave_from_roce_gid); 1843255932Salfred 1844329159Shselaskyint mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, 1845329159Shselasky u8 *gid) 1846255932Salfred{ 1847255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1848255932Salfred 1849255932Salfred if (!mlx4_is_master(dev)) 1850255932Salfred return -EINVAL; 1851255932Salfred 1852329159Shselasky memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw, 1853329159Shselasky MLX4_ROCE_GID_ENTRY_SIZE); 1854255932Salfred return 0; 1855255932Salfred} 1856255932SalfredEXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); 1857255932Salfred 1858283612Sglebius/* Cable Module Info */ 1859283612Sglebius#define MODULE_INFO_MAX_READ 48 1860283612Sglebius 1861283612Sglebius#define I2C_ADDR_LOW 0x50 1862283612Sglebius#define I2C_ADDR_HIGH 0x51 1863283612Sglebius#define I2C_PAGE_SIZE 256 1864283612Sglebius 1865283612Sglebius/* Module Info Data */ 1866283612Sglebiusstruct mlx4_cable_info { 1867283612Sglebius u8 i2c_addr; 1868283612Sglebius u8 page_num; 1869283612Sglebius __be16 dev_mem_address; 1870283612Sglebius __be16 reserved1; 1871283612Sglebius __be16 size; 1872283612Sglebius __be32 reserved2[2]; 1873283612Sglebius u8 data[MODULE_INFO_MAX_READ]; 1874283612Sglebius}; 1875283612Sglebius 1876283612Sglebiusenum cable_info_err { 1877329159Shselasky CABLE_INF_INV_PORT = 0x1, 1878329159Shselasky CABLE_INF_OP_NOSUP = 0x2, 1879329159Shselasky CABLE_INF_NOT_CONN = 0x3, 1880329159Shselasky CABLE_INF_NO_EEPRM = 0x4, 1881329159Shselasky CABLE_INF_PAGE_ERR = 0x5, 1882329159Shselasky CABLE_INF_INV_ADDR = 0x6, 1883329159Shselasky CABLE_INF_I2C_ADDR = 0x7, 1884329159Shselasky CABLE_INF_QSFP_VIO = 0x8, 1885329159Shselasky CABLE_INF_I2C_BUSY = 0x9, 1886283612Sglebius}; 1887283612Sglebius 1888283612Sglebius#define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF) 1889283612Sglebius 1890283612Sglebius#ifdef DEBUG 1891283612Sglebiusstatic inline const char *cable_info_mad_err_str(u16 mad_status) 1892283612Sglebius{ 1893283612Sglebius u8 err = MAD_STATUS_2_CABLE_ERR(mad_status); 1894283612Sglebius 1895283612Sglebius switch (err) { 1896283612Sglebius case CABLE_INF_INV_PORT: 1897283612Sglebius return "invalid port selected"; 1898283612Sglebius case CABLE_INF_OP_NOSUP: 1899283612Sglebius return "operation not supported for this port (the port is of type CX4 or internal)"; 1900283612Sglebius case CABLE_INF_NOT_CONN: 1901283612Sglebius return "cable is not connected"; 1902283612Sglebius case CABLE_INF_NO_EEPRM: 1903283612Sglebius return "the connected cable has no EPROM (passive copper cable)"; 1904283612Sglebius case CABLE_INF_PAGE_ERR: 1905283612Sglebius return "page number is greater than 15"; 1906283612Sglebius case CABLE_INF_INV_ADDR: 1907283612Sglebius return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)"; 1908283612Sglebius case CABLE_INF_I2C_ADDR: 1909283612Sglebius return "invalid I2C slave address"; 1910283612Sglebius case CABLE_INF_QSFP_VIO: 1911283612Sglebius return "at least one cable violates the QSFP specification and ignores the modsel signal"; 1912283612Sglebius case CABLE_INF_I2C_BUSY: 1913283612Sglebius return "I2C bus is constantly busy"; 1914283612Sglebius } 1915283612Sglebius return "Unknown Error"; 1916283612Sglebius} 1917283612Sglebius#endif /* DEBUG */ 1918283612Sglebius 1919283612Sglebius/** 1920283612Sglebius * mlx4_get_module_info - Read cable module eeprom data 1921283612Sglebius * @dev: mlx4_dev. 1922283612Sglebius * @port: port number. 1923283612Sglebius * @offset: byte offset in eeprom to start reading data from. 1924283612Sglebius * @size: num of bytes to read. 1925283612Sglebius * @data: output buffer to put the requested data into. 1926283612Sglebius * 1927283612Sglebius * Reads cable module eeprom data, puts the outcome data into 1928283612Sglebius * data pointer paramer. 1929283612Sglebius * Returns num of read bytes on success or a negative error 1930283612Sglebius * code. 1931283612Sglebius */ 1932329159Shselaskyint mlx4_get_module_info(struct mlx4_dev *dev, u8 port, 1933329159Shselasky u16 offset, u16 size, u8 *data) 1934283612Sglebius{ 1935283612Sglebius struct mlx4_cmd_mailbox *inbox, *outbox; 1936283612Sglebius struct mlx4_mad_ifc *inmad, *outmad; 1937283612Sglebius struct mlx4_cable_info *cable_info; 1938283612Sglebius u16 i2c_addr; 1939283612Sglebius int ret; 1940283612Sglebius 1941283612Sglebius if (size > MODULE_INFO_MAX_READ) 1942283612Sglebius size = MODULE_INFO_MAX_READ; 1943283612Sglebius 1944283612Sglebius inbox = mlx4_alloc_cmd_mailbox(dev); 1945329159Shselasky if (IS_ERR(inbox)) 1946283612Sglebius return PTR_ERR(inbox); 1947283612Sglebius 1948283612Sglebius outbox = mlx4_alloc_cmd_mailbox(dev); 1949283612Sglebius if (IS_ERR(outbox)) { 1950283612Sglebius mlx4_free_cmd_mailbox(dev, inbox); 1951283612Sglebius return PTR_ERR(outbox); 1952283612Sglebius } 1953283612Sglebius 1954283612Sglebius inmad = (struct mlx4_mad_ifc *)(inbox->buf); 1955283612Sglebius outmad = (struct mlx4_mad_ifc *)(outbox->buf); 1956283612Sglebius 1957283612Sglebius inmad->method = 0x1; /* Get */ 1958283612Sglebius inmad->class_version = 0x1; 1959283612Sglebius inmad->mgmt_class = 0x1; 1960283612Sglebius inmad->base_version = 0x1; 1961283612Sglebius inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */ 1962283612Sglebius 1963283612Sglebius if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE) 1964283612Sglebius /* Cross pages reads are not allowed 1965283612Sglebius * read until offset 256 in low page 1966283612Sglebius */ 1967283612Sglebius size -= offset + size - I2C_PAGE_SIZE; 1968283612Sglebius 1969283612Sglebius i2c_addr = I2C_ADDR_LOW; 1970283612Sglebius if (offset >= I2C_PAGE_SIZE) { 1971283612Sglebius /* Reset offset to high page */ 1972283612Sglebius i2c_addr = I2C_ADDR_HIGH; 1973283612Sglebius offset -= I2C_PAGE_SIZE; 1974283612Sglebius } 1975283612Sglebius 1976283612Sglebius cable_info = (struct mlx4_cable_info *)inmad->data; 1977283612Sglebius cable_info->dev_mem_address = cpu_to_be16(offset); 1978283612Sglebius cable_info->page_num = 0; 1979283612Sglebius cable_info->i2c_addr = i2c_addr; 1980283612Sglebius cable_info->size = cpu_to_be16(size); 1981283612Sglebius 1982283612Sglebius ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, 1983329159Shselasky MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 1984329159Shselasky MLX4_CMD_NATIVE); 1985283612Sglebius if (ret) 1986283612Sglebius goto out; 1987283612Sglebius 1988283612Sglebius if (be16_to_cpu(outmad->status)) { 1989283612Sglebius /* Mad returned with bad status */ 1990283612Sglebius ret = be16_to_cpu(outmad->status); 1991283612Sglebius#ifdef DEBUG 1992329159Shselasky mlx4_warn(dev, 1993329159Shselasky "MLX4_CMD_MAD_IFC Get Module info attr(%x) port(%d) i2c_addr(%x) offset(%d) size(%d): Response Mad Status(%x) - %s\n", 1994329159Shselasky 0xFF60, port, i2c_addr, offset, size, 1995329159Shselasky ret, cable_info_mad_err_str(ret)); 1996283612Sglebius#endif 1997283612Sglebius if (i2c_addr == I2C_ADDR_HIGH && 1998283612Sglebius MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR) 1999283612Sglebius /* Some SFP cables do not support i2c slave 2000283612Sglebius * address 0x51 (high page), abort silently. 2001283612Sglebius */ 2002283612Sglebius ret = 0; 2003283612Sglebius else 2004283612Sglebius ret = -ret; 2005283612Sglebius goto out; 2006283612Sglebius } 2007283612Sglebius cable_info = (struct mlx4_cable_info *)outmad->data; 2008283612Sglebius memcpy(data, cable_info->data, size); 2009283612Sglebius ret = size; 2010283612Sglebiusout: 2011283612Sglebius mlx4_free_cmd_mailbox(dev, inbox); 2012283612Sglebius mlx4_free_cmd_mailbox(dev, outbox); 2013283612Sglebius return ret; 2014283612Sglebius} 2015283612SglebiusEXPORT_SYMBOL(mlx4_get_module_info); 2016