15a2cc190SJeff Kirsher /* 25a2cc190SJeff Kirsher * Copyright (c) 2007 Mellanox Technologies. All rights reserved. 35a2cc190SJeff Kirsher * 45a2cc190SJeff Kirsher * This software is available to you under a choice of one of two 55a2cc190SJeff Kirsher * licenses. You may choose to be licensed under the terms of the GNU 65a2cc190SJeff Kirsher * General Public License (GPL) Version 2, available from the file 75a2cc190SJeff Kirsher * COPYING in the main directory of this source tree, or the 85a2cc190SJeff Kirsher * OpenIB.org BSD license below: 95a2cc190SJeff Kirsher * 105a2cc190SJeff Kirsher * Redistribution and use in source and binary forms, with or 115a2cc190SJeff Kirsher * without modification, are permitted provided that the following 125a2cc190SJeff Kirsher * conditions are met: 135a2cc190SJeff Kirsher * 145a2cc190SJeff Kirsher * - Redistributions of source code must retain the above 155a2cc190SJeff Kirsher * copyright notice, this list of conditions and the following 165a2cc190SJeff Kirsher * disclaimer. 175a2cc190SJeff Kirsher * 185a2cc190SJeff Kirsher * - Redistributions in binary form must reproduce the above 195a2cc190SJeff Kirsher * copyright notice, this list of conditions and the following 205a2cc190SJeff Kirsher * disclaimer in the documentation and/or other materials 215a2cc190SJeff Kirsher * provided with the distribution. 225a2cc190SJeff Kirsher * 235a2cc190SJeff Kirsher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 245a2cc190SJeff Kirsher * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 255a2cc190SJeff Kirsher * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 265a2cc190SJeff Kirsher * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 275a2cc190SJeff Kirsher * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 285a2cc190SJeff Kirsher * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 295a2cc190SJeff Kirsher * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 305a2cc190SJeff Kirsher * SOFTWARE. 315a2cc190SJeff Kirsher */ 325a2cc190SJeff Kirsher 335a2cc190SJeff Kirsher #include <linux/errno.h> 345a2cc190SJeff Kirsher #include <linux/if_ether.h> 35c59fec20SEugenia Emantayev #include <linux/if_vlan.h> 36ee40fa06SPaul Gortmaker #include <linux/export.h> 375a2cc190SJeff Kirsher 385a2cc190SJeff Kirsher #include <linux/mlx4/cmd.h> 395a2cc190SJeff Kirsher 405a2cc190SJeff Kirsher #include "mlx4.h" 41b4b6e842SEran Ben Elisha #include "mlx4_stats.h" 425a2cc190SJeff Kirsher 435a2cc190SJeff Kirsher #define MLX4_MAC_VALID (1ull << 63) 445a2cc190SJeff Kirsher 455a2cc190SJeff Kirsher #define MLX4_VLAN_VALID (1u << 31) 465a2cc190SJeff Kirsher #define MLX4_VLAN_MASK 0xfff 475a2cc190SJeff Kirsher 4878500b8cSMuhammad Mahajna #define MLX4_STATS_TRAFFIC_COUNTERS_MASK 0xfULL 4978500b8cSMuhammad Mahajna #define MLX4_STATS_TRAFFIC_DROPS_MASK 0xc0ULL 5078500b8cSMuhammad Mahajna #define MLX4_STATS_ERROR_COUNTERS_MASK 0x1ffc30ULL 5178500b8cSMuhammad Mahajna #define MLX4_STATS_PORT_COUNTERS_MASK 0x1fe00000ULL 5278500b8cSMuhammad Mahajna 5378500b8cSMuhammad Mahajna #define MLX4_FLAG_V_IGNORE_FCS_MASK 0x2 5478500b8cSMuhammad Mahajna #define MLX4_IGNORE_FCS_MASK 0x1 55564ed9b1STariq Toukan #define MLX4_TC_MAX_NUMBER 8 5678500b8cSMuhammad Mahajna 575a2cc190SJeff Kirsher void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table) 585a2cc190SJeff Kirsher { 595a2cc190SJeff Kirsher int i; 605a2cc190SJeff Kirsher 615a2cc190SJeff Kirsher mutex_init(&table->mutex); 625a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 635a2cc190SJeff Kirsher table->entries[i] = 0; 645a2cc190SJeff Kirsher table->refs[i] = 0; 655f61385dSMoni Shoua table->is_dup[i] = false; 665a2cc190SJeff Kirsher } 675a2cc190SJeff Kirsher table->max = 1 << dev->caps.log_num_macs; 685a2cc190SJeff Kirsher table->total = 0; 695a2cc190SJeff Kirsher } 705a2cc190SJeff Kirsher 715a2cc190SJeff Kirsher void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table) 725a2cc190SJeff Kirsher { 735a2cc190SJeff Kirsher int i; 745a2cc190SJeff Kirsher 755a2cc190SJeff Kirsher mutex_init(&table->mutex); 765a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 775a2cc190SJeff Kirsher table->entries[i] = 0; 785a2cc190SJeff Kirsher table->refs[i] = 0; 795f61385dSMoni Shoua table->is_dup[i] = false; 805a2cc190SJeff Kirsher } 81e72ebf5aSYevgeny Petrilin table->max = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR; 825a2cc190SJeff Kirsher table->total = 0; 835a2cc190SJeff Kirsher } 845a2cc190SJeff Kirsher 85111c6094SJack Morgenstein void mlx4_init_roce_gid_table(struct mlx4_dev *dev, 86111c6094SJack Morgenstein struct mlx4_roce_gid_table *table) 87111c6094SJack Morgenstein { 88111c6094SJack Morgenstein int i; 89111c6094SJack Morgenstein 90111c6094SJack Morgenstein mutex_init(&table->mutex); 91111c6094SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) 92111c6094SJack Morgenstein memset(table->roce_gids[i].raw, 0, MLX4_ROCE_GID_ENTRY_SIZE); 93111c6094SJack Morgenstein } 94111c6094SJack Morgenstein 955a2cc190SJeff Kirsher static int validate_index(struct mlx4_dev *dev, 965a2cc190SJeff Kirsher struct mlx4_mac_table *table, int index) 975a2cc190SJeff Kirsher { 985a2cc190SJeff Kirsher int err = 0; 995a2cc190SJeff Kirsher 1005a2cc190SJeff Kirsher if (index < 0 || index >= table->max || !table->entries[index]) { 1015a2cc190SJeff Kirsher mlx4_warn(dev, "No valid Mac entry for the given index\n"); 1025a2cc190SJeff Kirsher err = -EINVAL; 1035a2cc190SJeff Kirsher } 1045a2cc190SJeff Kirsher return err; 1055a2cc190SJeff Kirsher } 1065a2cc190SJeff Kirsher 1075a2cc190SJeff Kirsher static int find_index(struct mlx4_dev *dev, 1085a2cc190SJeff Kirsher struct mlx4_mac_table *table, u64 mac) 1095a2cc190SJeff Kirsher { 1105a2cc190SJeff Kirsher int i; 111ffe455adSEugenia Emantayev 1125a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 113f4fd40b2SJack Morgenstein if (table->refs[i] && 114f4fd40b2SJack Morgenstein (MLX4_MAC_MASK & mac) == 115ffe455adSEugenia Emantayev (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) 1165a2cc190SJeff Kirsher return i; 1175a2cc190SJeff Kirsher } 1185a2cc190SJeff Kirsher /* Mac not found */ 1195a2cc190SJeff Kirsher return -EINVAL; 1205a2cc190SJeff Kirsher } 1215a2cc190SJeff Kirsher 122ffe455adSEugenia Emantayev static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, 123ffe455adSEugenia Emantayev __be64 *entries) 124ffe455adSEugenia Emantayev { 125ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 126ffe455adSEugenia Emantayev u32 in_mod; 127ffe455adSEugenia Emantayev int err; 128ffe455adSEugenia Emantayev 129ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 130ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 131ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 132ffe455adSEugenia Emantayev 133ffe455adSEugenia Emantayev memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); 134ffe455adSEugenia Emantayev 135ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; 136ffe455adSEugenia Emantayev 137a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 138a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 139a130b590SIdo Shamay MLX4_CMD_NATIVE); 140ffe455adSEugenia Emantayev 141ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 142ffe455adSEugenia Emantayev return err; 143ffe455adSEugenia Emantayev } 144ffe455adSEugenia Emantayev 145297e0dadSMoni Shoua int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx) 146297e0dadSMoni Shoua { 147297e0dadSMoni Shoua struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 148297e0dadSMoni Shoua struct mlx4_mac_table *table = &info->mac_table; 149297e0dadSMoni Shoua int i; 150297e0dadSMoni Shoua 151297e0dadSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 152297e0dadSMoni Shoua if (!table->refs[i]) 153297e0dadSMoni Shoua continue; 154297e0dadSMoni Shoua 155297e0dadSMoni Shoua if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 156297e0dadSMoni Shoua *idx = i; 157297e0dadSMoni Shoua return 0; 158297e0dadSMoni Shoua } 159297e0dadSMoni Shoua } 160297e0dadSMoni Shoua 161297e0dadSMoni Shoua return -ENOENT; 162297e0dadSMoni Shoua } 163297e0dadSMoni Shoua EXPORT_SYMBOL_GPL(mlx4_find_cached_mac); 164297e0dadSMoni Shoua 1655f61385dSMoni Shoua static bool mlx4_need_mf_bond(struct mlx4_dev *dev) 1665f61385dSMoni Shoua { 1675f61385dSMoni Shoua int i, num_eth_ports = 0; 1685f61385dSMoni Shoua 1695f61385dSMoni Shoua if (!mlx4_is_mfunc(dev)) 1705f61385dSMoni Shoua return false; 1715f61385dSMoni Shoua mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) 1725f61385dSMoni Shoua ++num_eth_ports; 1735f61385dSMoni Shoua 1745f61385dSMoni Shoua return (num_eth_ports == 2) ? true : false; 1755f61385dSMoni Shoua } 1765f61385dSMoni Shoua 177ffe455adSEugenia Emantayev int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 178ffe455adSEugenia Emantayev { 179ffe455adSEugenia Emantayev struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 180ffe455adSEugenia Emantayev struct mlx4_mac_table *table = &info->mac_table; 181ffe455adSEugenia Emantayev int i, err = 0; 182ffe455adSEugenia Emantayev int free = -1; 1835f61385dSMoni Shoua int free_for_dup = -1; 1845f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 1855f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 1865f61385dSMoni Shoua struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table; 1875f61385dSMoni Shoua bool need_mf_bond = mlx4_need_mf_bond(dev); 1885f61385dSMoni Shoua bool can_mf_bond = true; 189ffe455adSEugenia Emantayev 1905f61385dSMoni Shoua mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d %s duplicate\n", 1915f61385dSMoni Shoua (unsigned long long)mac, port, 1925f61385dSMoni Shoua dup ? "with" : "without"); 193ffe455adSEugenia Emantayev 1945f61385dSMoni Shoua if (need_mf_bond) { 1955f61385dSMoni Shoua if (port == 1) { 196ffe455adSEugenia Emantayev mutex_lock(&table->mutex); 19703a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 1985f61385dSMoni Shoua } else { 1995f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 20003a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 2015f61385dSMoni Shoua } 2025f61385dSMoni Shoua } else { 2035f61385dSMoni Shoua mutex_lock(&table->mutex); 2045f61385dSMoni Shoua } 2055f61385dSMoni Shoua 2065f61385dSMoni Shoua if (need_mf_bond) { 2075f61385dSMoni Shoua int index_at_port = -1; 2085f61385dSMoni Shoua int index_at_dup_port = -1; 2095f61385dSMoni Shoua 2105f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 2115f61385dSMoni Shoua if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))) 2125f61385dSMoni Shoua index_at_port = i; 2135f61385dSMoni Shoua if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i])))) 2145f61385dSMoni Shoua index_at_dup_port = i; 2155f61385dSMoni Shoua } 2165f61385dSMoni Shoua 2175f61385dSMoni Shoua /* check that same mac is not in the tables at different indices */ 2185f61385dSMoni Shoua if ((index_at_port != index_at_dup_port) && 2195f61385dSMoni Shoua (index_at_port >= 0) && 2205f61385dSMoni Shoua (index_at_dup_port >= 0)) 2215f61385dSMoni Shoua can_mf_bond = false; 2225f61385dSMoni Shoua 2235f61385dSMoni Shoua /* If the mac is already in the primary table, the slot must be 2245f61385dSMoni Shoua * available in the duplicate table as well. 2255f61385dSMoni Shoua */ 2265f61385dSMoni Shoua if (index_at_port >= 0 && index_at_dup_port < 0 && 2275f61385dSMoni Shoua dup_table->refs[index_at_port]) { 2285f61385dSMoni Shoua can_mf_bond = false; 2295f61385dSMoni Shoua } 2305f61385dSMoni Shoua /* If the mac is already in the duplicate table, check that the 2315f61385dSMoni Shoua * corresponding index is not occupied in the primary table, or 2325f61385dSMoni Shoua * the primary table already contains the mac at the same index. 2335f61385dSMoni Shoua * Otherwise, you cannot bond (primary contains a different mac 2345f61385dSMoni Shoua * at that index). 2355f61385dSMoni Shoua */ 2365f61385dSMoni Shoua if (index_at_dup_port >= 0) { 2375f61385dSMoni Shoua if (!table->refs[index_at_dup_port] || 2385f61385dSMoni Shoua ((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[index_at_dup_port])))) 2395f61385dSMoni Shoua free_for_dup = index_at_dup_port; 2405f61385dSMoni Shoua else 2415f61385dSMoni Shoua can_mf_bond = false; 2425f61385dSMoni Shoua } 2435f61385dSMoni Shoua } 2445f61385dSMoni Shoua 245ffe455adSEugenia Emantayev for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 246f4fd40b2SJack Morgenstein if (!table->refs[i]) { 247f4fd40b2SJack Morgenstein if (free < 0) 248ffe455adSEugenia Emantayev free = i; 2495f61385dSMoni Shoua if (free_for_dup < 0 && need_mf_bond && can_mf_bond) { 2505f61385dSMoni Shoua if (!dup_table->refs[i]) 2515f61385dSMoni Shoua free_for_dup = i; 2525f61385dSMoni Shoua } 253ffe455adSEugenia Emantayev continue; 254ffe455adSEugenia Emantayev } 255ffe455adSEugenia Emantayev 256f4fd40b2SJack Morgenstein if ((MLX4_MAC_MASK & mac) == 257f4fd40b2SJack Morgenstein (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 2586ce71acdSRony Efraim /* MAC already registered, increment ref count */ 2596ce71acdSRony Efraim err = i; 2606ce71acdSRony Efraim ++table->refs[i]; 2615f61385dSMoni Shoua if (dup) { 2625f61385dSMoni Shoua u64 dup_mac = MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]); 2635f61385dSMoni Shoua 2645f61385dSMoni Shoua if (dup_mac != mac || !dup_table->is_dup[i]) { 2655f61385dSMoni Shoua mlx4_warn(dev, "register mac: expect duplicate mac 0x%llx on port %d index %d\n", 2665f61385dSMoni Shoua mac, dup_port, i); 2675f61385dSMoni Shoua } 2685f61385dSMoni Shoua } 269ffe455adSEugenia Emantayev goto out; 270ffe455adSEugenia Emantayev } 271ffe455adSEugenia Emantayev } 272ffe455adSEugenia Emantayev 2735f61385dSMoni Shoua if (need_mf_bond && (free_for_dup < 0)) { 2745f61385dSMoni Shoua if (dup) { 2755f61385dSMoni Shoua mlx4_warn(dev, "Fail to allocate duplicate MAC table entry\n"); 2765f61385dSMoni Shoua mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n"); 2775f61385dSMoni Shoua dup = false; 2785f61385dSMoni Shoua } 2795f61385dSMoni Shoua can_mf_bond = false; 2805f61385dSMoni Shoua } 2815f61385dSMoni Shoua 2825f61385dSMoni Shoua if (need_mf_bond && can_mf_bond) 2835f61385dSMoni Shoua free = free_for_dup; 2845f61385dSMoni Shoua 285ffe455adSEugenia Emantayev mlx4_dbg(dev, "Free MAC index is %d\n", free); 286ffe455adSEugenia Emantayev 287ffe455adSEugenia Emantayev if (table->total == table->max) { 288ffe455adSEugenia Emantayev /* No free mac entries */ 289ffe455adSEugenia Emantayev err = -ENOSPC; 290ffe455adSEugenia Emantayev goto out; 291ffe455adSEugenia Emantayev } 292ffe455adSEugenia Emantayev 293ffe455adSEugenia Emantayev /* Register new MAC */ 294ffe455adSEugenia Emantayev table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); 295ffe455adSEugenia Emantayev 296ffe455adSEugenia Emantayev err = mlx4_set_port_mac_table(dev, port, table->entries); 297ffe455adSEugenia Emantayev if (unlikely(err)) { 298ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 299ffe455adSEugenia Emantayev (unsigned long long) mac); 300ffe455adSEugenia Emantayev table->entries[free] = 0; 301ffe455adSEugenia Emantayev goto out; 302ffe455adSEugenia Emantayev } 3036ce71acdSRony Efraim table->refs[free] = 1; 3045f61385dSMoni Shoua table->is_dup[free] = false; 305ffe455adSEugenia Emantayev ++table->total; 3065f61385dSMoni Shoua if (dup) { 3075f61385dSMoni Shoua dup_table->refs[free] = 0; 3085f61385dSMoni Shoua dup_table->is_dup[free] = true; 3095f61385dSMoni Shoua dup_table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); 3105f61385dSMoni Shoua 3115f61385dSMoni Shoua err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries); 3125f61385dSMoni Shoua if (unlikely(err)) { 3135f61385dSMoni Shoua mlx4_warn(dev, "Failed adding duplicate mac: 0x%llx\n", mac); 3145f61385dSMoni Shoua dup_table->is_dup[free] = false; 3155f61385dSMoni Shoua dup_table->entries[free] = 0; 3165f61385dSMoni Shoua goto out; 3175f61385dSMoni Shoua } 3185f61385dSMoni Shoua ++dup_table->total; 3195f61385dSMoni Shoua } 3205f61385dSMoni Shoua err = free; 321ffe455adSEugenia Emantayev out: 3225f61385dSMoni Shoua if (need_mf_bond) { 3235f61385dSMoni Shoua if (port == 2) { 324ffe455adSEugenia Emantayev mutex_unlock(&table->mutex); 3255f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 3265f61385dSMoni Shoua } else { 3275f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 3285f61385dSMoni Shoua mutex_unlock(&table->mutex); 3295f61385dSMoni Shoua } 3305f61385dSMoni Shoua } else { 3315f61385dSMoni Shoua mutex_unlock(&table->mutex); 3325f61385dSMoni Shoua } 333ffe455adSEugenia Emantayev return err; 334ffe455adSEugenia Emantayev } 335ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_register_mac); 336ffe455adSEugenia Emantayev 337ffe455adSEugenia Emantayev int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 338ffe455adSEugenia Emantayev { 339e7dbeba8SJack Morgenstein u64 out_param = 0; 340acddd5ddSJack Morgenstein int err = -EINVAL; 341ffe455adSEugenia Emantayev 342ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 343acddd5ddSJack Morgenstein if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 344acddd5ddSJack Morgenstein err = mlx4_cmd_imm(dev, mac, &out_param, 345acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_MAC, 346acddd5ddSJack Morgenstein RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 347acddd5ddSJack Morgenstein MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 348acddd5ddSJack Morgenstein } 349acddd5ddSJack Morgenstein if (err && err == -EINVAL && mlx4_is_slave(dev)) { 350acddd5ddSJack Morgenstein /* retry using old REG_MAC format */ 351ffe455adSEugenia Emantayev set_param_l(&out_param, port); 352ffe455adSEugenia Emantayev err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 353ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 354ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 355acddd5ddSJack Morgenstein if (!err) 356acddd5ddSJack Morgenstein dev->flags |= MLX4_FLAG_OLD_REG_MAC; 357acddd5ddSJack Morgenstein } 358ffe455adSEugenia Emantayev if (err) 359ffe455adSEugenia Emantayev return err; 360ffe455adSEugenia Emantayev 361ffe455adSEugenia Emantayev return get_param_l(&out_param); 362ffe455adSEugenia Emantayev } 363ffe455adSEugenia Emantayev return __mlx4_register_mac(dev, port, mac); 364ffe455adSEugenia Emantayev } 365ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(mlx4_register_mac); 366ffe455adSEugenia Emantayev 36716a10ffdSYan Burman int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port) 36816a10ffdSYan Burman { 36916a10ffdSYan Burman return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] + 37016a10ffdSYan Burman (port - 1) * (1 << dev->caps.log_num_macs); 37116a10ffdSYan Burman } 37216a10ffdSYan Burman EXPORT_SYMBOL_GPL(mlx4_get_base_qpn); 373ffe455adSEugenia Emantayev 374ffe455adSEugenia Emantayev void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 375ffe455adSEugenia Emantayev { 376143b3efbSEugenia Emantayev struct mlx4_port_info *info; 377143b3efbSEugenia Emantayev struct mlx4_mac_table *table; 378ffe455adSEugenia Emantayev int index; 3795f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 3805f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 3815f61385dSMoni Shoua struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table; 382ffe455adSEugenia Emantayev 383143b3efbSEugenia Emantayev if (port < 1 || port > dev->caps.num_ports) { 384143b3efbSEugenia Emantayev mlx4_warn(dev, "invalid port number (%d), aborting...\n", port); 385143b3efbSEugenia Emantayev return; 386143b3efbSEugenia Emantayev } 387143b3efbSEugenia Emantayev info = &mlx4_priv(dev)->port[port]; 388143b3efbSEugenia Emantayev table = &info->mac_table; 3895f61385dSMoni Shoua 3905f61385dSMoni Shoua if (dup) { 3915f61385dSMoni Shoua if (port == 1) { 3925a2cc190SJeff Kirsher mutex_lock(&table->mutex); 39303a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 3945f61385dSMoni Shoua } else { 3955f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 39603a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 3975f61385dSMoni Shoua } 3985f61385dSMoni Shoua } else { 3995f61385dSMoni Shoua mutex_lock(&table->mutex); 4005f61385dSMoni Shoua } 4015f61385dSMoni Shoua 4026ce71acdSRony Efraim index = find_index(dev, table, mac); 4035a2cc190SJeff Kirsher 4045a2cc190SJeff Kirsher if (validate_index(dev, table, index)) 4055a2cc190SJeff Kirsher goto out; 4065f61385dSMoni Shoua 4075f61385dSMoni Shoua if (--table->refs[index] || table->is_dup[index]) { 4081a91de28SJoe Perches mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n", 4091a91de28SJoe Perches index); 4105f61385dSMoni Shoua if (!table->refs[index]) 4115f61385dSMoni Shoua dup_table->is_dup[index] = false; 4126ce71acdSRony Efraim goto out; 4136ce71acdSRony Efraim } 4145a2cc190SJeff Kirsher 4155a2cc190SJeff Kirsher table->entries[index] = 0; 4165f61385dSMoni Shoua if (mlx4_set_port_mac_table(dev, port, table->entries)) 4175f61385dSMoni Shoua mlx4_warn(dev, "Fail to set mac in port %d during unregister\n", port); 4185a2cc190SJeff Kirsher --table->total; 4195f61385dSMoni Shoua 4205f61385dSMoni Shoua if (dup) { 4215f61385dSMoni Shoua dup_table->is_dup[index] = false; 4225f61385dSMoni Shoua if (dup_table->refs[index]) 4235f61385dSMoni Shoua goto out; 4245f61385dSMoni Shoua dup_table->entries[index] = 0; 4255f61385dSMoni Shoua if (mlx4_set_port_mac_table(dev, dup_port, dup_table->entries)) 4265f61385dSMoni Shoua mlx4_warn(dev, "Fail to set mac in duplicate port %d during unregister\n", dup_port); 4275f61385dSMoni Shoua 4285f61385dSMoni Shoua --table->total; 4295f61385dSMoni Shoua } 4305a2cc190SJeff Kirsher out: 4315f61385dSMoni Shoua if (dup) { 4325f61385dSMoni Shoua if (port == 2) { 4335a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 4345f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 4355f61385dSMoni Shoua } else { 4365f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 4375f61385dSMoni Shoua mutex_unlock(&table->mutex); 4385f61385dSMoni Shoua } 4395f61385dSMoni Shoua } else { 4405f61385dSMoni Shoua mutex_unlock(&table->mutex); 4415f61385dSMoni Shoua } 4425a2cc190SJeff Kirsher } 443ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_unregister_mac); 444ffe455adSEugenia Emantayev 445ffe455adSEugenia Emantayev void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 446ffe455adSEugenia Emantayev { 447e7dbeba8SJack Morgenstein u64 out_param = 0; 448ffe455adSEugenia Emantayev 449ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 450acddd5ddSJack Morgenstein if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 451acddd5ddSJack Morgenstein (void) mlx4_cmd_imm(dev, mac, &out_param, 452acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_MAC, 453acddd5ddSJack Morgenstein RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 454acddd5ddSJack Morgenstein MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 455acddd5ddSJack Morgenstein } else { 456acddd5ddSJack Morgenstein /* use old unregister mac format */ 457ffe455adSEugenia Emantayev set_param_l(&out_param, port); 458162344edSOr Gerlitz (void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 459ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 460ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 461acddd5ddSJack Morgenstein } 462ffe455adSEugenia Emantayev return; 463ffe455adSEugenia Emantayev } 464ffe455adSEugenia Emantayev __mlx4_unregister_mac(dev, port, mac); 465ffe455adSEugenia Emantayev return; 466ffe455adSEugenia Emantayev } 4675a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_mac); 4685a2cc190SJeff Kirsher 46916a10ffdSYan Burman int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac) 4705a2cc190SJeff Kirsher { 4715a2cc190SJeff Kirsher struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 4725a2cc190SJeff Kirsher struct mlx4_mac_table *table = &info->mac_table; 473ffe455adSEugenia Emantayev int index = qpn - info->base_qpn; 474ffe455adSEugenia Emantayev int err = 0; 4755f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 4765f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 4775f61385dSMoni Shoua struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table; 4785a2cc190SJeff Kirsher 479ffe455adSEugenia Emantayev /* CX1 doesn't support multi-functions */ 4805f61385dSMoni Shoua if (dup) { 4815f61385dSMoni Shoua if (port == 1) { 4825a2cc190SJeff Kirsher mutex_lock(&table->mutex); 48303a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 4845f61385dSMoni Shoua } else { 4855f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 48603a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 4875f61385dSMoni Shoua } 4885f61385dSMoni Shoua } else { 4895f61385dSMoni Shoua mutex_lock(&table->mutex); 4905f61385dSMoni Shoua } 4915a2cc190SJeff Kirsher 4925a2cc190SJeff Kirsher err = validate_index(dev, table, index); 4935a2cc190SJeff Kirsher if (err) 4945a2cc190SJeff Kirsher goto out; 4955a2cc190SJeff Kirsher 4965a2cc190SJeff Kirsher table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); 4975a2cc190SJeff Kirsher 4985a2cc190SJeff Kirsher err = mlx4_set_port_mac_table(dev, port, table->entries); 4995a2cc190SJeff Kirsher if (unlikely(err)) { 500ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 501ffe455adSEugenia Emantayev (unsigned long long) new_mac); 5025a2cc190SJeff Kirsher table->entries[index] = 0; 5035f61385dSMoni Shoua } else { 5045f61385dSMoni Shoua if (dup) { 5055f61385dSMoni Shoua dup_table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); 5065f61385dSMoni Shoua 5075f61385dSMoni Shoua err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries); 5085f61385dSMoni Shoua if (unlikely(err)) { 5095f61385dSMoni Shoua mlx4_err(dev, "Failed adding duplicate MAC: 0x%llx\n", 5105f61385dSMoni Shoua (unsigned long long)new_mac); 5115f61385dSMoni Shoua dup_table->entries[index] = 0; 5125f61385dSMoni Shoua } 5135f61385dSMoni Shoua } 5145a2cc190SJeff Kirsher } 5155a2cc190SJeff Kirsher out: 5165f61385dSMoni Shoua if (dup) { 5175f61385dSMoni Shoua if (port == 2) { 5185a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 5195f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 5205f61385dSMoni Shoua } else { 5215f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 5225f61385dSMoni Shoua mutex_unlock(&table->mutex); 5235f61385dSMoni Shoua } 5245f61385dSMoni Shoua } else { 5255f61385dSMoni Shoua mutex_unlock(&table->mutex); 5265f61385dSMoni Shoua } 5275a2cc190SJeff Kirsher return err; 5285a2cc190SJeff Kirsher } 52916a10ffdSYan Burman EXPORT_SYMBOL_GPL(__mlx4_replace_mac); 530ffe455adSEugenia Emantayev 5315a2cc190SJeff Kirsher static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, 5325a2cc190SJeff Kirsher __be32 *entries) 5335a2cc190SJeff Kirsher { 5345a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 5355a2cc190SJeff Kirsher u32 in_mod; 5365a2cc190SJeff Kirsher int err; 5375a2cc190SJeff Kirsher 5385a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 5395a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 5405a2cc190SJeff Kirsher return PTR_ERR(mailbox); 5415a2cc190SJeff Kirsher 5425a2cc190SJeff Kirsher memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); 5435a2cc190SJeff Kirsher in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; 544a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 545a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 546a130b590SIdo Shamay MLX4_CMD_NATIVE); 5475a2cc190SJeff Kirsher 5485a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 5495a2cc190SJeff Kirsher 5505a2cc190SJeff Kirsher return err; 5515a2cc190SJeff Kirsher } 5525a2cc190SJeff Kirsher 5535a2cc190SJeff Kirsher int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx) 5545a2cc190SJeff Kirsher { 5555a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 5565a2cc190SJeff Kirsher int i; 5575a2cc190SJeff Kirsher 5585a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) { 5595a2cc190SJeff Kirsher if (table->refs[i] && 5605a2cc190SJeff Kirsher (vid == (MLX4_VLAN_MASK & 5615a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 5625a2cc190SJeff Kirsher /* VLAN already registered, increase reference count */ 5635a2cc190SJeff Kirsher *idx = i; 5645a2cc190SJeff Kirsher return 0; 5655a2cc190SJeff Kirsher } 5665a2cc190SJeff Kirsher } 5675a2cc190SJeff Kirsher 5685a2cc190SJeff Kirsher return -ENOENT; 5695a2cc190SJeff Kirsher } 5705a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan); 5715a2cc190SJeff Kirsher 5723f7fb021SRony Efraim int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, 573ffe455adSEugenia Emantayev int *index) 5745a2cc190SJeff Kirsher { 5755a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 5765a2cc190SJeff Kirsher int i, err = 0; 5775a2cc190SJeff Kirsher int free = -1; 5785f61385dSMoni Shoua int free_for_dup = -1; 5795f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 5805f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 5815f61385dSMoni Shoua struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table; 5825f61385dSMoni Shoua bool need_mf_bond = mlx4_need_mf_bond(dev); 5835f61385dSMoni Shoua bool can_mf_bond = true; 5845a2cc190SJeff Kirsher 5855f61385dSMoni Shoua mlx4_dbg(dev, "Registering VLAN: %d for port %d %s duplicate\n", 5865f61385dSMoni Shoua vlan, port, 5875f61385dSMoni Shoua dup ? "with" : "without"); 5885f61385dSMoni Shoua 5895f61385dSMoni Shoua if (need_mf_bond) { 5905f61385dSMoni Shoua if (port == 1) { 5915a2cc190SJeff Kirsher mutex_lock(&table->mutex); 59203a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 5935f61385dSMoni Shoua } else { 5945f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 59503a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 5965f61385dSMoni Shoua } 5975f61385dSMoni Shoua } else { 5985f61385dSMoni Shoua mutex_lock(&table->mutex); 5995f61385dSMoni Shoua } 600e72ebf5aSYevgeny Petrilin 601e72ebf5aSYevgeny Petrilin if (table->total == table->max) { 602e72ebf5aSYevgeny Petrilin /* No free vlan entries */ 603e72ebf5aSYevgeny Petrilin err = -ENOSPC; 604e72ebf5aSYevgeny Petrilin goto out; 605e72ebf5aSYevgeny Petrilin } 606e72ebf5aSYevgeny Petrilin 6075f61385dSMoni Shoua if (need_mf_bond) { 6085f61385dSMoni Shoua int index_at_port = -1; 6095f61385dSMoni Shoua int index_at_dup_port = -1; 6105f61385dSMoni Shoua 6115a2cc190SJeff Kirsher for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 6125f61385dSMoni Shoua if ((vlan == (MLX4_VLAN_MASK & be32_to_cpu(table->entries[i])))) 6135f61385dSMoni Shoua index_at_port = i; 6145f61385dSMoni Shoua if ((vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i])))) 6155f61385dSMoni Shoua index_at_dup_port = i; 6165f61385dSMoni Shoua } 6175f61385dSMoni Shoua /* check that same vlan is not in the tables at different indices */ 6185f61385dSMoni Shoua if ((index_at_port != index_at_dup_port) && 6195f61385dSMoni Shoua (index_at_port >= 0) && 6205f61385dSMoni Shoua (index_at_dup_port >= 0)) 6215f61385dSMoni Shoua can_mf_bond = false; 6225f61385dSMoni Shoua 6235f61385dSMoni Shoua /* If the vlan is already in the primary table, the slot must be 6245f61385dSMoni Shoua * available in the duplicate table as well. 6255f61385dSMoni Shoua */ 6265f61385dSMoni Shoua if (index_at_port >= 0 && index_at_dup_port < 0 && 6275f61385dSMoni Shoua dup_table->refs[index_at_port]) { 6285f61385dSMoni Shoua can_mf_bond = false; 6295f61385dSMoni Shoua } 6305f61385dSMoni Shoua /* If the vlan is already in the duplicate table, check that the 6315f61385dSMoni Shoua * corresponding index is not occupied in the primary table, or 6325f61385dSMoni Shoua * the primary table already contains the vlan at the same index. 6335f61385dSMoni Shoua * Otherwise, you cannot bond (primary contains a different vlan 6345f61385dSMoni Shoua * at that index). 6355f61385dSMoni Shoua */ 6365f61385dSMoni Shoua if (index_at_dup_port >= 0) { 6375f61385dSMoni Shoua if (!table->refs[index_at_dup_port] || 6385f61385dSMoni Shoua (vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[index_at_dup_port])))) 6395f61385dSMoni Shoua free_for_dup = index_at_dup_port; 6405f61385dSMoni Shoua else 6415f61385dSMoni Shoua can_mf_bond = false; 6425f61385dSMoni Shoua } 6435a2cc190SJeff Kirsher } 6445a2cc190SJeff Kirsher 6455f61385dSMoni Shoua for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 6465f61385dSMoni Shoua if (!table->refs[i]) { 6475f61385dSMoni Shoua if (free < 0) 6485f61385dSMoni Shoua free = i; 6495f61385dSMoni Shoua if (free_for_dup < 0 && need_mf_bond && can_mf_bond) { 6505f61385dSMoni Shoua if (!dup_table->refs[i]) 6515f61385dSMoni Shoua free_for_dup = i; 6525f61385dSMoni Shoua } 6535f61385dSMoni Shoua } 6545f61385dSMoni Shoua 6555f61385dSMoni Shoua if ((table->refs[i] || table->is_dup[i]) && 6565a2cc190SJeff Kirsher (vlan == (MLX4_VLAN_MASK & 6575a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 6585a2cc190SJeff Kirsher /* Vlan already registered, increase references count */ 6595f61385dSMoni Shoua mlx4_dbg(dev, "vlan %u is already registered.\n", vlan); 6605a2cc190SJeff Kirsher *index = i; 6615a2cc190SJeff Kirsher ++table->refs[i]; 6625f61385dSMoni Shoua if (dup) { 6635f61385dSMoni Shoua u16 dup_vlan = MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i]); 6645f61385dSMoni Shoua 6655f61385dSMoni Shoua if (dup_vlan != vlan || !dup_table->is_dup[i]) { 6665f61385dSMoni Shoua mlx4_warn(dev, "register vlan: expected duplicate vlan %u on port %d index %d\n", 6675f61385dSMoni Shoua vlan, dup_port, i); 6685f61385dSMoni Shoua } 6695f61385dSMoni Shoua } 6705a2cc190SJeff Kirsher goto out; 6715a2cc190SJeff Kirsher } 6725a2cc190SJeff Kirsher } 6735a2cc190SJeff Kirsher 6745f61385dSMoni Shoua if (need_mf_bond && (free_for_dup < 0)) { 6755f61385dSMoni Shoua if (dup) { 6765f61385dSMoni Shoua mlx4_warn(dev, "Fail to allocate duplicate VLAN table entry\n"); 6775f61385dSMoni Shoua mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n"); 6785f61385dSMoni Shoua dup = false; 6795f61385dSMoni Shoua } 6805f61385dSMoni Shoua can_mf_bond = false; 6815f61385dSMoni Shoua } 6825f61385dSMoni Shoua 6835f61385dSMoni Shoua if (need_mf_bond && can_mf_bond) 6845f61385dSMoni Shoua free = free_for_dup; 6855f61385dSMoni Shoua 6865a2cc190SJeff Kirsher if (free < 0) { 6875a2cc190SJeff Kirsher err = -ENOMEM; 6885a2cc190SJeff Kirsher goto out; 6895a2cc190SJeff Kirsher } 6905a2cc190SJeff Kirsher 691ffe455adSEugenia Emantayev /* Register new VLAN */ 6925a2cc190SJeff Kirsher table->refs[free] = 1; 6935f61385dSMoni Shoua table->is_dup[free] = false; 6945a2cc190SJeff Kirsher table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 6955a2cc190SJeff Kirsher 6965a2cc190SJeff Kirsher err = mlx4_set_port_vlan_table(dev, port, table->entries); 6975a2cc190SJeff Kirsher if (unlikely(err)) { 6985a2cc190SJeff Kirsher mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); 6995a2cc190SJeff Kirsher table->refs[free] = 0; 7005a2cc190SJeff Kirsher table->entries[free] = 0; 7015a2cc190SJeff Kirsher goto out; 7025a2cc190SJeff Kirsher } 7035f61385dSMoni Shoua ++table->total; 7045f61385dSMoni Shoua if (dup) { 7055f61385dSMoni Shoua dup_table->refs[free] = 0; 7065f61385dSMoni Shoua dup_table->is_dup[free] = true; 7075f61385dSMoni Shoua dup_table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 7085f61385dSMoni Shoua 7095f61385dSMoni Shoua err = mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries); 7105f61385dSMoni Shoua if (unlikely(err)) { 7115f61385dSMoni Shoua mlx4_warn(dev, "Failed adding duplicate vlan: %u\n", vlan); 7125f61385dSMoni Shoua dup_table->is_dup[free] = false; 7135f61385dSMoni Shoua dup_table->entries[free] = 0; 7145f61385dSMoni Shoua goto out; 7155f61385dSMoni Shoua } 7165f61385dSMoni Shoua ++dup_table->total; 7175f61385dSMoni Shoua } 7185a2cc190SJeff Kirsher 7195a2cc190SJeff Kirsher *index = free; 7205a2cc190SJeff Kirsher out: 7215f61385dSMoni Shoua if (need_mf_bond) { 7225f61385dSMoni Shoua if (port == 2) { 7235a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 7245f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 7255f61385dSMoni Shoua } else { 7265f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 7275f61385dSMoni Shoua mutex_unlock(&table->mutex); 7285f61385dSMoni Shoua } 7295f61385dSMoni Shoua } else { 7305f61385dSMoni Shoua mutex_unlock(&table->mutex); 7315f61385dSMoni Shoua } 7325a2cc190SJeff Kirsher return err; 7335a2cc190SJeff Kirsher } 734ffe455adSEugenia Emantayev 735ffe455adSEugenia Emantayev int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) 736ffe455adSEugenia Emantayev { 737e7dbeba8SJack Morgenstein u64 out_param = 0; 738ffe455adSEugenia Emantayev int err; 739ffe455adSEugenia Emantayev 740162226a1SJack Morgenstein if (vlan > 4095) 741162226a1SJack Morgenstein return -EINVAL; 742162226a1SJack Morgenstein 743ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 744acddd5ddSJack Morgenstein err = mlx4_cmd_imm(dev, vlan, &out_param, 745acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN, 746ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 747ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 748ffe455adSEugenia Emantayev if (!err) 749ffe455adSEugenia Emantayev *index = get_param_l(&out_param); 750ffe455adSEugenia Emantayev 751ffe455adSEugenia Emantayev return err; 752ffe455adSEugenia Emantayev } 753ffe455adSEugenia Emantayev return __mlx4_register_vlan(dev, port, vlan, index); 754ffe455adSEugenia Emantayev } 7555a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_register_vlan); 7565a2cc190SJeff Kirsher 7572009d005SJack Morgenstein void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 7585a2cc190SJeff Kirsher { 7595a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 7602009d005SJack Morgenstein int index; 7615f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 7625f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 7635f61385dSMoni Shoua struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table; 7642009d005SJack Morgenstein 7655f61385dSMoni Shoua if (dup) { 7665f61385dSMoni Shoua if (port == 1) { 7672009d005SJack Morgenstein mutex_lock(&table->mutex); 76803a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 7695f61385dSMoni Shoua } else { 7705f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 77103a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 7725f61385dSMoni Shoua } 7735f61385dSMoni Shoua } else { 7745f61385dSMoni Shoua mutex_lock(&table->mutex); 7755f61385dSMoni Shoua } 7765f61385dSMoni Shoua 7772009d005SJack Morgenstein if (mlx4_find_cached_vlan(dev, port, vlan, &index)) { 7782009d005SJack Morgenstein mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan); 7792009d005SJack Morgenstein goto out; 7802009d005SJack Morgenstein } 7815a2cc190SJeff Kirsher 7825a2cc190SJeff Kirsher if (index < MLX4_VLAN_REGULAR) { 7835a2cc190SJeff Kirsher mlx4_warn(dev, "Trying to free special vlan index %d\n", index); 7845a2cc190SJeff Kirsher goto out; 7855a2cc190SJeff Kirsher } 7862009d005SJack Morgenstein 7875f61385dSMoni Shoua if (--table->refs[index] || table->is_dup[index]) { 7881a91de28SJoe Perches mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n", 7891a91de28SJoe Perches table->refs[index], index); 7905f61385dSMoni Shoua if (!table->refs[index]) 7915f61385dSMoni Shoua dup_table->is_dup[index] = false; 7925a2cc190SJeff Kirsher goto out; 7935a2cc190SJeff Kirsher } 7945a2cc190SJeff Kirsher table->entries[index] = 0; 7955f61385dSMoni Shoua if (mlx4_set_port_vlan_table(dev, port, table->entries)) 7965f61385dSMoni Shoua mlx4_warn(dev, "Fail to set vlan in port %d during unregister\n", port); 7975a2cc190SJeff Kirsher --table->total; 7985f61385dSMoni Shoua if (dup) { 7995f61385dSMoni Shoua dup_table->is_dup[index] = false; 8005f61385dSMoni Shoua if (dup_table->refs[index]) 8015f61385dSMoni Shoua goto out; 8025f61385dSMoni Shoua dup_table->entries[index] = 0; 8035f61385dSMoni Shoua if (mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries)) 8045f61385dSMoni Shoua mlx4_warn(dev, "Fail to set vlan in duplicate port %d during unregister\n", dup_port); 8055f61385dSMoni Shoua --dup_table->total; 8065f61385dSMoni Shoua } 8075a2cc190SJeff Kirsher out: 8085f61385dSMoni Shoua if (dup) { 8095f61385dSMoni Shoua if (port == 2) { 8105a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 8115f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 8125f61385dSMoni Shoua } else { 8135f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 8145f61385dSMoni Shoua mutex_unlock(&table->mutex); 8155f61385dSMoni Shoua } 8165f61385dSMoni Shoua } else { 8175f61385dSMoni Shoua mutex_unlock(&table->mutex); 8185f61385dSMoni Shoua } 8195a2cc190SJeff Kirsher } 820ffe455adSEugenia Emantayev 8212009d005SJack Morgenstein void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 822ffe455adSEugenia Emantayev { 823162226a1SJack Morgenstein u64 out_param = 0; 824ffe455adSEugenia Emantayev 825ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 8262009d005SJack Morgenstein (void) mlx4_cmd_imm(dev, vlan, &out_param, 827acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN, 828162226a1SJack Morgenstein RES_OP_RESERVE_AND_MAP, 829ffe455adSEugenia Emantayev MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, 830ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 831ffe455adSEugenia Emantayev return; 832ffe455adSEugenia Emantayev } 8332009d005SJack Morgenstein __mlx4_unregister_vlan(dev, port, vlan); 834ffe455adSEugenia Emantayev } 8355a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_vlan); 8365a2cc190SJeff Kirsher 8375f61385dSMoni Shoua int mlx4_bond_mac_table(struct mlx4_dev *dev) 8385f61385dSMoni Shoua { 8395f61385dSMoni Shoua struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table; 8405f61385dSMoni Shoua struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table; 8415f61385dSMoni Shoua int ret = 0; 8425f61385dSMoni Shoua int i; 8435f61385dSMoni Shoua bool update1 = false; 8445f61385dSMoni Shoua bool update2 = false; 8455f61385dSMoni Shoua 8465f61385dSMoni Shoua mutex_lock(&t1->mutex); 8475f61385dSMoni Shoua mutex_lock(&t2->mutex); 8485f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 8495f61385dSMoni Shoua if ((t1->entries[i] != t2->entries[i]) && 8505f61385dSMoni Shoua t1->entries[i] && t2->entries[i]) { 8515f61385dSMoni Shoua mlx4_warn(dev, "can't duplicate entry %d in mac table\n", i); 8525f61385dSMoni Shoua ret = -EINVAL; 8535f61385dSMoni Shoua goto unlock; 8545f61385dSMoni Shoua } 8555f61385dSMoni Shoua } 8565f61385dSMoni Shoua 8575f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 8585f61385dSMoni Shoua if (t1->entries[i] && !t2->entries[i]) { 8595f61385dSMoni Shoua t2->entries[i] = t1->entries[i]; 8605f61385dSMoni Shoua t2->is_dup[i] = true; 8615f61385dSMoni Shoua update2 = true; 8625f61385dSMoni Shoua } else if (!t1->entries[i] && t2->entries[i]) { 8635f61385dSMoni Shoua t1->entries[i] = t2->entries[i]; 8645f61385dSMoni Shoua t1->is_dup[i] = true; 8655f61385dSMoni Shoua update1 = true; 8665f61385dSMoni Shoua } else if (t1->entries[i] && t2->entries[i]) { 8675f61385dSMoni Shoua t1->is_dup[i] = true; 8685f61385dSMoni Shoua t2->is_dup[i] = true; 8695f61385dSMoni Shoua } 8705f61385dSMoni Shoua } 8715f61385dSMoni Shoua 8725f61385dSMoni Shoua if (update1) { 8735f61385dSMoni Shoua ret = mlx4_set_port_mac_table(dev, 1, t1->entries); 8745f61385dSMoni Shoua if (ret) 8755f61385dSMoni Shoua mlx4_warn(dev, "failed to set MAC table for port 1 (%d)\n", ret); 8765f61385dSMoni Shoua } 8775f61385dSMoni Shoua if (!ret && update2) { 8785f61385dSMoni Shoua ret = mlx4_set_port_mac_table(dev, 2, t2->entries); 8795f61385dSMoni Shoua if (ret) 8805f61385dSMoni Shoua mlx4_warn(dev, "failed to set MAC table for port 2 (%d)\n", ret); 8815f61385dSMoni Shoua } 8825f61385dSMoni Shoua 8835f61385dSMoni Shoua if (ret) 8845f61385dSMoni Shoua mlx4_warn(dev, "failed to create mirror MAC tables\n"); 8855f61385dSMoni Shoua unlock: 8865f61385dSMoni Shoua mutex_unlock(&t2->mutex); 8875f61385dSMoni Shoua mutex_unlock(&t1->mutex); 8885f61385dSMoni Shoua return ret; 8895f61385dSMoni Shoua } 8905f61385dSMoni Shoua 8915f61385dSMoni Shoua int mlx4_unbond_mac_table(struct mlx4_dev *dev) 8925f61385dSMoni Shoua { 8935f61385dSMoni Shoua struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table; 8945f61385dSMoni Shoua struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table; 8955f61385dSMoni Shoua int ret = 0; 8965f61385dSMoni Shoua int ret1; 8975f61385dSMoni Shoua int i; 8985f61385dSMoni Shoua bool update1 = false; 8995f61385dSMoni Shoua bool update2 = false; 9005f61385dSMoni Shoua 9015f61385dSMoni Shoua mutex_lock(&t1->mutex); 9025f61385dSMoni Shoua mutex_lock(&t2->mutex); 9035f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 9045f61385dSMoni Shoua if (t1->entries[i] != t2->entries[i]) { 9055f61385dSMoni Shoua mlx4_warn(dev, "mac table is in an unexpected state when trying to unbond\n"); 9065f61385dSMoni Shoua ret = -EINVAL; 9075f61385dSMoni Shoua goto unlock; 9085f61385dSMoni Shoua } 9095f61385dSMoni Shoua } 9105f61385dSMoni Shoua 9115f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 9125f61385dSMoni Shoua if (!t1->entries[i]) 9135f61385dSMoni Shoua continue; 9145f61385dSMoni Shoua t1->is_dup[i] = false; 9155f61385dSMoni Shoua if (!t1->refs[i]) { 9165f61385dSMoni Shoua t1->entries[i] = 0; 9175f61385dSMoni Shoua update1 = true; 9185f61385dSMoni Shoua } 9195f61385dSMoni Shoua t2->is_dup[i] = false; 9205f61385dSMoni Shoua if (!t2->refs[i]) { 9215f61385dSMoni Shoua t2->entries[i] = 0; 9225f61385dSMoni Shoua update2 = true; 9235f61385dSMoni Shoua } 9245f61385dSMoni Shoua } 9255f61385dSMoni Shoua 9265f61385dSMoni Shoua if (update1) { 9275f61385dSMoni Shoua ret = mlx4_set_port_mac_table(dev, 1, t1->entries); 9285f61385dSMoni Shoua if (ret) 9295f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror MAC tables for port 1(%d)\n", ret); 9305f61385dSMoni Shoua } 9315f61385dSMoni Shoua if (update2) { 9325f61385dSMoni Shoua ret1 = mlx4_set_port_mac_table(dev, 2, t2->entries); 9335f61385dSMoni Shoua if (ret1) { 9345f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror MAC tables for port 2(%d)\n", ret1); 9355f61385dSMoni Shoua ret = ret1; 9365f61385dSMoni Shoua } 9375f61385dSMoni Shoua } 9385f61385dSMoni Shoua unlock: 9395f61385dSMoni Shoua mutex_unlock(&t2->mutex); 9405f61385dSMoni Shoua mutex_unlock(&t1->mutex); 9415f61385dSMoni Shoua return ret; 9425f61385dSMoni Shoua } 9435f61385dSMoni Shoua 9445f61385dSMoni Shoua int mlx4_bond_vlan_table(struct mlx4_dev *dev) 9455f61385dSMoni Shoua { 9465f61385dSMoni Shoua struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table; 9475f61385dSMoni Shoua struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table; 9485f61385dSMoni Shoua int ret = 0; 9495f61385dSMoni Shoua int i; 9505f61385dSMoni Shoua bool update1 = false; 9515f61385dSMoni Shoua bool update2 = false; 9525f61385dSMoni Shoua 9535f61385dSMoni Shoua mutex_lock(&t1->mutex); 9545f61385dSMoni Shoua mutex_lock(&t2->mutex); 9555f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 9565f61385dSMoni Shoua if ((t1->entries[i] != t2->entries[i]) && 9575f61385dSMoni Shoua t1->entries[i] && t2->entries[i]) { 9585f61385dSMoni Shoua mlx4_warn(dev, "can't duplicate entry %d in vlan table\n", i); 9595f61385dSMoni Shoua ret = -EINVAL; 9605f61385dSMoni Shoua goto unlock; 9615f61385dSMoni Shoua } 9625f61385dSMoni Shoua } 9635f61385dSMoni Shoua 9645f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 9655f61385dSMoni Shoua if (t1->entries[i] && !t2->entries[i]) { 9665f61385dSMoni Shoua t2->entries[i] = t1->entries[i]; 9675f61385dSMoni Shoua t2->is_dup[i] = true; 9685f61385dSMoni Shoua update2 = true; 9695f61385dSMoni Shoua } else if (!t1->entries[i] && t2->entries[i]) { 9705f61385dSMoni Shoua t1->entries[i] = t2->entries[i]; 9715f61385dSMoni Shoua t1->is_dup[i] = true; 9725f61385dSMoni Shoua update1 = true; 9735f61385dSMoni Shoua } else if (t1->entries[i] && t2->entries[i]) { 9745f61385dSMoni Shoua t1->is_dup[i] = true; 9755f61385dSMoni Shoua t2->is_dup[i] = true; 9765f61385dSMoni Shoua } 9775f61385dSMoni Shoua } 9785f61385dSMoni Shoua 9795f61385dSMoni Shoua if (update1) { 9805f61385dSMoni Shoua ret = mlx4_set_port_vlan_table(dev, 1, t1->entries); 9815f61385dSMoni Shoua if (ret) 9825f61385dSMoni Shoua mlx4_warn(dev, "failed to set VLAN table for port 1 (%d)\n", ret); 9835f61385dSMoni Shoua } 9845f61385dSMoni Shoua if (!ret && update2) { 9855f61385dSMoni Shoua ret = mlx4_set_port_vlan_table(dev, 2, t2->entries); 9865f61385dSMoni Shoua if (ret) 9875f61385dSMoni Shoua mlx4_warn(dev, "failed to set VLAN table for port 2 (%d)\n", ret); 9885f61385dSMoni Shoua } 9895f61385dSMoni Shoua 9905f61385dSMoni Shoua if (ret) 9915f61385dSMoni Shoua mlx4_warn(dev, "failed to create mirror VLAN tables\n"); 9925f61385dSMoni Shoua unlock: 9935f61385dSMoni Shoua mutex_unlock(&t2->mutex); 9945f61385dSMoni Shoua mutex_unlock(&t1->mutex); 9955f61385dSMoni Shoua return ret; 9965f61385dSMoni Shoua } 9975f61385dSMoni Shoua 9985f61385dSMoni Shoua int mlx4_unbond_vlan_table(struct mlx4_dev *dev) 9995f61385dSMoni Shoua { 10005f61385dSMoni Shoua struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table; 10015f61385dSMoni Shoua struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table; 10025f61385dSMoni Shoua int ret = 0; 10035f61385dSMoni Shoua int ret1; 10045f61385dSMoni Shoua int i; 10055f61385dSMoni Shoua bool update1 = false; 10065f61385dSMoni Shoua bool update2 = false; 10075f61385dSMoni Shoua 10085f61385dSMoni Shoua mutex_lock(&t1->mutex); 10095f61385dSMoni Shoua mutex_lock(&t2->mutex); 10105f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 10115f61385dSMoni Shoua if (t1->entries[i] != t2->entries[i]) { 10125f61385dSMoni Shoua mlx4_warn(dev, "vlan table is in an unexpected state when trying to unbond\n"); 10135f61385dSMoni Shoua ret = -EINVAL; 10145f61385dSMoni Shoua goto unlock; 10155f61385dSMoni Shoua } 10165f61385dSMoni Shoua } 10175f61385dSMoni Shoua 10185f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 10195f61385dSMoni Shoua if (!t1->entries[i]) 10205f61385dSMoni Shoua continue; 10215f61385dSMoni Shoua t1->is_dup[i] = false; 10225f61385dSMoni Shoua if (!t1->refs[i]) { 10235f61385dSMoni Shoua t1->entries[i] = 0; 10245f61385dSMoni Shoua update1 = true; 10255f61385dSMoni Shoua } 10265f61385dSMoni Shoua t2->is_dup[i] = false; 10275f61385dSMoni Shoua if (!t2->refs[i]) { 10285f61385dSMoni Shoua t2->entries[i] = 0; 10295f61385dSMoni Shoua update2 = true; 10305f61385dSMoni Shoua } 10315f61385dSMoni Shoua } 10325f61385dSMoni Shoua 10335f61385dSMoni Shoua if (update1) { 10345f61385dSMoni Shoua ret = mlx4_set_port_vlan_table(dev, 1, t1->entries); 10355f61385dSMoni Shoua if (ret) 10365f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror VLAN tables for port 1(%d)\n", ret); 10375f61385dSMoni Shoua } 10385f61385dSMoni Shoua if (update2) { 10395f61385dSMoni Shoua ret1 = mlx4_set_port_vlan_table(dev, 2, t2->entries); 10405f61385dSMoni Shoua if (ret1) { 10415f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror VLAN tables for port 2(%d)\n", ret1); 10425f61385dSMoni Shoua ret = ret1; 10435f61385dSMoni Shoua } 10445f61385dSMoni Shoua } 10455f61385dSMoni Shoua unlock: 10465f61385dSMoni Shoua mutex_unlock(&t2->mutex); 10475f61385dSMoni Shoua mutex_unlock(&t1->mutex); 10485f61385dSMoni Shoua return ret; 10495f61385dSMoni Shoua } 10505f61385dSMoni Shoua 10515a2cc190SJeff Kirsher int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) 10525a2cc190SJeff Kirsher { 10535a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *inmailbox, *outmailbox; 10545a2cc190SJeff Kirsher u8 *inbuf, *outbuf; 10555a2cc190SJeff Kirsher int err; 10565a2cc190SJeff Kirsher 10575a2cc190SJeff Kirsher inmailbox = mlx4_alloc_cmd_mailbox(dev); 10585a2cc190SJeff Kirsher if (IS_ERR(inmailbox)) 10595a2cc190SJeff Kirsher return PTR_ERR(inmailbox); 10605a2cc190SJeff Kirsher 10615a2cc190SJeff Kirsher outmailbox = mlx4_alloc_cmd_mailbox(dev); 10625a2cc190SJeff Kirsher if (IS_ERR(outmailbox)) { 10635a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 10645a2cc190SJeff Kirsher return PTR_ERR(outmailbox); 10655a2cc190SJeff Kirsher } 10665a2cc190SJeff Kirsher 10675a2cc190SJeff Kirsher inbuf = inmailbox->buf; 10685a2cc190SJeff Kirsher outbuf = outmailbox->buf; 10695a2cc190SJeff Kirsher inbuf[0] = 1; 10705a2cc190SJeff Kirsher inbuf[1] = 1; 10715a2cc190SJeff Kirsher inbuf[2] = 1; 10725a2cc190SJeff Kirsher inbuf[3] = 1; 10735a2cc190SJeff Kirsher *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015); 10745a2cc190SJeff Kirsher *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); 10755a2cc190SJeff Kirsher 10765a2cc190SJeff Kirsher err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, 1077f9baff50SJack Morgenstein MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 1078f9baff50SJack Morgenstein MLX4_CMD_NATIVE); 10795a2cc190SJeff Kirsher if (!err) 10805a2cc190SJeff Kirsher *caps = *(__be32 *) (outbuf + 84); 10815a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 10825a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, outmailbox); 10835a2cc190SJeff Kirsher return err; 10845a2cc190SJeff Kirsher } 10859cd59352SJack Morgenstein static struct mlx4_roce_gid_entry zgid_entry; 10865a2cc190SJeff Kirsher 1087449fc488SMatan Barak int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port) 1088b6ffaeffSJack Morgenstein { 1089449fc488SMatan Barak int vfs; 1090449fc488SMatan Barak int slave_gid = slave; 1091449fc488SMatan Barak unsigned i; 1092449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 1093449fc488SMatan Barak struct mlx4_active_ports actv_ports; 1094449fc488SMatan Barak unsigned max_port_p_one; 1095449fc488SMatan Barak 1096b6ffaeffSJack Morgenstein if (slave == 0) 1097b6ffaeffSJack Morgenstein return MLX4_ROCE_PF_GIDS; 1098449fc488SMatan Barak 1099449fc488SMatan Barak /* Slave is a VF */ 1100449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1101449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave); 1102449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 1103449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 1104449fc488SMatan Barak 1105449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 1106449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 1107449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 1108449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 1109449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1110449fc488SMatan Barak if (i == port) 1111449fc488SMatan Barak continue; 1112449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 1113449fc488SMatan Barak dev, &exclusive_ports); 1114449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 1115872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1116449fc488SMatan Barak } 1117872bf2fbSYishai Hadas vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; 1118449fc488SMatan Barak if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs)) 1119449fc488SMatan Barak return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1; 1120449fc488SMatan Barak return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs; 1121b6ffaeffSJack Morgenstein } 1122b6ffaeffSJack Morgenstein 1123449fc488SMatan Barak int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port) 1124b6ffaeffSJack Morgenstein { 1125b6ffaeffSJack Morgenstein int gids; 1126449fc488SMatan Barak unsigned i; 1127449fc488SMatan Barak int slave_gid = slave; 1128b6ffaeffSJack Morgenstein int vfs; 1129b6ffaeffSJack Morgenstein 1130449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 1131449fc488SMatan Barak struct mlx4_active_ports actv_ports; 1132449fc488SMatan Barak unsigned max_port_p_one; 1133b6ffaeffSJack Morgenstein 1134b6ffaeffSJack Morgenstein if (slave == 0) 1135b6ffaeffSJack Morgenstein return 0; 1136b6ffaeffSJack Morgenstein 1137449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1138449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave); 1139449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 1140449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 1141449fc488SMatan Barak 1142449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 1143449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 1144449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 1145449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 1146449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1147449fc488SMatan Barak if (i == port) 1148449fc488SMatan Barak continue; 1149449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 1150449fc488SMatan Barak dev, &exclusive_ports); 1151449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 1152872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1153b6ffaeffSJack Morgenstein } 1154449fc488SMatan Barak gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 1155872bf2fbSYishai Hadas vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; 1156449fc488SMatan Barak if (slave_gid <= gids % vfs) 1157449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1); 1158449fc488SMatan Barak 1159449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + (gids % vfs) + 1160449fc488SMatan Barak ((gids / vfs) * (slave_gid - 1)); 1161449fc488SMatan Barak } 1162449fc488SMatan Barak EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix); 1163b6ffaeffSJack Morgenstein 1164111c6094SJack Morgenstein static int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave, 1165111c6094SJack Morgenstein int port, struct mlx4_cmd_mailbox *mailbox) 1166111c6094SJack Morgenstein { 1167111c6094SJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_mbox; 1168111c6094SJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 1169111c6094SJack Morgenstein int num_gids, base, offset; 1170111c6094SJack Morgenstein int i, err; 1171111c6094SJack Morgenstein 1172111c6094SJack Morgenstein num_gids = mlx4_get_slave_num_gids(dev, slave, port); 1173111c6094SJack Morgenstein base = mlx4_get_base_gid_ix(dev, slave, port); 1174111c6094SJack Morgenstein 1175111c6094SJack Morgenstein memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE); 1176111c6094SJack Morgenstein 1177111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex)); 1178111c6094SJack Morgenstein /* Zero-out gids belonging to that slave in the port GID table */ 1179111c6094SJack Morgenstein for (i = 0, offset = base; i < num_gids; offset++, i++) 1180111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 1181111c6094SJack Morgenstein zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE); 1182111c6094SJack Morgenstein 1183111c6094SJack Morgenstein /* Now, copy roce port gids table to mailbox for passing to FW */ 1184111c6094SJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf; 1185111c6094SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 1186111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw, 1187111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw, 1188111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 1189111c6094SJack Morgenstein 1190111c6094SJack Morgenstein err = mlx4_cmd(dev, mailbox->dma, 1191a130b590SIdo Shamay ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8), 1192a130b590SIdo Shamay MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT, 1193a130b590SIdo Shamay MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1194111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 1195111c6094SJack Morgenstein return err; 1196111c6094SJack Morgenstein } 1197111c6094SJack Morgenstein 1198111c6094SJack Morgenstein 1199111c6094SJack Morgenstein void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave) 1200111c6094SJack Morgenstein { 1201111c6094SJack Morgenstein struct mlx4_active_ports actv_ports; 1202111c6094SJack Morgenstein struct mlx4_cmd_mailbox *mailbox; 1203111c6094SJack Morgenstein int num_eth_ports, err; 1204111c6094SJack Morgenstein int i; 1205111c6094SJack Morgenstein 1206872bf2fbSYishai Hadas if (slave < 0 || slave > dev->persist->num_vfs) 1207111c6094SJack Morgenstein return; 1208111c6094SJack Morgenstein 1209111c6094SJack Morgenstein actv_ports = mlx4_get_active_ports(dev, slave); 1210111c6094SJack Morgenstein 1211111c6094SJack Morgenstein for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) { 1212111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) { 1213111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 1214111c6094SJack Morgenstein continue; 1215111c6094SJack Morgenstein num_eth_ports++; 1216111c6094SJack Morgenstein } 1217111c6094SJack Morgenstein } 1218111c6094SJack Morgenstein 1219111c6094SJack Morgenstein if (!num_eth_ports) 1220111c6094SJack Morgenstein return; 1221111c6094SJack Morgenstein 1222111c6094SJack Morgenstein /* have ETH ports. Alloc mailbox for SET_PORT command */ 1223111c6094SJack Morgenstein mailbox = mlx4_alloc_cmd_mailbox(dev); 1224111c6094SJack Morgenstein if (IS_ERR(mailbox)) 1225111c6094SJack Morgenstein return; 1226111c6094SJack Morgenstein 1227111c6094SJack Morgenstein for (i = 0; i < dev->caps.num_ports; i++) { 1228111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) { 1229111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 1230111c6094SJack Morgenstein continue; 1231111c6094SJack Morgenstein err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox); 1232111c6094SJack Morgenstein if (err) 1233111c6094SJack Morgenstein mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n", 1234111c6094SJack Morgenstein slave, i + 1, err); 1235111c6094SJack Morgenstein } 1236111c6094SJack Morgenstein } 1237111c6094SJack Morgenstein 1238111c6094SJack Morgenstein mlx4_free_cmd_mailbox(dev, mailbox); 1239111c6094SJack Morgenstein return; 1240111c6094SJack Morgenstein } 1241111c6094SJack Morgenstein 1242ffe455adSEugenia Emantayev static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, 1243ffe455adSEugenia Emantayev u8 op_mod, struct mlx4_cmd_mailbox *inbox) 1244ffe455adSEugenia Emantayev { 1245ffe455adSEugenia Emantayev struct mlx4_priv *priv = mlx4_priv(dev); 1246ffe455adSEugenia Emantayev struct mlx4_port_info *port_info; 1247ffe455adSEugenia Emantayev struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; 1248ffe455adSEugenia Emantayev struct mlx4_slave_state *slave_st = &master->slave_state[slave]; 1249ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *qpn_context; 1250ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *gen_context; 1251b6ffaeffSJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1; 1252ffe455adSEugenia Emantayev int reset_qkey_viols; 1253ffe455adSEugenia Emantayev int port; 1254ffe455adSEugenia Emantayev int is_eth; 1255b6ffaeffSJack Morgenstein int num_gids; 1256b6ffaeffSJack Morgenstein int base; 1257ffe455adSEugenia Emantayev u32 in_modifier; 1258ffe455adSEugenia Emantayev u32 promisc; 1259ffe455adSEugenia Emantayev u16 mtu, prev_mtu; 1260ffe455adSEugenia Emantayev int err; 1261b6ffaeffSJack Morgenstein int i, j; 1262b6ffaeffSJack Morgenstein int offset; 1263ffe455adSEugenia Emantayev __be32 agg_cap_mask; 1264ffe455adSEugenia Emantayev __be32 slave_cap_mask; 1265ffe455adSEugenia Emantayev __be32 new_cap_mask; 1266ffe455adSEugenia Emantayev 1267ffe455adSEugenia Emantayev port = in_mod & 0xff; 1268ffe455adSEugenia Emantayev in_modifier = in_mod >> 8; 1269ffe455adSEugenia Emantayev is_eth = op_mod; 1270ffe455adSEugenia Emantayev port_info = &priv->port[port]; 1271ffe455adSEugenia Emantayev 1272ffe455adSEugenia Emantayev /* Slaves cannot perform SET_PORT operations except changing MTU */ 1273ffe455adSEugenia Emantayev if (is_eth) { 1274ffe455adSEugenia Emantayev if (slave != dev->caps.function && 12759cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GENERAL && 12769cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GID_TABLE) { 1277ffe455adSEugenia Emantayev mlx4_warn(dev, "denying SET_PORT for slave:%d\n", 1278ffe455adSEugenia Emantayev slave); 1279ffe455adSEugenia Emantayev return -EINVAL; 1280ffe455adSEugenia Emantayev } 1281ffe455adSEugenia Emantayev switch (in_modifier) { 1282ffe455adSEugenia Emantayev case MLX4_SET_PORT_RQP_CALC: 1283ffe455adSEugenia Emantayev qpn_context = inbox->buf; 1284ffe455adSEugenia Emantayev qpn_context->base_qpn = 1285ffe455adSEugenia Emantayev cpu_to_be32(port_info->base_qpn); 1286ffe455adSEugenia Emantayev qpn_context->n_mac = 0x7; 1287ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->promisc) >> 1288ffe455adSEugenia Emantayev SET_PORT_PROMISC_SHIFT; 1289ffe455adSEugenia Emantayev qpn_context->promisc = cpu_to_be32( 1290ffe455adSEugenia Emantayev promisc << SET_PORT_PROMISC_SHIFT | 1291ffe455adSEugenia Emantayev port_info->base_qpn); 1292ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->mcast) >> 1293ffe455adSEugenia Emantayev SET_PORT_MC_PROMISC_SHIFT; 1294ffe455adSEugenia Emantayev qpn_context->mcast = cpu_to_be32( 1295ffe455adSEugenia Emantayev promisc << SET_PORT_MC_PROMISC_SHIFT | 1296ffe455adSEugenia Emantayev port_info->base_qpn); 1297ffe455adSEugenia Emantayev break; 1298ffe455adSEugenia Emantayev case MLX4_SET_PORT_GENERAL: 1299ffe455adSEugenia Emantayev gen_context = inbox->buf; 1300ffe455adSEugenia Emantayev /* Mtu is configured as the max MTU among all the 1301ffe455adSEugenia Emantayev * the functions on the port. */ 1302ffe455adSEugenia Emantayev mtu = be16_to_cpu(gen_context->mtu); 1303c59fec20SEugenia Emantayev mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] + 1304c59fec20SEugenia Emantayev ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); 1305ffe455adSEugenia Emantayev prev_mtu = slave_st->mtu[port]; 1306ffe455adSEugenia Emantayev slave_st->mtu[port] = mtu; 1307ffe455adSEugenia Emantayev if (mtu > master->max_mtu[port]) 1308ffe455adSEugenia Emantayev master->max_mtu[port] = mtu; 1309ffe455adSEugenia Emantayev if (mtu < prev_mtu && prev_mtu == 1310ffe455adSEugenia Emantayev master->max_mtu[port]) { 1311ffe455adSEugenia Emantayev slave_st->mtu[port] = mtu; 1312ffe455adSEugenia Emantayev master->max_mtu[port] = mtu; 1313ffe455adSEugenia Emantayev for (i = 0; i < dev->num_slaves; i++) { 1314ffe455adSEugenia Emantayev master->max_mtu[port] = 1315ffe455adSEugenia Emantayev max(master->max_mtu[port], 1316ffe455adSEugenia Emantayev master->slave_state[i].mtu[port]); 1317ffe455adSEugenia Emantayev } 1318ffe455adSEugenia Emantayev } 1319ffe455adSEugenia Emantayev 1320ffe455adSEugenia Emantayev gen_context->mtu = cpu_to_be16(master->max_mtu[port]); 13212a500090SEugenia Emantayev /* Slave cannot change Global Pause configuration */ 13222a500090SEugenia Emantayev if (slave != mlx4_master_func_num(dev) && 13232a500090SEugenia Emantayev ((gen_context->pptx != master->pptx) || 13242a500090SEugenia Emantayev (gen_context->pprx != master->pprx))) { 13252a500090SEugenia Emantayev gen_context->pptx = master->pptx; 13262a500090SEugenia Emantayev gen_context->pprx = master->pprx; 13272a500090SEugenia Emantayev mlx4_warn(dev, 13282a500090SEugenia Emantayev "denying Global Pause change for slave:%d\n", 13292a500090SEugenia Emantayev slave); 13302a500090SEugenia Emantayev } else { 13312a500090SEugenia Emantayev master->pptx = gen_context->pptx; 13322a500090SEugenia Emantayev master->pprx = gen_context->pprx; 13332a500090SEugenia Emantayev } 1334ffe455adSEugenia Emantayev break; 13359cd59352SJack Morgenstein case MLX4_SET_PORT_GID_TABLE: 1336b6ffaeffSJack Morgenstein /* change to MULTIPLE entries: number of guest's gids 1337b6ffaeffSJack Morgenstein * need a FOR-loop here over number of gids the guest has. 1338b6ffaeffSJack Morgenstein * 1. Check no duplicates in gids passed by slave 1339b6ffaeffSJack Morgenstein */ 1340449fc488SMatan Barak num_gids = mlx4_get_slave_num_gids(dev, slave, port); 1341449fc488SMatan Barak base = mlx4_get_base_gid_ix(dev, slave, port); 1342b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1343b6ffaeffSJack Morgenstein for (i = 0; i < num_gids; gid_entry_mbox++, i++) { 1344b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 1345b6ffaeffSJack Morgenstein sizeof(zgid_entry))) 1346b6ffaeffSJack Morgenstein continue; 1347b6ffaeffSJack Morgenstein gid_entry_mb1 = gid_entry_mbox + 1; 1348b6ffaeffSJack Morgenstein for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) { 1349b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw, 1350b6ffaeffSJack Morgenstein zgid_entry.raw, sizeof(zgid_entry))) 1351b6ffaeffSJack Morgenstein continue; 1352b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw, 1353b6ffaeffSJack Morgenstein sizeof(gid_entry_mbox->raw))) { 1354b6ffaeffSJack Morgenstein /* found duplicate */ 1355b6ffaeffSJack Morgenstein return -EINVAL; 1356b6ffaeffSJack Morgenstein } 1357b6ffaeffSJack Morgenstein } 1358b6ffaeffSJack Morgenstein } 1359b6ffaeffSJack Morgenstein 1360b6ffaeffSJack Morgenstein /* 2. Check that do not have duplicates in OTHER 1361b6ffaeffSJack Morgenstein * entries in the port GID table 1362b6ffaeffSJack Morgenstein */ 1363111c6094SJack Morgenstein 1364111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex)); 13659cd59352SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 1366b6ffaeffSJack Morgenstein if (i >= base && i < base + num_gids) 1367b6ffaeffSJack Morgenstein continue; /* don't compare to slave's current gids */ 1368111c6094SJack Morgenstein gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i]; 1369b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry))) 1370b6ffaeffSJack Morgenstein continue; 1371b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1372b6ffaeffSJack Morgenstein for (j = 0; j < num_gids; gid_entry_mbox++, j++) { 1373b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 1374b6ffaeffSJack Morgenstein sizeof(zgid_entry))) 1375b6ffaeffSJack Morgenstein continue; 1376b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw, 1377b6ffaeffSJack Morgenstein sizeof(gid_entry_tbl->raw))) { 1378b6ffaeffSJack Morgenstein /* found duplicate */ 13791a91de28SJoe Perches mlx4_warn(dev, "requested gid entry for slave:%d is a duplicate of gid at index %d\n", 13809cd59352SJack Morgenstein slave, i); 1381111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 1382b6ffaeffSJack Morgenstein return -EINVAL; 13839cd59352SJack Morgenstein } 13849cd59352SJack Morgenstein } 13859cd59352SJack Morgenstein } 1386b6ffaeffSJack Morgenstein 1387b6ffaeffSJack Morgenstein /* insert slave GIDs with memcpy, starting at slave's base index */ 1388b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1389b6ffaeffSJack Morgenstein for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++) 1390111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 1391111c6094SJack Morgenstein gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE); 1392b6ffaeffSJack Morgenstein 1393b6ffaeffSJack Morgenstein /* Now, copy roce port gids table to current mailbox for passing to FW */ 1394b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1395b6ffaeffSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 1396111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw, 1397111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw, 1398111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 1399b6ffaeffSJack Morgenstein 1400111c6094SJack Morgenstein err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 1401111c6094SJack Morgenstein MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1402111c6094SJack Morgenstein MLX4_CMD_NATIVE); 1403111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 1404111c6094SJack Morgenstein return err; 1405ffe455adSEugenia Emantayev } 1406111c6094SJack Morgenstein 1407111c6094SJack Morgenstein return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 1408ffe455adSEugenia Emantayev MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1409ffe455adSEugenia Emantayev MLX4_CMD_NATIVE); 1410ffe455adSEugenia Emantayev } 1411ffe455adSEugenia Emantayev 141251af33cfSIdo Shamay /* Slaves are not allowed to SET_PORT beacon (LED) blink */ 141351af33cfSIdo Shamay if (op_mod == MLX4_SET_PORT_BEACON_OPCODE) { 141451af33cfSIdo Shamay mlx4_warn(dev, "denying SET_PORT Beacon slave:%d\n", slave); 141551af33cfSIdo Shamay return -EPERM; 141651af33cfSIdo Shamay } 141751af33cfSIdo Shamay 1418ffe455adSEugenia Emantayev /* For IB, we only consider: 1419ffe455adSEugenia Emantayev * - The capability mask, which is set to the aggregate of all 1420ffe455adSEugenia Emantayev * slave function capabilities 1421ffe455adSEugenia Emantayev * - The QKey violatin counter - reset according to each request. 1422ffe455adSEugenia Emantayev */ 1423ffe455adSEugenia Emantayev 1424ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 1425ffe455adSEugenia Emantayev reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40; 1426ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[2]; 1427ffe455adSEugenia Emantayev } else { 1428ffe455adSEugenia Emantayev reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1; 1429ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[1]; 1430ffe455adSEugenia Emantayev } 1431ffe455adSEugenia Emantayev 1432efcd235dSJack Morgenstein /* slave may not set the IS_SM capability for the port */ 1433efcd235dSJack Morgenstein if (slave != mlx4_master_func_num(dev) && 1434efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM)) 1435efcd235dSJack Morgenstein return -EINVAL; 1436efcd235dSJack Morgenstein 1437efcd235dSJack Morgenstein /* No DEV_MGMT in multifunc mode */ 1438efcd235dSJack Morgenstein if (mlx4_is_mfunc(dev) && 1439efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP)) 1440efcd235dSJack Morgenstein return -EINVAL; 1441efcd235dSJack Morgenstein 1442ffe455adSEugenia Emantayev agg_cap_mask = 0; 1443ffe455adSEugenia Emantayev slave_cap_mask = 1444ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; 1445ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask; 1446ffe455adSEugenia Emantayev for (i = 0; i < dev->num_slaves; i++) 1447ffe455adSEugenia Emantayev agg_cap_mask |= 1448ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[i].ib_cap_mask[port]; 1449ffe455adSEugenia Emantayev 1450ffe455adSEugenia Emantayev /* only clear mailbox for guests. Master may be setting 1451ffe455adSEugenia Emantayev * MTU or PKEY table size 1452ffe455adSEugenia Emantayev */ 1453ffe455adSEugenia Emantayev if (slave != dev->caps.function) 1454ffe455adSEugenia Emantayev memset(inbox->buf, 0, 256); 1455ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 1456edc4a67eSJack Morgenstein *(u8 *) inbox->buf |= !!reset_qkey_viols << 6; 1457ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[2] = agg_cap_mask; 1458ffe455adSEugenia Emantayev } else { 1459edc4a67eSJack Morgenstein ((u8 *) inbox->buf)[3] |= !!reset_qkey_viols; 1460ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[1] = agg_cap_mask; 1461ffe455adSEugenia Emantayev } 1462ffe455adSEugenia Emantayev 1463ffe455adSEugenia Emantayev err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT, 1464ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1465ffe455adSEugenia Emantayev if (err) 1466ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = 1467ffe455adSEugenia Emantayev slave_cap_mask; 1468ffe455adSEugenia Emantayev return err; 1469ffe455adSEugenia Emantayev } 1470ffe455adSEugenia Emantayev 1471ffe455adSEugenia Emantayev int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, 1472ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1473ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1474ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1475ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1476ffe455adSEugenia Emantayev { 1477449fc488SMatan Barak int port = mlx4_slave_convert_port( 1478449fc488SMatan Barak dev, slave, vhcr->in_modifier & 0xFF); 1479449fc488SMatan Barak 1480449fc488SMatan Barak if (port < 0) 1481449fc488SMatan Barak return -EINVAL; 1482449fc488SMatan Barak 1483449fc488SMatan Barak vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) | 1484449fc488SMatan Barak (port & 0xFF); 1485449fc488SMatan Barak 1486ffe455adSEugenia Emantayev return mlx4_common_set_port(dev, slave, vhcr->in_modifier, 1487ffe455adSEugenia Emantayev vhcr->op_modifier, inbox); 1488ffe455adSEugenia Emantayev } 1489ffe455adSEugenia Emantayev 1490096335b3SOr Gerlitz /* bit locations for set port command with zero op modifier */ 1491096335b3SOr Gerlitz enum { 1492096335b3SOr Gerlitz MLX4_SET_PORT_VL_CAP = 4, /* bits 7:4 */ 1493096335b3SOr Gerlitz MLX4_SET_PORT_MTU_CAP = 12, /* bits 15:12 */ 14946634961cSJack Morgenstein MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20, 1495096335b3SOr Gerlitz MLX4_CHANGE_PORT_VL_CAP = 21, 1496096335b3SOr Gerlitz MLX4_CHANGE_PORT_MTU_CAP = 22, 1497096335b3SOr Gerlitz }; 1498096335b3SOr Gerlitz 14996634961cSJack Morgenstein int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz) 15005a2cc190SJeff Kirsher { 15015a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 15026634961cSJack Morgenstein int err, vl_cap, pkey_tbl_flag = 0; 15035a2cc190SJeff Kirsher 15045a2cc190SJeff Kirsher if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) 15055a2cc190SJeff Kirsher return 0; 15065a2cc190SJeff Kirsher 15075a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 15085a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 15095a2cc190SJeff Kirsher return PTR_ERR(mailbox); 15105a2cc190SJeff Kirsher 15115a2cc190SJeff Kirsher ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; 1512096335b3SOr Gerlitz 15136634961cSJack Morgenstein if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) { 15146634961cSJack Morgenstein pkey_tbl_flag = 1; 15156634961cSJack Morgenstein ((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz); 15166634961cSJack Morgenstein } 15176634961cSJack Morgenstein 1518096335b3SOr Gerlitz /* IB VL CAP enum isn't used by the firmware, just numerical values */ 1519096335b3SOr Gerlitz for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) { 1520096335b3SOr Gerlitz ((__be32 *) mailbox->buf)[0] = cpu_to_be32( 1521096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_MTU_CAP) | 1522096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_VL_CAP) | 15236634961cSJack Morgenstein (pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) | 1524096335b3SOr Gerlitz (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) | 1525096335b3SOr Gerlitz (vl_cap << MLX4_SET_PORT_VL_CAP)); 1526a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, port, 1527a130b590SIdo Shamay MLX4_SET_PORT_IB_OPCODE, MLX4_CMD_SET_PORT, 1528f9baff50SJack Morgenstein MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 1529096335b3SOr Gerlitz if (err != -ENOMEM) 1530096335b3SOr Gerlitz break; 1531096335b3SOr Gerlitz } 15325a2cc190SJeff Kirsher 15335a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 15345a2cc190SJeff Kirsher return err; 15355a2cc190SJeff Kirsher } 1536ffe455adSEugenia Emantayev 15371da494cbSMoni Shoua #define SET_PORT_ROCE_2_FLAGS 0x10 15381da494cbSMoni Shoua #define MLX4_SET_PORT_ROCE_V1_V2 0x2 1539cb9ffb76SJoerg Roedel int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, 1540ffe455adSEugenia Emantayev u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx) 1541ffe455adSEugenia Emantayev { 1542ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 1543ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *context; 1544ffe455adSEugenia Emantayev int err; 1545ffe455adSEugenia Emantayev u32 in_mod; 1546ffe455adSEugenia Emantayev 1547ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 1548ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 1549ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 1550ffe455adSEugenia Emantayev context = mailbox->buf; 1551ffe455adSEugenia Emantayev context->flags = SET_PORT_GEN_ALL_VALID; 1552ffe455adSEugenia Emantayev context->mtu = cpu_to_be16(mtu); 1553ffe455adSEugenia Emantayev context->pptx = (pptx * (!pfctx)) << 7; 1554ffe455adSEugenia Emantayev context->pfctx = pfctx; 1555ffe455adSEugenia Emantayev context->pprx = (pprx * (!pfcrx)) << 7; 1556ffe455adSEugenia Emantayev context->pfcrx = pfcrx; 1557ffe455adSEugenia Emantayev 15581da494cbSMoni Shoua if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2) { 15591da494cbSMoni Shoua context->flags |= SET_PORT_ROCE_2_FLAGS; 15601da494cbSMoni Shoua context->roce_mode |= 15611da494cbSMoni Shoua MLX4_SET_PORT_ROCE_V1_V2 << 4; 15621da494cbSMoni Shoua } 1563ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 1564a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1565a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1566a130b590SIdo Shamay MLX4_CMD_WRAPPED); 1567ffe455adSEugenia Emantayev 1568ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 1569ffe455adSEugenia Emantayev return err; 1570ffe455adSEugenia Emantayev } 1571ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_general); 1572ffe455adSEugenia Emantayev 1573cb9ffb76SJoerg Roedel int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, 1574ffe455adSEugenia Emantayev u8 promisc) 1575ffe455adSEugenia Emantayev { 1576ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 1577ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *context; 1578ffe455adSEugenia Emantayev int err; 1579ffe455adSEugenia Emantayev u32 in_mod; 1580ffe455adSEugenia Emantayev u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ? 1581ffe455adSEugenia Emantayev MCAST_DIRECT : MCAST_DEFAULT; 1582ffe455adSEugenia Emantayev 1583c96d97f4SHadar Hen Zion if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) 1584ffe455adSEugenia Emantayev return 0; 1585ffe455adSEugenia Emantayev 1586ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 1587ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 1588ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 1589ffe455adSEugenia Emantayev context = mailbox->buf; 1590ffe455adSEugenia Emantayev context->base_qpn = cpu_to_be32(base_qpn); 1591ffe455adSEugenia Emantayev context->n_mac = dev->caps.log_num_macs; 1592ffe455adSEugenia Emantayev context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | 1593ffe455adSEugenia Emantayev base_qpn); 1594ffe455adSEugenia Emantayev context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | 1595ffe455adSEugenia Emantayev base_qpn); 1596ffe455adSEugenia Emantayev context->intra_no_vlan = 0; 1597ffe455adSEugenia Emantayev context->no_vlan = MLX4_NO_VLAN_IDX; 1598ffe455adSEugenia Emantayev context->intra_vlan_miss = 0; 1599ffe455adSEugenia Emantayev context->vlan_miss = MLX4_VLAN_MISS_IDX; 1600ffe455adSEugenia Emantayev 1601ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port; 1602a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1603a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1604a130b590SIdo Shamay MLX4_CMD_WRAPPED); 1605ffe455adSEugenia Emantayev 1606ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 1607ffe455adSEugenia Emantayev return err; 1608ffe455adSEugenia Emantayev } 1609ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); 1610ffe455adSEugenia Emantayev 161178500b8cSMuhammad Mahajna int mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, u8 ignore_fcs_value) 161278500b8cSMuhammad Mahajna { 161378500b8cSMuhammad Mahajna struct mlx4_cmd_mailbox *mailbox; 161478500b8cSMuhammad Mahajna struct mlx4_set_port_general_context *context; 161578500b8cSMuhammad Mahajna u32 in_mod; 161678500b8cSMuhammad Mahajna int err; 161778500b8cSMuhammad Mahajna 161878500b8cSMuhammad Mahajna mailbox = mlx4_alloc_cmd_mailbox(dev); 161978500b8cSMuhammad Mahajna if (IS_ERR(mailbox)) 162078500b8cSMuhammad Mahajna return PTR_ERR(mailbox); 162178500b8cSMuhammad Mahajna context = mailbox->buf; 162278500b8cSMuhammad Mahajna context->v_ignore_fcs |= MLX4_FLAG_V_IGNORE_FCS_MASK; 162378500b8cSMuhammad Mahajna if (ignore_fcs_value) 162478500b8cSMuhammad Mahajna context->ignore_fcs |= MLX4_IGNORE_FCS_MASK; 162578500b8cSMuhammad Mahajna else 162678500b8cSMuhammad Mahajna context->ignore_fcs &= ~MLX4_IGNORE_FCS_MASK; 162778500b8cSMuhammad Mahajna 162878500b8cSMuhammad Mahajna in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 162978500b8cSMuhammad Mahajna err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 163078500b8cSMuhammad Mahajna MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 163178500b8cSMuhammad Mahajna 163278500b8cSMuhammad Mahajna mlx4_free_cmd_mailbox(dev, mailbox); 163378500b8cSMuhammad Mahajna return err; 163478500b8cSMuhammad Mahajna } 163578500b8cSMuhammad Mahajna EXPORT_SYMBOL(mlx4_SET_PORT_fcs_check); 163678500b8cSMuhammad Mahajna 16377ffdf726SOr Gerlitz enum { 16387ffdf726SOr Gerlitz VXLAN_ENABLE_MODIFY = 1 << 7, 16397ffdf726SOr Gerlitz VXLAN_STEERING_MODIFY = 1 << 6, 16407ffdf726SOr Gerlitz 16417ffdf726SOr Gerlitz VXLAN_ENABLE = 1 << 7, 16427ffdf726SOr Gerlitz }; 16437ffdf726SOr Gerlitz 16447ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context { 16457ffdf726SOr Gerlitz u32 reserved1; 16467ffdf726SOr Gerlitz u8 modify_flags; 16477ffdf726SOr Gerlitz u8 reserved2; 16487ffdf726SOr Gerlitz u8 enable_flags; 16497ffdf726SOr Gerlitz u8 steering; 16507ffdf726SOr Gerlitz }; 16517ffdf726SOr Gerlitz 16521b136de1SOr Gerlitz int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable) 16537ffdf726SOr Gerlitz { 16547ffdf726SOr Gerlitz int err; 16557ffdf726SOr Gerlitz u32 in_mod; 16567ffdf726SOr Gerlitz struct mlx4_cmd_mailbox *mailbox; 16577ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context *context; 16587ffdf726SOr Gerlitz 16597ffdf726SOr Gerlitz mailbox = mlx4_alloc_cmd_mailbox(dev); 16607ffdf726SOr Gerlitz if (IS_ERR(mailbox)) 16617ffdf726SOr Gerlitz return PTR_ERR(mailbox); 16627ffdf726SOr Gerlitz context = mailbox->buf; 16637ffdf726SOr Gerlitz memset(context, 0, sizeof(*context)); 16647ffdf726SOr Gerlitz 16657ffdf726SOr Gerlitz context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY; 16661b136de1SOr Gerlitz if (enable) 16677ffdf726SOr Gerlitz context->enable_flags = VXLAN_ENABLE; 16687ffdf726SOr Gerlitz context->steering = steering; 16697ffdf726SOr Gerlitz 16707ffdf726SOr Gerlitz in_mod = MLX4_SET_PORT_VXLAN << 8 | port; 1671a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1672a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1673a130b590SIdo Shamay MLX4_CMD_NATIVE); 16747ffdf726SOr Gerlitz 16757ffdf726SOr Gerlitz mlx4_free_cmd_mailbox(dev, mailbox); 16767ffdf726SOr Gerlitz return err; 16777ffdf726SOr Gerlitz } 16787ffdf726SOr Gerlitz EXPORT_SYMBOL(mlx4_SET_PORT_VXLAN); 16797ffdf726SOr Gerlitz 168051af33cfSIdo Shamay int mlx4_SET_PORT_BEACON(struct mlx4_dev *dev, u8 port, u16 time) 168151af33cfSIdo Shamay { 168251af33cfSIdo Shamay int err; 168351af33cfSIdo Shamay struct mlx4_cmd_mailbox *mailbox; 168451af33cfSIdo Shamay 168551af33cfSIdo Shamay mailbox = mlx4_alloc_cmd_mailbox(dev); 168651af33cfSIdo Shamay if (IS_ERR(mailbox)) 168751af33cfSIdo Shamay return PTR_ERR(mailbox); 168851af33cfSIdo Shamay 168951af33cfSIdo Shamay *((__be32 *)mailbox->buf) = cpu_to_be32(time); 169051af33cfSIdo Shamay 169151af33cfSIdo Shamay err = mlx4_cmd(dev, mailbox->dma, port, MLX4_SET_PORT_BEACON_OPCODE, 169251af33cfSIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 169351af33cfSIdo Shamay MLX4_CMD_NATIVE); 169451af33cfSIdo Shamay 169551af33cfSIdo Shamay mlx4_free_cmd_mailbox(dev, mailbox); 169651af33cfSIdo Shamay return err; 169751af33cfSIdo Shamay } 169851af33cfSIdo Shamay EXPORT_SYMBOL(mlx4_SET_PORT_BEACON); 169951af33cfSIdo Shamay 1700ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1701ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1702ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1703ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1704ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1705ffe455adSEugenia Emantayev { 1706ffe455adSEugenia Emantayev int err = 0; 1707ffe455adSEugenia Emantayev 1708ffe455adSEugenia Emantayev return err; 1709ffe455adSEugenia Emantayev } 1710ffe455adSEugenia Emantayev 1711ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, 1712ffe455adSEugenia Emantayev u64 mac, u64 clear, u8 mode) 1713ffe455adSEugenia Emantayev { 1714ffe455adSEugenia Emantayev return mlx4_cmd(dev, (mac | (clear << 63)), port, mode, 1715ffe455adSEugenia Emantayev MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B, 1716ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 1717ffe455adSEugenia Emantayev } 1718ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR); 1719ffe455adSEugenia Emantayev 1720ffe455adSEugenia Emantayev int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1721ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1722ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1723ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1724ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1725ffe455adSEugenia Emantayev { 1726ffe455adSEugenia Emantayev int err = 0; 1727ffe455adSEugenia Emantayev 1728ffe455adSEugenia Emantayev return err; 1729ffe455adSEugenia Emantayev } 1730ffe455adSEugenia Emantayev 1731ffe455adSEugenia Emantayev int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave, 1732ffe455adSEugenia Emantayev u32 in_mod, struct mlx4_cmd_mailbox *outbox) 1733ffe455adSEugenia Emantayev { 1734ffe455adSEugenia Emantayev return mlx4_cmd_box(dev, 0, outbox->dma, in_mod, 0, 1735ffe455adSEugenia Emantayev MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B, 1736ffe455adSEugenia Emantayev MLX4_CMD_NATIVE); 1737ffe455adSEugenia Emantayev } 1738ffe455adSEugenia Emantayev 1739ffe455adSEugenia Emantayev int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, 1740ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1741ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1742ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1743ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1744ffe455adSEugenia Emantayev { 174535fb9afbSEugenia Emantayev if (slave != dev->caps.function) 174635fb9afbSEugenia Emantayev return 0; 1747ffe455adSEugenia Emantayev return mlx4_common_dump_eth_stats(dev, slave, 1748ffe455adSEugenia Emantayev vhcr->in_modifier, outbox); 1749ffe455adSEugenia Emantayev } 175093ece0c1SEugenia Emantayev 17519cd59352SJack Morgenstein int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, 17529cd59352SJack Morgenstein int *slave_id) 17536ee51a4eSJack Morgenstein { 17546ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 17556ee51a4eSJack Morgenstein int i, found_ix = -1; 1756b6ffaeffSJack Morgenstein int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 1757449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 1758449fc488SMatan Barak unsigned num_vfs; 1759449fc488SMatan Barak int slave_gid; 17606ee51a4eSJack Morgenstein 17616ee51a4eSJack Morgenstein if (!mlx4_is_mfunc(dev)) 17626ee51a4eSJack Morgenstein return -EINVAL; 17636ee51a4eSJack Morgenstein 1764449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1765872bf2fbSYishai Hadas num_vfs = bitmap_weight(slaves_pport.slaves, 1766872bf2fbSYishai Hadas dev->persist->num_vfs + 1) - 1; 1767449fc488SMatan Barak 17686ee51a4eSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 1769111c6094SJack Morgenstein if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid, 1770111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE)) { 17716ee51a4eSJack Morgenstein found_ix = i; 17726ee51a4eSJack Morgenstein break; 17736ee51a4eSJack Morgenstein } 17746ee51a4eSJack Morgenstein } 17756ee51a4eSJack Morgenstein 1776b6ffaeffSJack Morgenstein if (found_ix >= 0) { 17770254bc82SMatan Barak /* Calculate a slave_gid which is the slave number in the gid 17780254bc82SMatan Barak * table and not a globally unique slave number. 17790254bc82SMatan Barak */ 1780b6ffaeffSJack Morgenstein if (found_ix < MLX4_ROCE_PF_GIDS) 1781449fc488SMatan Barak slave_gid = 0; 1782449fc488SMatan Barak else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) * 1783449fc488SMatan Barak (vf_gids / num_vfs + 1)) 1784449fc488SMatan Barak slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) / 1785449fc488SMatan Barak (vf_gids / num_vfs + 1)) + 1; 1786b6ffaeffSJack Morgenstein else 1787449fc488SMatan Barak slave_gid = 1788b6ffaeffSJack Morgenstein ((found_ix - MLX4_ROCE_PF_GIDS - 1789449fc488SMatan Barak ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) / 1790449fc488SMatan Barak (vf_gids / num_vfs)) + vf_gids % num_vfs + 1; 1791449fc488SMatan Barak 17920254bc82SMatan Barak /* Calculate the globally unique slave id */ 1793449fc488SMatan Barak if (slave_gid) { 1794449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 1795449fc488SMatan Barak struct mlx4_active_ports actv_ports; 1796449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 1797449fc488SMatan Barak unsigned max_port_p_one; 17980254bc82SMatan Barak int num_vfs_before = 0; 17990254bc82SMatan Barak int candidate_slave_gid; 1800449fc488SMatan Barak 18010254bc82SMatan Barak /* Calculate how many VFs are on the previous port, if exists */ 1802449fc488SMatan Barak for (i = 1; i < port; i++) { 1803449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 18040254bc82SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1805449fc488SMatan Barak slaves_pport_actv = 1806449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv( 1807449fc488SMatan Barak dev, &exclusive_ports); 18080254bc82SMatan Barak num_vfs_before += bitmap_weight( 1809449fc488SMatan Barak slaves_pport_actv.slaves, 1810872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1811449fc488SMatan Barak } 1812449fc488SMatan Barak 18130254bc82SMatan Barak /* candidate_slave_gid isn't necessarily the correct slave, but 18140254bc82SMatan Barak * it has the same number of ports and is assigned to the same 18150254bc82SMatan Barak * ports as the real slave we're looking for. On dual port VF, 18160254bc82SMatan Barak * slave_gid = [single port VFs on port <port>] + 18170254bc82SMatan Barak * [offset of the current slave from the first dual port VF] + 18180254bc82SMatan Barak * 1 (for the PF). 18190254bc82SMatan Barak */ 18200254bc82SMatan Barak candidate_slave_gid = slave_gid + num_vfs_before; 18210254bc82SMatan Barak 18220254bc82SMatan Barak actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid); 1823449fc488SMatan Barak max_port_p_one = find_first_bit( 1824449fc488SMatan Barak actv_ports.ports, dev->caps.num_ports) + 1825449fc488SMatan Barak bitmap_weight(actv_ports.ports, 1826449fc488SMatan Barak dev->caps.num_ports) + 1; 1827449fc488SMatan Barak 18280254bc82SMatan Barak /* Calculate the real slave number */ 1829449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 1830449fc488SMatan Barak if (i == port) 1831449fc488SMatan Barak continue; 1832449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, 1833449fc488SMatan Barak dev->caps.num_ports); 1834449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1835449fc488SMatan Barak slaves_pport_actv = 1836449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv( 1837449fc488SMatan Barak dev, &exclusive_ports); 1838449fc488SMatan Barak slave_gid += bitmap_weight( 1839449fc488SMatan Barak slaves_pport_actv.slaves, 1840872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1841449fc488SMatan Barak } 1842449fc488SMatan Barak } 1843449fc488SMatan Barak *slave_id = slave_gid; 1844b6ffaeffSJack Morgenstein } 18456ee51a4eSJack Morgenstein 18466ee51a4eSJack Morgenstein return (found_ix >= 0) ? 0 : -EINVAL; 18476ee51a4eSJack Morgenstein } 18486ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid); 18496ee51a4eSJack Morgenstein 18509cd59352SJack Morgenstein int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, 18519cd59352SJack Morgenstein u8 *gid) 18526ee51a4eSJack Morgenstein { 18536ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 18546ee51a4eSJack Morgenstein 18556ee51a4eSJack Morgenstein if (!mlx4_is_master(dev)) 18566ee51a4eSJack Morgenstein return -EINVAL; 18576ee51a4eSJack Morgenstein 1858111c6094SJack Morgenstein memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw, 1859111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 18606ee51a4eSJack Morgenstein return 0; 18616ee51a4eSJack Morgenstein } 18626ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); 186332a173c7SSaeed Mahameed 186432a173c7SSaeed Mahameed /* Cable Module Info */ 186532a173c7SSaeed Mahameed #define MODULE_INFO_MAX_READ 48 186632a173c7SSaeed Mahameed 186732a173c7SSaeed Mahameed #define I2C_ADDR_LOW 0x50 186832a173c7SSaeed Mahameed #define I2C_ADDR_HIGH 0x51 186932a173c7SSaeed Mahameed #define I2C_PAGE_SIZE 256 187032a173c7SSaeed Mahameed 187132a173c7SSaeed Mahameed /* Module Info Data */ 187232a173c7SSaeed Mahameed struct mlx4_cable_info { 187332a173c7SSaeed Mahameed u8 i2c_addr; 187432a173c7SSaeed Mahameed u8 page_num; 187532a173c7SSaeed Mahameed __be16 dev_mem_address; 187632a173c7SSaeed Mahameed __be16 reserved1; 187732a173c7SSaeed Mahameed __be16 size; 187832a173c7SSaeed Mahameed __be32 reserved2[2]; 187932a173c7SSaeed Mahameed u8 data[MODULE_INFO_MAX_READ]; 188032a173c7SSaeed Mahameed }; 188132a173c7SSaeed Mahameed 188232a173c7SSaeed Mahameed enum cable_info_err { 188332a173c7SSaeed Mahameed CABLE_INF_INV_PORT = 0x1, 188432a173c7SSaeed Mahameed CABLE_INF_OP_NOSUP = 0x2, 188532a173c7SSaeed Mahameed CABLE_INF_NOT_CONN = 0x3, 188632a173c7SSaeed Mahameed CABLE_INF_NO_EEPRM = 0x4, 188732a173c7SSaeed Mahameed CABLE_INF_PAGE_ERR = 0x5, 188832a173c7SSaeed Mahameed CABLE_INF_INV_ADDR = 0x6, 188932a173c7SSaeed Mahameed CABLE_INF_I2C_ADDR = 0x7, 189032a173c7SSaeed Mahameed CABLE_INF_QSFP_VIO = 0x8, 189132a173c7SSaeed Mahameed CABLE_INF_I2C_BUSY = 0x9, 189232a173c7SSaeed Mahameed }; 189332a173c7SSaeed Mahameed 189432a173c7SSaeed Mahameed #define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF) 189532a173c7SSaeed Mahameed 189632a173c7SSaeed Mahameed static inline const char *cable_info_mad_err_str(u16 mad_status) 189732a173c7SSaeed Mahameed { 189832a173c7SSaeed Mahameed u8 err = MAD_STATUS_2_CABLE_ERR(mad_status); 189932a173c7SSaeed Mahameed 190032a173c7SSaeed Mahameed switch (err) { 190132a173c7SSaeed Mahameed case CABLE_INF_INV_PORT: 190232a173c7SSaeed Mahameed return "invalid port selected"; 190332a173c7SSaeed Mahameed case CABLE_INF_OP_NOSUP: 190432a173c7SSaeed Mahameed return "operation not supported for this port (the port is of type CX4 or internal)"; 190532a173c7SSaeed Mahameed case CABLE_INF_NOT_CONN: 190632a173c7SSaeed Mahameed return "cable is not connected"; 190732a173c7SSaeed Mahameed case CABLE_INF_NO_EEPRM: 190832a173c7SSaeed Mahameed return "the connected cable has no EPROM (passive copper cable)"; 190932a173c7SSaeed Mahameed case CABLE_INF_PAGE_ERR: 191032a173c7SSaeed Mahameed return "page number is greater than 15"; 191132a173c7SSaeed Mahameed case CABLE_INF_INV_ADDR: 191232a173c7SSaeed Mahameed return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)"; 191332a173c7SSaeed Mahameed case CABLE_INF_I2C_ADDR: 191432a173c7SSaeed Mahameed return "invalid I2C slave address"; 191532a173c7SSaeed Mahameed case CABLE_INF_QSFP_VIO: 191632a173c7SSaeed Mahameed return "at least one cable violates the QSFP specification and ignores the modsel signal"; 191732a173c7SSaeed Mahameed case CABLE_INF_I2C_BUSY: 191832a173c7SSaeed Mahameed return "I2C bus is constantly busy"; 191932a173c7SSaeed Mahameed } 192032a173c7SSaeed Mahameed return "Unknown Error"; 192132a173c7SSaeed Mahameed } 192232a173c7SSaeed Mahameed 192332a173c7SSaeed Mahameed /** 192432a173c7SSaeed Mahameed * mlx4_get_module_info - Read cable module eeprom data 192532a173c7SSaeed Mahameed * @dev: mlx4_dev. 192632a173c7SSaeed Mahameed * @port: port number. 192732a173c7SSaeed Mahameed * @offset: byte offset in eeprom to start reading data from. 192832a173c7SSaeed Mahameed * @size: num of bytes to read. 192932a173c7SSaeed Mahameed * @data: output buffer to put the requested data into. 193032a173c7SSaeed Mahameed * 193132a173c7SSaeed Mahameed * Reads cable module eeprom data, puts the outcome data into 193232a173c7SSaeed Mahameed * data pointer paramer. 193332a173c7SSaeed Mahameed * Returns num of read bytes on success or a negative error 193432a173c7SSaeed Mahameed * code. 193532a173c7SSaeed Mahameed */ 193632a173c7SSaeed Mahameed int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, 193732a173c7SSaeed Mahameed u16 offset, u16 size, u8 *data) 193832a173c7SSaeed Mahameed { 193932a173c7SSaeed Mahameed struct mlx4_cmd_mailbox *inbox, *outbox; 194032a173c7SSaeed Mahameed struct mlx4_mad_ifc *inmad, *outmad; 194132a173c7SSaeed Mahameed struct mlx4_cable_info *cable_info; 194232a173c7SSaeed Mahameed u16 i2c_addr; 194332a173c7SSaeed Mahameed int ret; 194432a173c7SSaeed Mahameed 194532a173c7SSaeed Mahameed if (size > MODULE_INFO_MAX_READ) 194632a173c7SSaeed Mahameed size = MODULE_INFO_MAX_READ; 194732a173c7SSaeed Mahameed 194832a173c7SSaeed Mahameed inbox = mlx4_alloc_cmd_mailbox(dev); 194932a173c7SSaeed Mahameed if (IS_ERR(inbox)) 195032a173c7SSaeed Mahameed return PTR_ERR(inbox); 195132a173c7SSaeed Mahameed 195232a173c7SSaeed Mahameed outbox = mlx4_alloc_cmd_mailbox(dev); 195332a173c7SSaeed Mahameed if (IS_ERR(outbox)) { 195432a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, inbox); 195532a173c7SSaeed Mahameed return PTR_ERR(outbox); 195632a173c7SSaeed Mahameed } 195732a173c7SSaeed Mahameed 195832a173c7SSaeed Mahameed inmad = (struct mlx4_mad_ifc *)(inbox->buf); 195932a173c7SSaeed Mahameed outmad = (struct mlx4_mad_ifc *)(outbox->buf); 196032a173c7SSaeed Mahameed 196132a173c7SSaeed Mahameed inmad->method = 0x1; /* Get */ 196232a173c7SSaeed Mahameed inmad->class_version = 0x1; 196332a173c7SSaeed Mahameed inmad->mgmt_class = 0x1; 196432a173c7SSaeed Mahameed inmad->base_version = 0x1; 196532a173c7SSaeed Mahameed inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */ 196632a173c7SSaeed Mahameed 196732a173c7SSaeed Mahameed if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE) 196832a173c7SSaeed Mahameed /* Cross pages reads are not allowed 196932a173c7SSaeed Mahameed * read until offset 256 in low page 197032a173c7SSaeed Mahameed */ 197132a173c7SSaeed Mahameed size -= offset + size - I2C_PAGE_SIZE; 197232a173c7SSaeed Mahameed 197332a173c7SSaeed Mahameed i2c_addr = I2C_ADDR_LOW; 197432a173c7SSaeed Mahameed if (offset >= I2C_PAGE_SIZE) { 197532a173c7SSaeed Mahameed /* Reset offset to high page */ 197632a173c7SSaeed Mahameed i2c_addr = I2C_ADDR_HIGH; 197732a173c7SSaeed Mahameed offset -= I2C_PAGE_SIZE; 197832a173c7SSaeed Mahameed } 197932a173c7SSaeed Mahameed 198032a173c7SSaeed Mahameed cable_info = (struct mlx4_cable_info *)inmad->data; 198132a173c7SSaeed Mahameed cable_info->dev_mem_address = cpu_to_be16(offset); 198232a173c7SSaeed Mahameed cable_info->page_num = 0; 198332a173c7SSaeed Mahameed cable_info->i2c_addr = i2c_addr; 198432a173c7SSaeed Mahameed cable_info->size = cpu_to_be16(size); 198532a173c7SSaeed Mahameed 198632a173c7SSaeed Mahameed ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, 198732a173c7SSaeed Mahameed MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 198832a173c7SSaeed Mahameed MLX4_CMD_NATIVE); 198932a173c7SSaeed Mahameed if (ret) 199032a173c7SSaeed Mahameed goto out; 199132a173c7SSaeed Mahameed 199232a173c7SSaeed Mahameed if (be16_to_cpu(outmad->status)) { 199332a173c7SSaeed Mahameed /* Mad returned with bad status */ 199432a173c7SSaeed Mahameed ret = be16_to_cpu(outmad->status); 199532a173c7SSaeed Mahameed mlx4_warn(dev, 199632a173c7SSaeed Mahameed "MLX4_CMD_MAD_IFC Get Module info attr(%x) port(%d) i2c_addr(%x) offset(%d) size(%d): Response Mad Status(%x) - %s\n", 199732a173c7SSaeed Mahameed 0xFF60, port, i2c_addr, offset, size, 199832a173c7SSaeed Mahameed ret, cable_info_mad_err_str(ret)); 199932a173c7SSaeed Mahameed 200032a173c7SSaeed Mahameed if (i2c_addr == I2C_ADDR_HIGH && 200132a173c7SSaeed Mahameed MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR) 200232a173c7SSaeed Mahameed /* Some SFP cables do not support i2c slave 200332a173c7SSaeed Mahameed * address 0x51 (high page), abort silently. 200432a173c7SSaeed Mahameed */ 200532a173c7SSaeed Mahameed ret = 0; 200632a173c7SSaeed Mahameed else 200732a173c7SSaeed Mahameed ret = -ret; 200832a173c7SSaeed Mahameed goto out; 200932a173c7SSaeed Mahameed } 201032a173c7SSaeed Mahameed cable_info = (struct mlx4_cable_info *)outmad->data; 201132a173c7SSaeed Mahameed memcpy(data, cable_info->data, size); 201232a173c7SSaeed Mahameed ret = size; 201332a173c7SSaeed Mahameed out: 201432a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, inbox); 201532a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, outbox); 201632a173c7SSaeed Mahameed return ret; 201732a173c7SSaeed Mahameed } 201832a173c7SSaeed Mahameed EXPORT_SYMBOL(mlx4_get_module_info); 2019af7d5185SRana Shahout 2020af7d5185SRana Shahout int mlx4_max_tc(struct mlx4_dev *dev) 2021af7d5185SRana Shahout { 2022af7d5185SRana Shahout u8 num_tc = dev->caps.max_tc_eth; 2023af7d5185SRana Shahout 2024af7d5185SRana Shahout if (!num_tc) 2025564ed9b1STariq Toukan num_tc = MLX4_TC_MAX_NUMBER; 2026af7d5185SRana Shahout 2027af7d5185SRana Shahout return num_tc; 2028af7d5185SRana Shahout } 2029af7d5185SRana Shahout EXPORT_SYMBOL(mlx4_max_tc); 2030