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 5340fb4fc1SShaker Daibes #define MLX4_FLAG2_V_IGNORE_FCS_MASK BIT(1) 5440fb4fc1SShaker Daibes #define MLX4_FLAG2_V_USER_MTU_MASK BIT(5) 55be599603SMoshe Shemesh #define MLX4_FLAG2_V_USER_MAC_MASK BIT(6) 56bf1f9396SShaker Daibes #define MLX4_FLAG_V_MTU_MASK BIT(0) 571f8176f7SShaker Daibes #define MLX4_FLAG_V_PPRX_MASK BIT(1) 581f8176f7SShaker Daibes #define MLX4_FLAG_V_PPTX_MASK BIT(2) 5978500b8cSMuhammad Mahajna #define MLX4_IGNORE_FCS_MASK 0x1 60564ed9b1STariq Toukan #define MLX4_TC_MAX_NUMBER 8 6178500b8cSMuhammad Mahajna 625a2cc190SJeff Kirsher void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table) 635a2cc190SJeff Kirsher { 645a2cc190SJeff Kirsher int i; 655a2cc190SJeff Kirsher 665a2cc190SJeff Kirsher mutex_init(&table->mutex); 675a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 685a2cc190SJeff Kirsher table->entries[i] = 0; 695a2cc190SJeff Kirsher table->refs[i] = 0; 705f61385dSMoni Shoua table->is_dup[i] = false; 715a2cc190SJeff Kirsher } 725a2cc190SJeff Kirsher table->max = 1 << dev->caps.log_num_macs; 735a2cc190SJeff Kirsher table->total = 0; 745a2cc190SJeff Kirsher } 755a2cc190SJeff Kirsher 765a2cc190SJeff Kirsher void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table) 775a2cc190SJeff Kirsher { 785a2cc190SJeff Kirsher int i; 795a2cc190SJeff Kirsher 805a2cc190SJeff Kirsher mutex_init(&table->mutex); 815a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 825a2cc190SJeff Kirsher table->entries[i] = 0; 835a2cc190SJeff Kirsher table->refs[i] = 0; 845f61385dSMoni Shoua table->is_dup[i] = false; 855a2cc190SJeff Kirsher } 86e72ebf5aSYevgeny Petrilin table->max = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR; 875a2cc190SJeff Kirsher table->total = 0; 885a2cc190SJeff Kirsher } 895a2cc190SJeff Kirsher 90111c6094SJack Morgenstein void mlx4_init_roce_gid_table(struct mlx4_dev *dev, 91111c6094SJack Morgenstein struct mlx4_roce_gid_table *table) 92111c6094SJack Morgenstein { 93111c6094SJack Morgenstein int i; 94111c6094SJack Morgenstein 95111c6094SJack Morgenstein mutex_init(&table->mutex); 96111c6094SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) 97111c6094SJack Morgenstein memset(table->roce_gids[i].raw, 0, MLX4_ROCE_GID_ENTRY_SIZE); 98111c6094SJack Morgenstein } 99111c6094SJack Morgenstein 1005a2cc190SJeff Kirsher static int validate_index(struct mlx4_dev *dev, 1015a2cc190SJeff Kirsher struct mlx4_mac_table *table, int index) 1025a2cc190SJeff Kirsher { 1035a2cc190SJeff Kirsher int err = 0; 1045a2cc190SJeff Kirsher 1055a2cc190SJeff Kirsher if (index < 0 || index >= table->max || !table->entries[index]) { 1065a2cc190SJeff Kirsher mlx4_warn(dev, "No valid Mac entry for the given index\n"); 1075a2cc190SJeff Kirsher err = -EINVAL; 1085a2cc190SJeff Kirsher } 1095a2cc190SJeff Kirsher return err; 1105a2cc190SJeff Kirsher } 1115a2cc190SJeff Kirsher 1125a2cc190SJeff Kirsher static int find_index(struct mlx4_dev *dev, 1135a2cc190SJeff Kirsher struct mlx4_mac_table *table, u64 mac) 1145a2cc190SJeff Kirsher { 1155a2cc190SJeff Kirsher int i; 116ffe455adSEugenia Emantayev 1175a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 118f4fd40b2SJack Morgenstein if (table->refs[i] && 119f4fd40b2SJack Morgenstein (MLX4_MAC_MASK & mac) == 120ffe455adSEugenia Emantayev (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) 1215a2cc190SJeff Kirsher return i; 1225a2cc190SJeff Kirsher } 1235a2cc190SJeff Kirsher /* Mac not found */ 1245a2cc190SJeff Kirsher return -EINVAL; 1255a2cc190SJeff Kirsher } 1265a2cc190SJeff Kirsher 127ffe455adSEugenia Emantayev static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, 128ffe455adSEugenia Emantayev __be64 *entries) 129ffe455adSEugenia Emantayev { 130ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 131ffe455adSEugenia Emantayev u32 in_mod; 132ffe455adSEugenia Emantayev int err; 133ffe455adSEugenia Emantayev 134ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 135ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 136ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 137ffe455adSEugenia Emantayev 138ffe455adSEugenia Emantayev memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); 139ffe455adSEugenia Emantayev 140ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; 141ffe455adSEugenia Emantayev 142a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 143a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 144a130b590SIdo Shamay MLX4_CMD_NATIVE); 145ffe455adSEugenia Emantayev 146ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 147ffe455adSEugenia Emantayev return err; 148ffe455adSEugenia Emantayev } 149ffe455adSEugenia Emantayev 150297e0dadSMoni Shoua int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx) 151297e0dadSMoni Shoua { 152297e0dadSMoni Shoua struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 153297e0dadSMoni Shoua struct mlx4_mac_table *table = &info->mac_table; 154297e0dadSMoni Shoua int i; 155297e0dadSMoni Shoua 156297e0dadSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 157297e0dadSMoni Shoua if (!table->refs[i]) 158297e0dadSMoni Shoua continue; 159297e0dadSMoni Shoua 160297e0dadSMoni Shoua if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 161297e0dadSMoni Shoua *idx = i; 162297e0dadSMoni Shoua return 0; 163297e0dadSMoni Shoua } 164297e0dadSMoni Shoua } 165297e0dadSMoni Shoua 166297e0dadSMoni Shoua return -ENOENT; 167297e0dadSMoni Shoua } 168297e0dadSMoni Shoua EXPORT_SYMBOL_GPL(mlx4_find_cached_mac); 169297e0dadSMoni Shoua 1705f61385dSMoni Shoua static bool mlx4_need_mf_bond(struct mlx4_dev *dev) 1715f61385dSMoni Shoua { 1725f61385dSMoni Shoua int i, num_eth_ports = 0; 1735f61385dSMoni Shoua 1745f61385dSMoni Shoua if (!mlx4_is_mfunc(dev)) 1755f61385dSMoni Shoua return false; 1765f61385dSMoni Shoua mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) 1775f61385dSMoni Shoua ++num_eth_ports; 1785f61385dSMoni Shoua 1795f61385dSMoni Shoua return (num_eth_ports == 2) ? true : false; 1805f61385dSMoni Shoua } 1815f61385dSMoni Shoua 182ffe455adSEugenia Emantayev int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 183ffe455adSEugenia Emantayev { 184ffe455adSEugenia Emantayev struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 185ffe455adSEugenia Emantayev struct mlx4_mac_table *table = &info->mac_table; 186ffe455adSEugenia Emantayev int i, err = 0; 187ffe455adSEugenia Emantayev int free = -1; 1885f61385dSMoni Shoua int free_for_dup = -1; 1895f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 1905f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 1915f61385dSMoni Shoua struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table; 1925f61385dSMoni Shoua bool need_mf_bond = mlx4_need_mf_bond(dev); 1935f61385dSMoni Shoua bool can_mf_bond = true; 194ffe455adSEugenia Emantayev 1955f61385dSMoni Shoua mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d %s duplicate\n", 1965f61385dSMoni Shoua (unsigned long long)mac, port, 1975f61385dSMoni Shoua dup ? "with" : "without"); 198ffe455adSEugenia Emantayev 1995f61385dSMoni Shoua if (need_mf_bond) { 2005f61385dSMoni Shoua if (port == 1) { 201ffe455adSEugenia Emantayev mutex_lock(&table->mutex); 20203a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 2035f61385dSMoni Shoua } else { 2045f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 20503a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 2065f61385dSMoni Shoua } 2075f61385dSMoni Shoua } else { 2085f61385dSMoni Shoua mutex_lock(&table->mutex); 2095f61385dSMoni Shoua } 2105f61385dSMoni Shoua 2115f61385dSMoni Shoua if (need_mf_bond) { 2125f61385dSMoni Shoua int index_at_port = -1; 2135f61385dSMoni Shoua int index_at_dup_port = -1; 2145f61385dSMoni Shoua 2155f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 2165f61385dSMoni Shoua if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))) 2175f61385dSMoni Shoua index_at_port = i; 2185f61385dSMoni Shoua if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i])))) 2195f61385dSMoni Shoua index_at_dup_port = i; 2205f61385dSMoni Shoua } 2215f61385dSMoni Shoua 2225f61385dSMoni Shoua /* check that same mac is not in the tables at different indices */ 2235f61385dSMoni Shoua if ((index_at_port != index_at_dup_port) && 2245f61385dSMoni Shoua (index_at_port >= 0) && 2255f61385dSMoni Shoua (index_at_dup_port >= 0)) 2265f61385dSMoni Shoua can_mf_bond = false; 2275f61385dSMoni Shoua 2285f61385dSMoni Shoua /* If the mac is already in the primary table, the slot must be 2295f61385dSMoni Shoua * available in the duplicate table as well. 2305f61385dSMoni Shoua */ 2315f61385dSMoni Shoua if (index_at_port >= 0 && index_at_dup_port < 0 && 2325f61385dSMoni Shoua dup_table->refs[index_at_port]) { 2335f61385dSMoni Shoua can_mf_bond = false; 2345f61385dSMoni Shoua } 2355f61385dSMoni Shoua /* If the mac is already in the duplicate table, check that the 2365f61385dSMoni Shoua * corresponding index is not occupied in the primary table, or 2375f61385dSMoni Shoua * the primary table already contains the mac at the same index. 2385f61385dSMoni Shoua * Otherwise, you cannot bond (primary contains a different mac 2395f61385dSMoni Shoua * at that index). 2405f61385dSMoni Shoua */ 2415f61385dSMoni Shoua if (index_at_dup_port >= 0) { 2425f61385dSMoni Shoua if (!table->refs[index_at_dup_port] || 2435f61385dSMoni Shoua ((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[index_at_dup_port])))) 2445f61385dSMoni Shoua free_for_dup = index_at_dup_port; 2455f61385dSMoni Shoua else 2465f61385dSMoni Shoua can_mf_bond = false; 2475f61385dSMoni Shoua } 2485f61385dSMoni Shoua } 2495f61385dSMoni Shoua 250ffe455adSEugenia Emantayev for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 251f4fd40b2SJack Morgenstein if (!table->refs[i]) { 252f4fd40b2SJack Morgenstein if (free < 0) 253ffe455adSEugenia Emantayev free = i; 2545f61385dSMoni Shoua if (free_for_dup < 0 && need_mf_bond && can_mf_bond) { 2555f61385dSMoni Shoua if (!dup_table->refs[i]) 2565f61385dSMoni Shoua free_for_dup = i; 2575f61385dSMoni Shoua } 258ffe455adSEugenia Emantayev continue; 259ffe455adSEugenia Emantayev } 260ffe455adSEugenia Emantayev 261f4fd40b2SJack Morgenstein if ((MLX4_MAC_MASK & mac) == 262f4fd40b2SJack Morgenstein (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 2636ce71acdSRony Efraim /* MAC already registered, increment ref count */ 2646ce71acdSRony Efraim err = i; 2656ce71acdSRony Efraim ++table->refs[i]; 2665f61385dSMoni Shoua if (dup) { 2675f61385dSMoni Shoua u64 dup_mac = MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]); 2685f61385dSMoni Shoua 2695f61385dSMoni Shoua if (dup_mac != mac || !dup_table->is_dup[i]) { 2705f61385dSMoni Shoua mlx4_warn(dev, "register mac: expect duplicate mac 0x%llx on port %d index %d\n", 2715f61385dSMoni Shoua mac, dup_port, i); 2725f61385dSMoni Shoua } 2735f61385dSMoni Shoua } 274ffe455adSEugenia Emantayev goto out; 275ffe455adSEugenia Emantayev } 276ffe455adSEugenia Emantayev } 277ffe455adSEugenia Emantayev 2785f61385dSMoni Shoua if (need_mf_bond && (free_for_dup < 0)) { 2795f61385dSMoni Shoua if (dup) { 2805f61385dSMoni Shoua mlx4_warn(dev, "Fail to allocate duplicate MAC table entry\n"); 2815f61385dSMoni Shoua mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n"); 2825f61385dSMoni Shoua dup = false; 2835f61385dSMoni Shoua } 2845f61385dSMoni Shoua can_mf_bond = false; 2855f61385dSMoni Shoua } 2865f61385dSMoni Shoua 2875f61385dSMoni Shoua if (need_mf_bond && can_mf_bond) 2885f61385dSMoni Shoua free = free_for_dup; 2895f61385dSMoni Shoua 290ffe455adSEugenia Emantayev mlx4_dbg(dev, "Free MAC index is %d\n", free); 291ffe455adSEugenia Emantayev 292ffe455adSEugenia Emantayev if (table->total == table->max) { 293ffe455adSEugenia Emantayev /* No free mac entries */ 294ffe455adSEugenia Emantayev err = -ENOSPC; 295ffe455adSEugenia Emantayev goto out; 296ffe455adSEugenia Emantayev } 297ffe455adSEugenia Emantayev 298ffe455adSEugenia Emantayev /* Register new MAC */ 299ffe455adSEugenia Emantayev table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); 300ffe455adSEugenia Emantayev 301ffe455adSEugenia Emantayev err = mlx4_set_port_mac_table(dev, port, table->entries); 302ffe455adSEugenia Emantayev if (unlikely(err)) { 303ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 304ffe455adSEugenia Emantayev (unsigned long long) mac); 305ffe455adSEugenia Emantayev table->entries[free] = 0; 306ffe455adSEugenia Emantayev goto out; 307ffe455adSEugenia Emantayev } 3086ce71acdSRony Efraim table->refs[free] = 1; 3095f61385dSMoni Shoua table->is_dup[free] = false; 310ffe455adSEugenia Emantayev ++table->total; 3115f61385dSMoni Shoua if (dup) { 3125f61385dSMoni Shoua dup_table->refs[free] = 0; 3135f61385dSMoni Shoua dup_table->is_dup[free] = true; 3145f61385dSMoni Shoua dup_table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); 3155f61385dSMoni Shoua 3165f61385dSMoni Shoua err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries); 3175f61385dSMoni Shoua if (unlikely(err)) { 3185f61385dSMoni Shoua mlx4_warn(dev, "Failed adding duplicate mac: 0x%llx\n", mac); 3195f61385dSMoni Shoua dup_table->is_dup[free] = false; 3205f61385dSMoni Shoua dup_table->entries[free] = 0; 3215f61385dSMoni Shoua goto out; 3225f61385dSMoni Shoua } 3235f61385dSMoni Shoua ++dup_table->total; 3245f61385dSMoni Shoua } 3255f61385dSMoni Shoua err = free; 326ffe455adSEugenia Emantayev out: 3275f61385dSMoni Shoua if (need_mf_bond) { 3285f61385dSMoni Shoua if (port == 2) { 329ffe455adSEugenia Emantayev mutex_unlock(&table->mutex); 3305f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 3315f61385dSMoni Shoua } else { 3325f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 3335f61385dSMoni Shoua mutex_unlock(&table->mutex); 3345f61385dSMoni Shoua } 3355f61385dSMoni Shoua } else { 3365f61385dSMoni Shoua mutex_unlock(&table->mutex); 3375f61385dSMoni Shoua } 338ffe455adSEugenia Emantayev return err; 339ffe455adSEugenia Emantayev } 340ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_register_mac); 341ffe455adSEugenia Emantayev 342ffe455adSEugenia Emantayev int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 343ffe455adSEugenia Emantayev { 344e7dbeba8SJack Morgenstein u64 out_param = 0; 345acddd5ddSJack Morgenstein int err = -EINVAL; 346ffe455adSEugenia Emantayev 347ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 348acddd5ddSJack Morgenstein if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 349acddd5ddSJack Morgenstein err = mlx4_cmd_imm(dev, mac, &out_param, 350acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_MAC, 351acddd5ddSJack Morgenstein RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 352acddd5ddSJack Morgenstein MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 353acddd5ddSJack Morgenstein } 354acddd5ddSJack Morgenstein if (err && err == -EINVAL && mlx4_is_slave(dev)) { 355acddd5ddSJack Morgenstein /* retry using old REG_MAC format */ 356ffe455adSEugenia Emantayev set_param_l(&out_param, port); 357ffe455adSEugenia Emantayev err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 358ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 359ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 360acddd5ddSJack Morgenstein if (!err) 361acddd5ddSJack Morgenstein dev->flags |= MLX4_FLAG_OLD_REG_MAC; 362acddd5ddSJack Morgenstein } 363ffe455adSEugenia Emantayev if (err) 364ffe455adSEugenia Emantayev return err; 365ffe455adSEugenia Emantayev 366ffe455adSEugenia Emantayev return get_param_l(&out_param); 367ffe455adSEugenia Emantayev } 368ffe455adSEugenia Emantayev return __mlx4_register_mac(dev, port, mac); 369ffe455adSEugenia Emantayev } 370ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(mlx4_register_mac); 371ffe455adSEugenia Emantayev 37216a10ffdSYan Burman int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port) 37316a10ffdSYan Burman { 37416a10ffdSYan Burman return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] + 37516a10ffdSYan Burman (port - 1) * (1 << dev->caps.log_num_macs); 37616a10ffdSYan Burman } 37716a10ffdSYan Burman EXPORT_SYMBOL_GPL(mlx4_get_base_qpn); 378ffe455adSEugenia Emantayev 379ffe455adSEugenia Emantayev void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 380ffe455adSEugenia Emantayev { 381143b3efbSEugenia Emantayev struct mlx4_port_info *info; 382143b3efbSEugenia Emantayev struct mlx4_mac_table *table; 383ffe455adSEugenia Emantayev int index; 3845f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 3855f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 3865f61385dSMoni Shoua struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table; 387ffe455adSEugenia Emantayev 388143b3efbSEugenia Emantayev if (port < 1 || port > dev->caps.num_ports) { 389143b3efbSEugenia Emantayev mlx4_warn(dev, "invalid port number (%d), aborting...\n", port); 390143b3efbSEugenia Emantayev return; 391143b3efbSEugenia Emantayev } 392143b3efbSEugenia Emantayev info = &mlx4_priv(dev)->port[port]; 393143b3efbSEugenia Emantayev table = &info->mac_table; 3945f61385dSMoni Shoua 3955f61385dSMoni Shoua if (dup) { 3965f61385dSMoni Shoua if (port == 1) { 3975a2cc190SJeff Kirsher mutex_lock(&table->mutex); 39803a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 3995f61385dSMoni Shoua } else { 4005f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 40103a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 4025f61385dSMoni Shoua } 4035f61385dSMoni Shoua } else { 4045f61385dSMoni Shoua mutex_lock(&table->mutex); 4055f61385dSMoni Shoua } 4065f61385dSMoni Shoua 4076ce71acdSRony Efraim index = find_index(dev, table, mac); 4085a2cc190SJeff Kirsher 4095a2cc190SJeff Kirsher if (validate_index(dev, table, index)) 4105a2cc190SJeff Kirsher goto out; 4115f61385dSMoni Shoua 4125f61385dSMoni Shoua if (--table->refs[index] || table->is_dup[index]) { 4131a91de28SJoe Perches mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n", 4141a91de28SJoe Perches index); 4155f61385dSMoni Shoua if (!table->refs[index]) 4165f61385dSMoni Shoua dup_table->is_dup[index] = false; 4176ce71acdSRony Efraim goto out; 4186ce71acdSRony Efraim } 4195a2cc190SJeff Kirsher 4205a2cc190SJeff Kirsher table->entries[index] = 0; 4215f61385dSMoni Shoua if (mlx4_set_port_mac_table(dev, port, table->entries)) 4225f61385dSMoni Shoua mlx4_warn(dev, "Fail to set mac in port %d during unregister\n", port); 4235a2cc190SJeff Kirsher --table->total; 4245f61385dSMoni Shoua 4255f61385dSMoni Shoua if (dup) { 4265f61385dSMoni Shoua dup_table->is_dup[index] = false; 4275f61385dSMoni Shoua if (dup_table->refs[index]) 4285f61385dSMoni Shoua goto out; 4295f61385dSMoni Shoua dup_table->entries[index] = 0; 4305f61385dSMoni Shoua if (mlx4_set_port_mac_table(dev, dup_port, dup_table->entries)) 4315f61385dSMoni Shoua mlx4_warn(dev, "Fail to set mac in duplicate port %d during unregister\n", dup_port); 4325f61385dSMoni Shoua 4335f61385dSMoni Shoua --table->total; 4345f61385dSMoni Shoua } 4355a2cc190SJeff Kirsher out: 4365f61385dSMoni Shoua if (dup) { 4375f61385dSMoni Shoua if (port == 2) { 4385a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 4395f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 4405f61385dSMoni Shoua } else { 4415f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 4425f61385dSMoni Shoua mutex_unlock(&table->mutex); 4435f61385dSMoni Shoua } 4445f61385dSMoni Shoua } else { 4455f61385dSMoni Shoua mutex_unlock(&table->mutex); 4465f61385dSMoni Shoua } 4475a2cc190SJeff Kirsher } 448ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_unregister_mac); 449ffe455adSEugenia Emantayev 450ffe455adSEugenia Emantayev void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 451ffe455adSEugenia Emantayev { 452e7dbeba8SJack Morgenstein u64 out_param = 0; 453ffe455adSEugenia Emantayev 454ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 455acddd5ddSJack Morgenstein if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 456acddd5ddSJack Morgenstein (void) mlx4_cmd_imm(dev, mac, &out_param, 457acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_MAC, 458acddd5ddSJack Morgenstein RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 459acddd5ddSJack Morgenstein MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 460acddd5ddSJack Morgenstein } else { 461acddd5ddSJack Morgenstein /* use old unregister mac format */ 462ffe455adSEugenia Emantayev set_param_l(&out_param, port); 463162344edSOr Gerlitz (void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 464ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 465ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 466acddd5ddSJack Morgenstein } 467ffe455adSEugenia Emantayev return; 468ffe455adSEugenia Emantayev } 469ffe455adSEugenia Emantayev __mlx4_unregister_mac(dev, port, mac); 470ffe455adSEugenia Emantayev return; 471ffe455adSEugenia Emantayev } 4725a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_mac); 4735a2cc190SJeff Kirsher 47416a10ffdSYan Burman int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac) 4755a2cc190SJeff Kirsher { 4765a2cc190SJeff Kirsher struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 4775a2cc190SJeff Kirsher struct mlx4_mac_table *table = &info->mac_table; 478ffe455adSEugenia Emantayev int index = qpn - info->base_qpn; 479ffe455adSEugenia Emantayev int err = 0; 4805f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 4815f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 4825f61385dSMoni Shoua struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table; 4835a2cc190SJeff Kirsher 484ffe455adSEugenia Emantayev /* CX1 doesn't support multi-functions */ 4855f61385dSMoni Shoua if (dup) { 4865f61385dSMoni Shoua if (port == 1) { 4875a2cc190SJeff Kirsher mutex_lock(&table->mutex); 48803a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 4895f61385dSMoni Shoua } else { 4905f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 49103a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 4925f61385dSMoni Shoua } 4935f61385dSMoni Shoua } else { 4945f61385dSMoni Shoua mutex_lock(&table->mutex); 4955f61385dSMoni Shoua } 4965a2cc190SJeff Kirsher 4975a2cc190SJeff Kirsher err = validate_index(dev, table, index); 4985a2cc190SJeff Kirsher if (err) 4995a2cc190SJeff Kirsher goto out; 5005a2cc190SJeff Kirsher 5015a2cc190SJeff Kirsher table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); 5025a2cc190SJeff Kirsher 5035a2cc190SJeff Kirsher err = mlx4_set_port_mac_table(dev, port, table->entries); 5045a2cc190SJeff Kirsher if (unlikely(err)) { 505ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 506ffe455adSEugenia Emantayev (unsigned long long) new_mac); 5075a2cc190SJeff Kirsher table->entries[index] = 0; 5085f61385dSMoni Shoua } else { 5095f61385dSMoni Shoua if (dup) { 5105f61385dSMoni Shoua dup_table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); 5115f61385dSMoni Shoua 5125f61385dSMoni Shoua err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries); 5135f61385dSMoni Shoua if (unlikely(err)) { 5145f61385dSMoni Shoua mlx4_err(dev, "Failed adding duplicate MAC: 0x%llx\n", 5155f61385dSMoni Shoua (unsigned long long)new_mac); 5165f61385dSMoni Shoua dup_table->entries[index] = 0; 5175f61385dSMoni Shoua } 5185f61385dSMoni Shoua } 5195a2cc190SJeff Kirsher } 5205a2cc190SJeff Kirsher out: 5215f61385dSMoni Shoua if (dup) { 5225f61385dSMoni Shoua if (port == 2) { 5235a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 5245f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 5255f61385dSMoni Shoua } else { 5265f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 5275f61385dSMoni Shoua mutex_unlock(&table->mutex); 5285f61385dSMoni Shoua } 5295f61385dSMoni Shoua } else { 5305f61385dSMoni Shoua mutex_unlock(&table->mutex); 5315f61385dSMoni Shoua } 5325a2cc190SJeff Kirsher return err; 5335a2cc190SJeff Kirsher } 53416a10ffdSYan Burman EXPORT_SYMBOL_GPL(__mlx4_replace_mac); 535ffe455adSEugenia Emantayev 5365a2cc190SJeff Kirsher static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, 5375a2cc190SJeff Kirsher __be32 *entries) 5385a2cc190SJeff Kirsher { 5395a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 5405a2cc190SJeff Kirsher u32 in_mod; 5415a2cc190SJeff Kirsher int err; 5425a2cc190SJeff Kirsher 5435a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 5445a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 5455a2cc190SJeff Kirsher return PTR_ERR(mailbox); 5465a2cc190SJeff Kirsher 5475a2cc190SJeff Kirsher memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); 5485a2cc190SJeff Kirsher in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; 549a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 550a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 551a130b590SIdo Shamay MLX4_CMD_NATIVE); 5525a2cc190SJeff Kirsher 5535a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 5545a2cc190SJeff Kirsher 5555a2cc190SJeff Kirsher return err; 5565a2cc190SJeff Kirsher } 5575a2cc190SJeff Kirsher 5585a2cc190SJeff Kirsher int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx) 5595a2cc190SJeff Kirsher { 5605a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 5615a2cc190SJeff Kirsher int i; 5625a2cc190SJeff Kirsher 5635a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) { 5645a2cc190SJeff Kirsher if (table->refs[i] && 5655a2cc190SJeff Kirsher (vid == (MLX4_VLAN_MASK & 5665a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 5675a2cc190SJeff Kirsher /* VLAN already registered, increase reference count */ 5685a2cc190SJeff Kirsher *idx = i; 5695a2cc190SJeff Kirsher return 0; 5705a2cc190SJeff Kirsher } 5715a2cc190SJeff Kirsher } 5725a2cc190SJeff Kirsher 5735a2cc190SJeff Kirsher return -ENOENT; 5745a2cc190SJeff Kirsher } 5755a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan); 5765a2cc190SJeff Kirsher 5773f7fb021SRony Efraim int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, 578ffe455adSEugenia Emantayev int *index) 5795a2cc190SJeff Kirsher { 5805a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 5815a2cc190SJeff Kirsher int i, err = 0; 5825a2cc190SJeff Kirsher int free = -1; 5835f61385dSMoni Shoua int free_for_dup = -1; 5845f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 5855f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 5865f61385dSMoni Shoua struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table; 5875f61385dSMoni Shoua bool need_mf_bond = mlx4_need_mf_bond(dev); 5885f61385dSMoni Shoua bool can_mf_bond = true; 5895a2cc190SJeff Kirsher 5905f61385dSMoni Shoua mlx4_dbg(dev, "Registering VLAN: %d for port %d %s duplicate\n", 5915f61385dSMoni Shoua vlan, port, 5925f61385dSMoni Shoua dup ? "with" : "without"); 5935f61385dSMoni Shoua 5945f61385dSMoni Shoua if (need_mf_bond) { 5955f61385dSMoni Shoua if (port == 1) { 5965a2cc190SJeff Kirsher mutex_lock(&table->mutex); 59703a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 5985f61385dSMoni Shoua } else { 5995f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 60003a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 6015f61385dSMoni Shoua } 6025f61385dSMoni Shoua } else { 6035f61385dSMoni Shoua mutex_lock(&table->mutex); 6045f61385dSMoni Shoua } 605e72ebf5aSYevgeny Petrilin 606e72ebf5aSYevgeny Petrilin if (table->total == table->max) { 607e72ebf5aSYevgeny Petrilin /* No free vlan entries */ 608e72ebf5aSYevgeny Petrilin err = -ENOSPC; 609e72ebf5aSYevgeny Petrilin goto out; 610e72ebf5aSYevgeny Petrilin } 611e72ebf5aSYevgeny Petrilin 6125f61385dSMoni Shoua if (need_mf_bond) { 6135f61385dSMoni Shoua int index_at_port = -1; 6145f61385dSMoni Shoua int index_at_dup_port = -1; 6155f61385dSMoni Shoua 6165a2cc190SJeff Kirsher for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 6175f61385dSMoni Shoua if ((vlan == (MLX4_VLAN_MASK & be32_to_cpu(table->entries[i])))) 6185f61385dSMoni Shoua index_at_port = i; 6195f61385dSMoni Shoua if ((vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i])))) 6205f61385dSMoni Shoua index_at_dup_port = i; 6215f61385dSMoni Shoua } 6225f61385dSMoni Shoua /* check that same vlan is not in the tables at different indices */ 6235f61385dSMoni Shoua if ((index_at_port != index_at_dup_port) && 6245f61385dSMoni Shoua (index_at_port >= 0) && 6255f61385dSMoni Shoua (index_at_dup_port >= 0)) 6265f61385dSMoni Shoua can_mf_bond = false; 6275f61385dSMoni Shoua 6285f61385dSMoni Shoua /* If the vlan is already in the primary table, the slot must be 6295f61385dSMoni Shoua * available in the duplicate table as well. 6305f61385dSMoni Shoua */ 6315f61385dSMoni Shoua if (index_at_port >= 0 && index_at_dup_port < 0 && 6325f61385dSMoni Shoua dup_table->refs[index_at_port]) { 6335f61385dSMoni Shoua can_mf_bond = false; 6345f61385dSMoni Shoua } 6355f61385dSMoni Shoua /* If the vlan is already in the duplicate table, check that the 6365f61385dSMoni Shoua * corresponding index is not occupied in the primary table, or 6375f61385dSMoni Shoua * the primary table already contains the vlan at the same index. 6385f61385dSMoni Shoua * Otherwise, you cannot bond (primary contains a different vlan 6395f61385dSMoni Shoua * at that index). 6405f61385dSMoni Shoua */ 6415f61385dSMoni Shoua if (index_at_dup_port >= 0) { 6425f61385dSMoni Shoua if (!table->refs[index_at_dup_port] || 6435f61385dSMoni Shoua (vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[index_at_dup_port])))) 6445f61385dSMoni Shoua free_for_dup = index_at_dup_port; 6455f61385dSMoni Shoua else 6465f61385dSMoni Shoua can_mf_bond = false; 6475f61385dSMoni Shoua } 6485a2cc190SJeff Kirsher } 6495a2cc190SJeff Kirsher 6505f61385dSMoni Shoua for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 6515f61385dSMoni Shoua if (!table->refs[i]) { 6525f61385dSMoni Shoua if (free < 0) 6535f61385dSMoni Shoua free = i; 6545f61385dSMoni Shoua if (free_for_dup < 0 && need_mf_bond && can_mf_bond) { 6555f61385dSMoni Shoua if (!dup_table->refs[i]) 6565f61385dSMoni Shoua free_for_dup = i; 6575f61385dSMoni Shoua } 6585f61385dSMoni Shoua } 6595f61385dSMoni Shoua 6605f61385dSMoni Shoua if ((table->refs[i] || table->is_dup[i]) && 6615a2cc190SJeff Kirsher (vlan == (MLX4_VLAN_MASK & 6625a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 6635a2cc190SJeff Kirsher /* Vlan already registered, increase references count */ 6645f61385dSMoni Shoua mlx4_dbg(dev, "vlan %u is already registered.\n", vlan); 6655a2cc190SJeff Kirsher *index = i; 6665a2cc190SJeff Kirsher ++table->refs[i]; 6675f61385dSMoni Shoua if (dup) { 6685f61385dSMoni Shoua u16 dup_vlan = MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i]); 6695f61385dSMoni Shoua 6705f61385dSMoni Shoua if (dup_vlan != vlan || !dup_table->is_dup[i]) { 6715f61385dSMoni Shoua mlx4_warn(dev, "register vlan: expected duplicate vlan %u on port %d index %d\n", 6725f61385dSMoni Shoua vlan, dup_port, i); 6735f61385dSMoni Shoua } 6745f61385dSMoni Shoua } 6755a2cc190SJeff Kirsher goto out; 6765a2cc190SJeff Kirsher } 6775a2cc190SJeff Kirsher } 6785a2cc190SJeff Kirsher 6795f61385dSMoni Shoua if (need_mf_bond && (free_for_dup < 0)) { 6805f61385dSMoni Shoua if (dup) { 6815f61385dSMoni Shoua mlx4_warn(dev, "Fail to allocate duplicate VLAN table entry\n"); 6825f61385dSMoni Shoua mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n"); 6835f61385dSMoni Shoua dup = false; 6845f61385dSMoni Shoua } 6855f61385dSMoni Shoua can_mf_bond = false; 6865f61385dSMoni Shoua } 6875f61385dSMoni Shoua 6885f61385dSMoni Shoua if (need_mf_bond && can_mf_bond) 6895f61385dSMoni Shoua free = free_for_dup; 6905f61385dSMoni Shoua 6915a2cc190SJeff Kirsher if (free < 0) { 6925a2cc190SJeff Kirsher err = -ENOMEM; 6935a2cc190SJeff Kirsher goto out; 6945a2cc190SJeff Kirsher } 6955a2cc190SJeff Kirsher 696ffe455adSEugenia Emantayev /* Register new VLAN */ 6975a2cc190SJeff Kirsher table->refs[free] = 1; 6985f61385dSMoni Shoua table->is_dup[free] = false; 6995a2cc190SJeff Kirsher table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 7005a2cc190SJeff Kirsher 7015a2cc190SJeff Kirsher err = mlx4_set_port_vlan_table(dev, port, table->entries); 7025a2cc190SJeff Kirsher if (unlikely(err)) { 7035a2cc190SJeff Kirsher mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); 7045a2cc190SJeff Kirsher table->refs[free] = 0; 7055a2cc190SJeff Kirsher table->entries[free] = 0; 7065a2cc190SJeff Kirsher goto out; 7075a2cc190SJeff Kirsher } 7085f61385dSMoni Shoua ++table->total; 7095f61385dSMoni Shoua if (dup) { 7105f61385dSMoni Shoua dup_table->refs[free] = 0; 7115f61385dSMoni Shoua dup_table->is_dup[free] = true; 7125f61385dSMoni Shoua dup_table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 7135f61385dSMoni Shoua 7145f61385dSMoni Shoua err = mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries); 7155f61385dSMoni Shoua if (unlikely(err)) { 7165f61385dSMoni Shoua mlx4_warn(dev, "Failed adding duplicate vlan: %u\n", vlan); 7175f61385dSMoni Shoua dup_table->is_dup[free] = false; 7185f61385dSMoni Shoua dup_table->entries[free] = 0; 7195f61385dSMoni Shoua goto out; 7205f61385dSMoni Shoua } 7215f61385dSMoni Shoua ++dup_table->total; 7225f61385dSMoni Shoua } 7235a2cc190SJeff Kirsher 7245a2cc190SJeff Kirsher *index = free; 7255a2cc190SJeff Kirsher out: 7265f61385dSMoni Shoua if (need_mf_bond) { 7275f61385dSMoni Shoua if (port == 2) { 7285a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 7295f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 7305f61385dSMoni Shoua } else { 7315f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 7325f61385dSMoni Shoua mutex_unlock(&table->mutex); 7335f61385dSMoni Shoua } 7345f61385dSMoni Shoua } else { 7355f61385dSMoni Shoua mutex_unlock(&table->mutex); 7365f61385dSMoni Shoua } 7375a2cc190SJeff Kirsher return err; 7385a2cc190SJeff Kirsher } 739ffe455adSEugenia Emantayev 740ffe455adSEugenia Emantayev int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) 741ffe455adSEugenia Emantayev { 742e7dbeba8SJack Morgenstein u64 out_param = 0; 743ffe455adSEugenia Emantayev int err; 744ffe455adSEugenia Emantayev 745162226a1SJack Morgenstein if (vlan > 4095) 746162226a1SJack Morgenstein return -EINVAL; 747162226a1SJack Morgenstein 748ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 749acddd5ddSJack Morgenstein err = mlx4_cmd_imm(dev, vlan, &out_param, 750acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN, 751ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 752ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 753ffe455adSEugenia Emantayev if (!err) 754ffe455adSEugenia Emantayev *index = get_param_l(&out_param); 755ffe455adSEugenia Emantayev 756ffe455adSEugenia Emantayev return err; 757ffe455adSEugenia Emantayev } 758ffe455adSEugenia Emantayev return __mlx4_register_vlan(dev, port, vlan, index); 759ffe455adSEugenia Emantayev } 7605a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_register_vlan); 7615a2cc190SJeff Kirsher 7622009d005SJack Morgenstein void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 7635a2cc190SJeff Kirsher { 7645a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 7652009d005SJack Morgenstein int index; 7665f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 7675f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 7685f61385dSMoni Shoua struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table; 7692009d005SJack Morgenstein 7705f61385dSMoni Shoua if (dup) { 7715f61385dSMoni Shoua if (port == 1) { 7722009d005SJack Morgenstein mutex_lock(&table->mutex); 77303a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 7745f61385dSMoni Shoua } else { 7755f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 77603a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 7775f61385dSMoni Shoua } 7785f61385dSMoni Shoua } else { 7795f61385dSMoni Shoua mutex_lock(&table->mutex); 7805f61385dSMoni Shoua } 7815f61385dSMoni Shoua 7822009d005SJack Morgenstein if (mlx4_find_cached_vlan(dev, port, vlan, &index)) { 7832009d005SJack Morgenstein mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan); 7842009d005SJack Morgenstein goto out; 7852009d005SJack Morgenstein } 7865a2cc190SJeff Kirsher 7875a2cc190SJeff Kirsher if (index < MLX4_VLAN_REGULAR) { 7885a2cc190SJeff Kirsher mlx4_warn(dev, "Trying to free special vlan index %d\n", index); 7895a2cc190SJeff Kirsher goto out; 7905a2cc190SJeff Kirsher } 7912009d005SJack Morgenstein 7925f61385dSMoni Shoua if (--table->refs[index] || table->is_dup[index]) { 7931a91de28SJoe Perches mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n", 7941a91de28SJoe Perches table->refs[index], index); 7955f61385dSMoni Shoua if (!table->refs[index]) 7965f61385dSMoni Shoua dup_table->is_dup[index] = false; 7975a2cc190SJeff Kirsher goto out; 7985a2cc190SJeff Kirsher } 7995a2cc190SJeff Kirsher table->entries[index] = 0; 8005f61385dSMoni Shoua if (mlx4_set_port_vlan_table(dev, port, table->entries)) 8015f61385dSMoni Shoua mlx4_warn(dev, "Fail to set vlan in port %d during unregister\n", port); 8025a2cc190SJeff Kirsher --table->total; 8035f61385dSMoni Shoua if (dup) { 8045f61385dSMoni Shoua dup_table->is_dup[index] = false; 8055f61385dSMoni Shoua if (dup_table->refs[index]) 8065f61385dSMoni Shoua goto out; 8075f61385dSMoni Shoua dup_table->entries[index] = 0; 8085f61385dSMoni Shoua if (mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries)) 8095f61385dSMoni Shoua mlx4_warn(dev, "Fail to set vlan in duplicate port %d during unregister\n", dup_port); 8105f61385dSMoni Shoua --dup_table->total; 8115f61385dSMoni Shoua } 8125a2cc190SJeff Kirsher out: 8135f61385dSMoni Shoua if (dup) { 8145f61385dSMoni Shoua if (port == 2) { 8155a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 8165f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 8175f61385dSMoni Shoua } else { 8185f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 8195f61385dSMoni Shoua mutex_unlock(&table->mutex); 8205f61385dSMoni Shoua } 8215f61385dSMoni Shoua } else { 8225f61385dSMoni Shoua mutex_unlock(&table->mutex); 8235f61385dSMoni Shoua } 8245a2cc190SJeff Kirsher } 825ffe455adSEugenia Emantayev 8262009d005SJack Morgenstein void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 827ffe455adSEugenia Emantayev { 828162226a1SJack Morgenstein u64 out_param = 0; 829ffe455adSEugenia Emantayev 830ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 8312009d005SJack Morgenstein (void) mlx4_cmd_imm(dev, vlan, &out_param, 832acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN, 833162226a1SJack Morgenstein RES_OP_RESERVE_AND_MAP, 834ffe455adSEugenia Emantayev MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, 835ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 836ffe455adSEugenia Emantayev return; 837ffe455adSEugenia Emantayev } 8382009d005SJack Morgenstein __mlx4_unregister_vlan(dev, port, vlan); 839ffe455adSEugenia Emantayev } 8405a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_vlan); 8415a2cc190SJeff Kirsher 8425f61385dSMoni Shoua int mlx4_bond_mac_table(struct mlx4_dev *dev) 8435f61385dSMoni Shoua { 8445f61385dSMoni Shoua struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table; 8455f61385dSMoni Shoua struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table; 8465f61385dSMoni Shoua int ret = 0; 8475f61385dSMoni Shoua int i; 8485f61385dSMoni Shoua bool update1 = false; 8495f61385dSMoni Shoua bool update2 = false; 8505f61385dSMoni Shoua 8515f61385dSMoni Shoua mutex_lock(&t1->mutex); 8525f61385dSMoni Shoua mutex_lock(&t2->mutex); 8535f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 8545f61385dSMoni Shoua if ((t1->entries[i] != t2->entries[i]) && 8555f61385dSMoni Shoua t1->entries[i] && t2->entries[i]) { 8565f61385dSMoni Shoua mlx4_warn(dev, "can't duplicate entry %d in mac table\n", i); 8575f61385dSMoni Shoua ret = -EINVAL; 8585f61385dSMoni Shoua goto unlock; 8595f61385dSMoni Shoua } 8605f61385dSMoni Shoua } 8615f61385dSMoni Shoua 8625f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 8635f61385dSMoni Shoua if (t1->entries[i] && !t2->entries[i]) { 8645f61385dSMoni Shoua t2->entries[i] = t1->entries[i]; 8655f61385dSMoni Shoua t2->is_dup[i] = true; 8665f61385dSMoni Shoua update2 = true; 8675f61385dSMoni Shoua } else if (!t1->entries[i] && t2->entries[i]) { 8685f61385dSMoni Shoua t1->entries[i] = t2->entries[i]; 8695f61385dSMoni Shoua t1->is_dup[i] = true; 8705f61385dSMoni Shoua update1 = true; 8715f61385dSMoni Shoua } else if (t1->entries[i] && t2->entries[i]) { 8725f61385dSMoni Shoua t1->is_dup[i] = true; 8735f61385dSMoni Shoua t2->is_dup[i] = true; 8745f61385dSMoni Shoua } 8755f61385dSMoni Shoua } 8765f61385dSMoni Shoua 8775f61385dSMoni Shoua if (update1) { 8785f61385dSMoni Shoua ret = mlx4_set_port_mac_table(dev, 1, t1->entries); 8795f61385dSMoni Shoua if (ret) 8805f61385dSMoni Shoua mlx4_warn(dev, "failed to set MAC table for port 1 (%d)\n", ret); 8815f61385dSMoni Shoua } 8825f61385dSMoni Shoua if (!ret && update2) { 8835f61385dSMoni Shoua ret = mlx4_set_port_mac_table(dev, 2, t2->entries); 8845f61385dSMoni Shoua if (ret) 8855f61385dSMoni Shoua mlx4_warn(dev, "failed to set MAC table for port 2 (%d)\n", ret); 8865f61385dSMoni Shoua } 8875f61385dSMoni Shoua 8885f61385dSMoni Shoua if (ret) 8895f61385dSMoni Shoua mlx4_warn(dev, "failed to create mirror MAC tables\n"); 8905f61385dSMoni Shoua unlock: 8915f61385dSMoni Shoua mutex_unlock(&t2->mutex); 8925f61385dSMoni Shoua mutex_unlock(&t1->mutex); 8935f61385dSMoni Shoua return ret; 8945f61385dSMoni Shoua } 8955f61385dSMoni Shoua 8965f61385dSMoni Shoua int mlx4_unbond_mac_table(struct mlx4_dev *dev) 8975f61385dSMoni Shoua { 8985f61385dSMoni Shoua struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table; 8995f61385dSMoni Shoua struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table; 9005f61385dSMoni Shoua int ret = 0; 9015f61385dSMoni Shoua int ret1; 9025f61385dSMoni Shoua int i; 9035f61385dSMoni Shoua bool update1 = false; 9045f61385dSMoni Shoua bool update2 = false; 9055f61385dSMoni Shoua 9065f61385dSMoni Shoua mutex_lock(&t1->mutex); 9075f61385dSMoni Shoua mutex_lock(&t2->mutex); 9085f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 9095f61385dSMoni Shoua if (t1->entries[i] != t2->entries[i]) { 9105f61385dSMoni Shoua mlx4_warn(dev, "mac table is in an unexpected state when trying to unbond\n"); 9115f61385dSMoni Shoua ret = -EINVAL; 9125f61385dSMoni Shoua goto unlock; 9135f61385dSMoni Shoua } 9145f61385dSMoni Shoua } 9155f61385dSMoni Shoua 9165f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 9175f61385dSMoni Shoua if (!t1->entries[i]) 9185f61385dSMoni Shoua continue; 9195f61385dSMoni Shoua t1->is_dup[i] = false; 9205f61385dSMoni Shoua if (!t1->refs[i]) { 9215f61385dSMoni Shoua t1->entries[i] = 0; 9225f61385dSMoni Shoua update1 = true; 9235f61385dSMoni Shoua } 9245f61385dSMoni Shoua t2->is_dup[i] = false; 9255f61385dSMoni Shoua if (!t2->refs[i]) { 9265f61385dSMoni Shoua t2->entries[i] = 0; 9275f61385dSMoni Shoua update2 = true; 9285f61385dSMoni Shoua } 9295f61385dSMoni Shoua } 9305f61385dSMoni Shoua 9315f61385dSMoni Shoua if (update1) { 9325f61385dSMoni Shoua ret = mlx4_set_port_mac_table(dev, 1, t1->entries); 9335f61385dSMoni Shoua if (ret) 9345f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror MAC tables for port 1(%d)\n", ret); 9355f61385dSMoni Shoua } 9365f61385dSMoni Shoua if (update2) { 9375f61385dSMoni Shoua ret1 = mlx4_set_port_mac_table(dev, 2, t2->entries); 9385f61385dSMoni Shoua if (ret1) { 9395f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror MAC tables for port 2(%d)\n", ret1); 9405f61385dSMoni Shoua ret = ret1; 9415f61385dSMoni Shoua } 9425f61385dSMoni Shoua } 9435f61385dSMoni Shoua unlock: 9445f61385dSMoni Shoua mutex_unlock(&t2->mutex); 9455f61385dSMoni Shoua mutex_unlock(&t1->mutex); 9465f61385dSMoni Shoua return ret; 9475f61385dSMoni Shoua } 9485f61385dSMoni Shoua 9495f61385dSMoni Shoua int mlx4_bond_vlan_table(struct mlx4_dev *dev) 9505f61385dSMoni Shoua { 9515f61385dSMoni Shoua struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table; 9525f61385dSMoni Shoua struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table; 9535f61385dSMoni Shoua int ret = 0; 9545f61385dSMoni Shoua int i; 9555f61385dSMoni Shoua bool update1 = false; 9565f61385dSMoni Shoua bool update2 = false; 9575f61385dSMoni Shoua 9585f61385dSMoni Shoua mutex_lock(&t1->mutex); 9595f61385dSMoni Shoua mutex_lock(&t2->mutex); 9605f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 9615f61385dSMoni Shoua if ((t1->entries[i] != t2->entries[i]) && 9625f61385dSMoni Shoua t1->entries[i] && t2->entries[i]) { 9635f61385dSMoni Shoua mlx4_warn(dev, "can't duplicate entry %d in vlan table\n", i); 9645f61385dSMoni Shoua ret = -EINVAL; 9655f61385dSMoni Shoua goto unlock; 9665f61385dSMoni Shoua } 9675f61385dSMoni Shoua } 9685f61385dSMoni Shoua 9695f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 9705f61385dSMoni Shoua if (t1->entries[i] && !t2->entries[i]) { 9715f61385dSMoni Shoua t2->entries[i] = t1->entries[i]; 9725f61385dSMoni Shoua t2->is_dup[i] = true; 9735f61385dSMoni Shoua update2 = true; 9745f61385dSMoni Shoua } else if (!t1->entries[i] && t2->entries[i]) { 9755f61385dSMoni Shoua t1->entries[i] = t2->entries[i]; 9765f61385dSMoni Shoua t1->is_dup[i] = true; 9775f61385dSMoni Shoua update1 = true; 9785f61385dSMoni Shoua } else if (t1->entries[i] && t2->entries[i]) { 9795f61385dSMoni Shoua t1->is_dup[i] = true; 9805f61385dSMoni Shoua t2->is_dup[i] = true; 9815f61385dSMoni Shoua } 9825f61385dSMoni Shoua } 9835f61385dSMoni Shoua 9845f61385dSMoni Shoua if (update1) { 9855f61385dSMoni Shoua ret = mlx4_set_port_vlan_table(dev, 1, t1->entries); 9865f61385dSMoni Shoua if (ret) 9875f61385dSMoni Shoua mlx4_warn(dev, "failed to set VLAN table for port 1 (%d)\n", ret); 9885f61385dSMoni Shoua } 9895f61385dSMoni Shoua if (!ret && update2) { 9905f61385dSMoni Shoua ret = mlx4_set_port_vlan_table(dev, 2, t2->entries); 9915f61385dSMoni Shoua if (ret) 9925f61385dSMoni Shoua mlx4_warn(dev, "failed to set VLAN table for port 2 (%d)\n", ret); 9935f61385dSMoni Shoua } 9945f61385dSMoni Shoua 9955f61385dSMoni Shoua if (ret) 9965f61385dSMoni Shoua mlx4_warn(dev, "failed to create mirror VLAN tables\n"); 9975f61385dSMoni Shoua unlock: 9985f61385dSMoni Shoua mutex_unlock(&t2->mutex); 9995f61385dSMoni Shoua mutex_unlock(&t1->mutex); 10005f61385dSMoni Shoua return ret; 10015f61385dSMoni Shoua } 10025f61385dSMoni Shoua 10035f61385dSMoni Shoua int mlx4_unbond_vlan_table(struct mlx4_dev *dev) 10045f61385dSMoni Shoua { 10055f61385dSMoni Shoua struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table; 10065f61385dSMoni Shoua struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table; 10075f61385dSMoni Shoua int ret = 0; 10085f61385dSMoni Shoua int ret1; 10095f61385dSMoni Shoua int i; 10105f61385dSMoni Shoua bool update1 = false; 10115f61385dSMoni Shoua bool update2 = false; 10125f61385dSMoni Shoua 10135f61385dSMoni Shoua mutex_lock(&t1->mutex); 10145f61385dSMoni Shoua mutex_lock(&t2->mutex); 10155f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 10165f61385dSMoni Shoua if (t1->entries[i] != t2->entries[i]) { 10175f61385dSMoni Shoua mlx4_warn(dev, "vlan table is in an unexpected state when trying to unbond\n"); 10185f61385dSMoni Shoua ret = -EINVAL; 10195f61385dSMoni Shoua goto unlock; 10205f61385dSMoni Shoua } 10215f61385dSMoni Shoua } 10225f61385dSMoni Shoua 10235f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 10245f61385dSMoni Shoua if (!t1->entries[i]) 10255f61385dSMoni Shoua continue; 10265f61385dSMoni Shoua t1->is_dup[i] = false; 10275f61385dSMoni Shoua if (!t1->refs[i]) { 10285f61385dSMoni Shoua t1->entries[i] = 0; 10295f61385dSMoni Shoua update1 = true; 10305f61385dSMoni Shoua } 10315f61385dSMoni Shoua t2->is_dup[i] = false; 10325f61385dSMoni Shoua if (!t2->refs[i]) { 10335f61385dSMoni Shoua t2->entries[i] = 0; 10345f61385dSMoni Shoua update2 = true; 10355f61385dSMoni Shoua } 10365f61385dSMoni Shoua } 10375f61385dSMoni Shoua 10385f61385dSMoni Shoua if (update1) { 10395f61385dSMoni Shoua ret = mlx4_set_port_vlan_table(dev, 1, t1->entries); 10405f61385dSMoni Shoua if (ret) 10415f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror VLAN tables for port 1(%d)\n", ret); 10425f61385dSMoni Shoua } 10435f61385dSMoni Shoua if (update2) { 10445f61385dSMoni Shoua ret1 = mlx4_set_port_vlan_table(dev, 2, t2->entries); 10455f61385dSMoni Shoua if (ret1) { 10465f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror VLAN tables for port 2(%d)\n", ret1); 10475f61385dSMoni Shoua ret = ret1; 10485f61385dSMoni Shoua } 10495f61385dSMoni Shoua } 10505f61385dSMoni Shoua unlock: 10515f61385dSMoni Shoua mutex_unlock(&t2->mutex); 10525f61385dSMoni Shoua mutex_unlock(&t1->mutex); 10535f61385dSMoni Shoua return ret; 10545f61385dSMoni Shoua } 10555f61385dSMoni Shoua 10565a2cc190SJeff Kirsher int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) 10575a2cc190SJeff Kirsher { 10585a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *inmailbox, *outmailbox; 10595a2cc190SJeff Kirsher u8 *inbuf, *outbuf; 10605a2cc190SJeff Kirsher int err; 10615a2cc190SJeff Kirsher 10625a2cc190SJeff Kirsher inmailbox = mlx4_alloc_cmd_mailbox(dev); 10635a2cc190SJeff Kirsher if (IS_ERR(inmailbox)) 10645a2cc190SJeff Kirsher return PTR_ERR(inmailbox); 10655a2cc190SJeff Kirsher 10665a2cc190SJeff Kirsher outmailbox = mlx4_alloc_cmd_mailbox(dev); 10675a2cc190SJeff Kirsher if (IS_ERR(outmailbox)) { 10685a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 10695a2cc190SJeff Kirsher return PTR_ERR(outmailbox); 10705a2cc190SJeff Kirsher } 10715a2cc190SJeff Kirsher 10725a2cc190SJeff Kirsher inbuf = inmailbox->buf; 10735a2cc190SJeff Kirsher outbuf = outmailbox->buf; 10745a2cc190SJeff Kirsher inbuf[0] = 1; 10755a2cc190SJeff Kirsher inbuf[1] = 1; 10765a2cc190SJeff Kirsher inbuf[2] = 1; 10775a2cc190SJeff Kirsher inbuf[3] = 1; 10785a2cc190SJeff Kirsher *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015); 10795a2cc190SJeff Kirsher *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); 10805a2cc190SJeff Kirsher 10815a2cc190SJeff Kirsher err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, 1082f9baff50SJack Morgenstein MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 1083f9baff50SJack Morgenstein MLX4_CMD_NATIVE); 10845a2cc190SJeff Kirsher if (!err) 10855a2cc190SJeff Kirsher *caps = *(__be32 *) (outbuf + 84); 10865a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 10875a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, outmailbox); 10885a2cc190SJeff Kirsher return err; 10895a2cc190SJeff Kirsher } 10909cd59352SJack Morgenstein static struct mlx4_roce_gid_entry zgid_entry; 10915a2cc190SJeff Kirsher 1092449fc488SMatan Barak int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port) 1093b6ffaeffSJack Morgenstein { 1094449fc488SMatan Barak int vfs; 1095449fc488SMatan Barak int slave_gid = slave; 1096449fc488SMatan Barak unsigned i; 1097449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 1098449fc488SMatan Barak struct mlx4_active_ports actv_ports; 1099449fc488SMatan Barak unsigned max_port_p_one; 1100449fc488SMatan Barak 1101b6ffaeffSJack Morgenstein if (slave == 0) 1102b6ffaeffSJack Morgenstein return MLX4_ROCE_PF_GIDS; 1103449fc488SMatan Barak 1104449fc488SMatan Barak /* Slave is a VF */ 1105449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1106449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave); 1107449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 1108449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 1109449fc488SMatan Barak 1110449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 1111449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 1112449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 1113449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 1114449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1115449fc488SMatan Barak if (i == port) 1116449fc488SMatan Barak continue; 1117449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 1118449fc488SMatan Barak dev, &exclusive_ports); 1119449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 1120872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1121449fc488SMatan Barak } 1122872bf2fbSYishai Hadas vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; 1123449fc488SMatan Barak if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs)) 1124449fc488SMatan Barak return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1; 1125449fc488SMatan Barak return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs; 1126b6ffaeffSJack Morgenstein } 1127b6ffaeffSJack Morgenstein 1128449fc488SMatan Barak int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port) 1129b6ffaeffSJack Morgenstein { 1130b6ffaeffSJack Morgenstein int gids; 1131449fc488SMatan Barak unsigned i; 1132449fc488SMatan Barak int slave_gid = slave; 1133b6ffaeffSJack Morgenstein int vfs; 1134b6ffaeffSJack Morgenstein 1135449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 1136449fc488SMatan Barak struct mlx4_active_ports actv_ports; 1137449fc488SMatan Barak unsigned max_port_p_one; 1138b6ffaeffSJack Morgenstein 1139b6ffaeffSJack Morgenstein if (slave == 0) 1140b6ffaeffSJack Morgenstein return 0; 1141b6ffaeffSJack Morgenstein 1142449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1143449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave); 1144449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 1145449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 1146449fc488SMatan Barak 1147449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 1148449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 1149449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 1150449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 1151449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1152449fc488SMatan Barak if (i == port) 1153449fc488SMatan Barak continue; 1154449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 1155449fc488SMatan Barak dev, &exclusive_ports); 1156449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 1157872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1158b6ffaeffSJack Morgenstein } 1159449fc488SMatan Barak gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 1160872bf2fbSYishai Hadas vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; 1161449fc488SMatan Barak if (slave_gid <= gids % vfs) 1162449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1); 1163449fc488SMatan Barak 1164449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + (gids % vfs) + 1165449fc488SMatan Barak ((gids / vfs) * (slave_gid - 1)); 1166449fc488SMatan Barak } 1167449fc488SMatan Barak EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix); 1168b6ffaeffSJack Morgenstein 1169111c6094SJack Morgenstein static int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave, 1170111c6094SJack Morgenstein int port, struct mlx4_cmd_mailbox *mailbox) 1171111c6094SJack Morgenstein { 1172111c6094SJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_mbox; 1173111c6094SJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 1174111c6094SJack Morgenstein int num_gids, base, offset; 1175111c6094SJack Morgenstein int i, err; 1176111c6094SJack Morgenstein 1177111c6094SJack Morgenstein num_gids = mlx4_get_slave_num_gids(dev, slave, port); 1178111c6094SJack Morgenstein base = mlx4_get_base_gid_ix(dev, slave, port); 1179111c6094SJack Morgenstein 1180111c6094SJack Morgenstein memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE); 1181111c6094SJack Morgenstein 1182111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex)); 1183111c6094SJack Morgenstein /* Zero-out gids belonging to that slave in the port GID table */ 1184111c6094SJack Morgenstein for (i = 0, offset = base; i < num_gids; offset++, i++) 1185111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 1186111c6094SJack Morgenstein zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE); 1187111c6094SJack Morgenstein 1188111c6094SJack Morgenstein /* Now, copy roce port gids table to mailbox for passing to FW */ 1189111c6094SJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf; 1190111c6094SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 1191111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw, 1192111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw, 1193111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 1194111c6094SJack Morgenstein 1195111c6094SJack Morgenstein err = mlx4_cmd(dev, mailbox->dma, 1196a130b590SIdo Shamay ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8), 1197a130b590SIdo Shamay MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT, 1198a130b590SIdo Shamay MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1199111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 1200111c6094SJack Morgenstein return err; 1201111c6094SJack Morgenstein } 1202111c6094SJack Morgenstein 1203111c6094SJack Morgenstein 1204111c6094SJack Morgenstein void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave) 1205111c6094SJack Morgenstein { 1206111c6094SJack Morgenstein struct mlx4_active_ports actv_ports; 1207111c6094SJack Morgenstein struct mlx4_cmd_mailbox *mailbox; 1208111c6094SJack Morgenstein int num_eth_ports, err; 1209111c6094SJack Morgenstein int i; 1210111c6094SJack Morgenstein 1211872bf2fbSYishai Hadas if (slave < 0 || slave > dev->persist->num_vfs) 1212111c6094SJack Morgenstein return; 1213111c6094SJack Morgenstein 1214111c6094SJack Morgenstein actv_ports = mlx4_get_active_ports(dev, slave); 1215111c6094SJack Morgenstein 1216111c6094SJack Morgenstein for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) { 1217111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) { 1218111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 1219111c6094SJack Morgenstein continue; 1220111c6094SJack Morgenstein num_eth_ports++; 1221111c6094SJack Morgenstein } 1222111c6094SJack Morgenstein } 1223111c6094SJack Morgenstein 1224111c6094SJack Morgenstein if (!num_eth_ports) 1225111c6094SJack Morgenstein return; 1226111c6094SJack Morgenstein 1227111c6094SJack Morgenstein /* have ETH ports. Alloc mailbox for SET_PORT command */ 1228111c6094SJack Morgenstein mailbox = mlx4_alloc_cmd_mailbox(dev); 1229111c6094SJack Morgenstein if (IS_ERR(mailbox)) 1230111c6094SJack Morgenstein return; 1231111c6094SJack Morgenstein 1232111c6094SJack Morgenstein for (i = 0; i < dev->caps.num_ports; i++) { 1233111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) { 1234111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 1235111c6094SJack Morgenstein continue; 1236111c6094SJack Morgenstein err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox); 1237111c6094SJack Morgenstein if (err) 1238111c6094SJack Morgenstein mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n", 1239111c6094SJack Morgenstein slave, i + 1, err); 1240111c6094SJack Morgenstein } 1241111c6094SJack Morgenstein } 1242111c6094SJack Morgenstein 1243111c6094SJack Morgenstein mlx4_free_cmd_mailbox(dev, mailbox); 1244111c6094SJack Morgenstein return; 1245111c6094SJack Morgenstein } 1246111c6094SJack Morgenstein 124740fb4fc1SShaker Daibes static void 1248bf1f9396SShaker Daibes mlx4_en_set_port_mtu(struct mlx4_dev *dev, int slave, int port, 1249bf1f9396SShaker Daibes struct mlx4_set_port_general_context *gen_context) 1250bf1f9396SShaker Daibes { 1251bf1f9396SShaker Daibes struct mlx4_priv *priv = mlx4_priv(dev); 1252bf1f9396SShaker Daibes struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; 1253bf1f9396SShaker Daibes struct mlx4_slave_state *slave_st = &master->slave_state[slave]; 1254bf1f9396SShaker Daibes u16 mtu, prev_mtu; 1255bf1f9396SShaker Daibes 1256bf1f9396SShaker Daibes /* Mtu is configured as the max USER_MTU among all 1257bf1f9396SShaker Daibes * the functions on the port. 1258bf1f9396SShaker Daibes */ 1259bf1f9396SShaker Daibes mtu = be16_to_cpu(gen_context->mtu); 1260bf1f9396SShaker Daibes mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] + 1261bf1f9396SShaker Daibes ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); 1262bf1f9396SShaker Daibes prev_mtu = slave_st->mtu[port]; 1263bf1f9396SShaker Daibes slave_st->mtu[port] = mtu; 1264bf1f9396SShaker Daibes if (mtu > master->max_mtu[port]) 1265bf1f9396SShaker Daibes master->max_mtu[port] = mtu; 1266bf1f9396SShaker Daibes if (mtu < prev_mtu && prev_mtu == master->max_mtu[port]) { 1267bf1f9396SShaker Daibes int i; 1268bf1f9396SShaker Daibes 1269bf1f9396SShaker Daibes slave_st->mtu[port] = mtu; 1270bf1f9396SShaker Daibes master->max_mtu[port] = mtu; 1271bf1f9396SShaker Daibes for (i = 0; i < dev->num_slaves; i++) 1272bf1f9396SShaker Daibes master->max_mtu[port] = 1273bf1f9396SShaker Daibes max_t(u16, master->max_mtu[port], 1274bf1f9396SShaker Daibes master->slave_state[i].mtu[port]); 1275bf1f9396SShaker Daibes } 1276bf1f9396SShaker Daibes gen_context->mtu = cpu_to_be16(master->max_mtu[port]); 1277bf1f9396SShaker Daibes } 1278bf1f9396SShaker Daibes 1279bf1f9396SShaker Daibes static void 128040fb4fc1SShaker Daibes mlx4_en_set_port_user_mtu(struct mlx4_dev *dev, int slave, int port, 128140fb4fc1SShaker Daibes struct mlx4_set_port_general_context *gen_context) 128240fb4fc1SShaker Daibes { 128340fb4fc1SShaker Daibes struct mlx4_priv *priv = mlx4_priv(dev); 128440fb4fc1SShaker Daibes struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; 128540fb4fc1SShaker Daibes struct mlx4_slave_state *slave_st = &master->slave_state[slave]; 128640fb4fc1SShaker Daibes u16 user_mtu, prev_user_mtu; 128740fb4fc1SShaker Daibes 128840fb4fc1SShaker Daibes /* User Mtu is configured as the max USER_MTU among all 128940fb4fc1SShaker Daibes * the functions on the port. 129040fb4fc1SShaker Daibes */ 129140fb4fc1SShaker Daibes user_mtu = be16_to_cpu(gen_context->user_mtu); 129240fb4fc1SShaker Daibes user_mtu = min_t(int, user_mtu, dev->caps.eth_mtu_cap[port]); 129340fb4fc1SShaker Daibes prev_user_mtu = slave_st->user_mtu[port]; 129440fb4fc1SShaker Daibes slave_st->user_mtu[port] = user_mtu; 129540fb4fc1SShaker Daibes if (user_mtu > master->max_user_mtu[port]) 129640fb4fc1SShaker Daibes master->max_user_mtu[port] = user_mtu; 129740fb4fc1SShaker Daibes if (user_mtu < prev_user_mtu && 129840fb4fc1SShaker Daibes prev_user_mtu == master->max_user_mtu[port]) { 129940fb4fc1SShaker Daibes int i; 130040fb4fc1SShaker Daibes 130140fb4fc1SShaker Daibes slave_st->user_mtu[port] = user_mtu; 130240fb4fc1SShaker Daibes master->max_user_mtu[port] = user_mtu; 130340fb4fc1SShaker Daibes for (i = 0; i < dev->num_slaves; i++) 130440fb4fc1SShaker Daibes master->max_user_mtu[port] = 130540fb4fc1SShaker Daibes max_t(u16, master->max_user_mtu[port], 130640fb4fc1SShaker Daibes master->slave_state[i].user_mtu[port]); 130740fb4fc1SShaker Daibes } 130840fb4fc1SShaker Daibes gen_context->user_mtu = cpu_to_be16(master->max_user_mtu[port]); 130940fb4fc1SShaker Daibes } 131040fb4fc1SShaker Daibes 13111f8176f7SShaker Daibes static void 13121f8176f7SShaker Daibes mlx4_en_set_port_global_pause(struct mlx4_dev *dev, int slave, 13131f8176f7SShaker Daibes struct mlx4_set_port_general_context *gen_context) 13141f8176f7SShaker Daibes { 13151f8176f7SShaker Daibes struct mlx4_priv *priv = mlx4_priv(dev); 13161f8176f7SShaker Daibes struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; 13171f8176f7SShaker Daibes 13181f8176f7SShaker Daibes /* Slave cannot change Global Pause configuration */ 13191f8176f7SShaker Daibes if (slave != mlx4_master_func_num(dev) && 13201f8176f7SShaker Daibes (gen_context->pptx != master->pptx || 13211f8176f7SShaker Daibes gen_context->pprx != master->pprx)) { 13221f8176f7SShaker Daibes gen_context->pptx = master->pptx; 13231f8176f7SShaker Daibes gen_context->pprx = master->pprx; 13241f8176f7SShaker Daibes mlx4_warn(dev, "denying Global Pause change for slave:%d\n", 13251f8176f7SShaker Daibes slave); 13261f8176f7SShaker Daibes } else { 13271f8176f7SShaker Daibes master->pptx = gen_context->pptx; 13281f8176f7SShaker Daibes master->pprx = gen_context->pprx; 13291f8176f7SShaker Daibes } 13301f8176f7SShaker Daibes } 13311f8176f7SShaker Daibes 1332ffe455adSEugenia Emantayev static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, 1333ffe455adSEugenia Emantayev u8 op_mod, struct mlx4_cmd_mailbox *inbox) 1334ffe455adSEugenia Emantayev { 1335ffe455adSEugenia Emantayev struct mlx4_priv *priv = mlx4_priv(dev); 1336ffe455adSEugenia Emantayev struct mlx4_port_info *port_info; 1337ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *qpn_context; 1338ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *gen_context; 1339b6ffaeffSJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1; 1340ffe455adSEugenia Emantayev int reset_qkey_viols; 1341ffe455adSEugenia Emantayev int port; 1342ffe455adSEugenia Emantayev int is_eth; 1343b6ffaeffSJack Morgenstein int num_gids; 1344b6ffaeffSJack Morgenstein int base; 1345ffe455adSEugenia Emantayev u32 in_modifier; 1346ffe455adSEugenia Emantayev u32 promisc; 1347ffe455adSEugenia Emantayev int err; 1348b6ffaeffSJack Morgenstein int i, j; 1349b6ffaeffSJack Morgenstein int offset; 1350ffe455adSEugenia Emantayev __be32 agg_cap_mask; 1351ffe455adSEugenia Emantayev __be32 slave_cap_mask; 1352ffe455adSEugenia Emantayev __be32 new_cap_mask; 1353ffe455adSEugenia Emantayev 1354ffe455adSEugenia Emantayev port = in_mod & 0xff; 1355ffe455adSEugenia Emantayev in_modifier = in_mod >> 8; 1356ffe455adSEugenia Emantayev is_eth = op_mod; 1357ffe455adSEugenia Emantayev port_info = &priv->port[port]; 1358ffe455adSEugenia Emantayev 135940fb4fc1SShaker Daibes /* Slaves cannot perform SET_PORT operations, 136040fb4fc1SShaker Daibes * except for changing MTU and USER_MTU. 136140fb4fc1SShaker Daibes */ 1362ffe455adSEugenia Emantayev if (is_eth) { 1363ffe455adSEugenia Emantayev if (slave != dev->caps.function && 13649cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GENERAL && 13659cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GID_TABLE) { 1366ffe455adSEugenia Emantayev mlx4_warn(dev, "denying SET_PORT for slave:%d\n", 1367ffe455adSEugenia Emantayev slave); 1368ffe455adSEugenia Emantayev return -EINVAL; 1369ffe455adSEugenia Emantayev } 1370ffe455adSEugenia Emantayev switch (in_modifier) { 1371ffe455adSEugenia Emantayev case MLX4_SET_PORT_RQP_CALC: 1372ffe455adSEugenia Emantayev qpn_context = inbox->buf; 1373ffe455adSEugenia Emantayev qpn_context->base_qpn = 1374ffe455adSEugenia Emantayev cpu_to_be32(port_info->base_qpn); 1375ffe455adSEugenia Emantayev qpn_context->n_mac = 0x7; 1376ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->promisc) >> 1377ffe455adSEugenia Emantayev SET_PORT_PROMISC_SHIFT; 1378ffe455adSEugenia Emantayev qpn_context->promisc = cpu_to_be32( 1379ffe455adSEugenia Emantayev promisc << SET_PORT_PROMISC_SHIFT | 1380ffe455adSEugenia Emantayev port_info->base_qpn); 1381ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->mcast) >> 1382ffe455adSEugenia Emantayev SET_PORT_MC_PROMISC_SHIFT; 1383ffe455adSEugenia Emantayev qpn_context->mcast = cpu_to_be32( 1384ffe455adSEugenia Emantayev promisc << SET_PORT_MC_PROMISC_SHIFT | 1385ffe455adSEugenia Emantayev port_info->base_qpn); 1386ffe455adSEugenia Emantayev break; 1387ffe455adSEugenia Emantayev case MLX4_SET_PORT_GENERAL: 1388ffe455adSEugenia Emantayev gen_context = inbox->buf; 1389bf1f9396SShaker Daibes 1390bf1f9396SShaker Daibes if (gen_context->flags & MLX4_FLAG_V_MTU_MASK) 1391bf1f9396SShaker Daibes mlx4_en_set_port_mtu(dev, slave, port, 1392bf1f9396SShaker Daibes gen_context); 139340fb4fc1SShaker Daibes 139440fb4fc1SShaker Daibes if (gen_context->flags2 & MLX4_FLAG2_V_USER_MTU_MASK) 139540fb4fc1SShaker Daibes mlx4_en_set_port_user_mtu(dev, slave, port, 139640fb4fc1SShaker Daibes gen_context); 139740fb4fc1SShaker Daibes 13981f8176f7SShaker Daibes if (gen_context->flags & 139973cfb2a2SDan Carpenter (MLX4_FLAG_V_PPRX_MASK | MLX4_FLAG_V_PPTX_MASK)) 14001f8176f7SShaker Daibes mlx4_en_set_port_global_pause(dev, slave, 14011f8176f7SShaker Daibes gen_context); 14021f8176f7SShaker Daibes 1403ffe455adSEugenia Emantayev break; 14049cd59352SJack Morgenstein case MLX4_SET_PORT_GID_TABLE: 1405b6ffaeffSJack Morgenstein /* change to MULTIPLE entries: number of guest's gids 1406b6ffaeffSJack Morgenstein * need a FOR-loop here over number of gids the guest has. 1407b6ffaeffSJack Morgenstein * 1. Check no duplicates in gids passed by slave 1408b6ffaeffSJack Morgenstein */ 1409449fc488SMatan Barak num_gids = mlx4_get_slave_num_gids(dev, slave, port); 1410449fc488SMatan Barak base = mlx4_get_base_gid_ix(dev, slave, port); 1411b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1412b6ffaeffSJack Morgenstein for (i = 0; i < num_gids; gid_entry_mbox++, i++) { 1413b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 1414b6ffaeffSJack Morgenstein sizeof(zgid_entry))) 1415b6ffaeffSJack Morgenstein continue; 1416b6ffaeffSJack Morgenstein gid_entry_mb1 = gid_entry_mbox + 1; 1417b6ffaeffSJack Morgenstein for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) { 1418b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw, 1419b6ffaeffSJack Morgenstein zgid_entry.raw, sizeof(zgid_entry))) 1420b6ffaeffSJack Morgenstein continue; 1421b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw, 1422b6ffaeffSJack Morgenstein sizeof(gid_entry_mbox->raw))) { 1423b6ffaeffSJack Morgenstein /* found duplicate */ 1424b6ffaeffSJack Morgenstein return -EINVAL; 1425b6ffaeffSJack Morgenstein } 1426b6ffaeffSJack Morgenstein } 1427b6ffaeffSJack Morgenstein } 1428b6ffaeffSJack Morgenstein 1429b6ffaeffSJack Morgenstein /* 2. Check that do not have duplicates in OTHER 1430b6ffaeffSJack Morgenstein * entries in the port GID table 1431b6ffaeffSJack Morgenstein */ 1432111c6094SJack Morgenstein 1433111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex)); 14349cd59352SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 1435b6ffaeffSJack Morgenstein if (i >= base && i < base + num_gids) 1436b6ffaeffSJack Morgenstein continue; /* don't compare to slave's current gids */ 1437111c6094SJack Morgenstein gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i]; 1438b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry))) 1439b6ffaeffSJack Morgenstein continue; 1440b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1441b6ffaeffSJack Morgenstein for (j = 0; j < num_gids; gid_entry_mbox++, j++) { 1442b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 1443b6ffaeffSJack Morgenstein sizeof(zgid_entry))) 1444b6ffaeffSJack Morgenstein continue; 1445b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw, 1446b6ffaeffSJack Morgenstein sizeof(gid_entry_tbl->raw))) { 1447b6ffaeffSJack Morgenstein /* found duplicate */ 14481a91de28SJoe Perches mlx4_warn(dev, "requested gid entry for slave:%d is a duplicate of gid at index %d\n", 14499cd59352SJack Morgenstein slave, i); 1450111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 1451b6ffaeffSJack Morgenstein return -EINVAL; 14529cd59352SJack Morgenstein } 14539cd59352SJack Morgenstein } 14549cd59352SJack Morgenstein } 1455b6ffaeffSJack Morgenstein 1456b6ffaeffSJack Morgenstein /* insert slave GIDs with memcpy, starting at slave's base index */ 1457b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1458b6ffaeffSJack Morgenstein for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++) 1459111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 1460111c6094SJack Morgenstein gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE); 1461b6ffaeffSJack Morgenstein 1462b6ffaeffSJack Morgenstein /* Now, copy roce port gids table to current mailbox for passing to FW */ 1463b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1464b6ffaeffSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 1465111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw, 1466111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw, 1467111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 1468b6ffaeffSJack Morgenstein 1469111c6094SJack Morgenstein err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 1470111c6094SJack Morgenstein MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1471111c6094SJack Morgenstein MLX4_CMD_NATIVE); 1472111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 1473111c6094SJack Morgenstein return err; 1474ffe455adSEugenia Emantayev } 1475111c6094SJack Morgenstein 1476111c6094SJack Morgenstein return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 1477ffe455adSEugenia Emantayev MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1478ffe455adSEugenia Emantayev MLX4_CMD_NATIVE); 1479ffe455adSEugenia Emantayev } 1480ffe455adSEugenia Emantayev 148151af33cfSIdo Shamay /* Slaves are not allowed to SET_PORT beacon (LED) blink */ 148251af33cfSIdo Shamay if (op_mod == MLX4_SET_PORT_BEACON_OPCODE) { 148351af33cfSIdo Shamay mlx4_warn(dev, "denying SET_PORT Beacon slave:%d\n", slave); 148451af33cfSIdo Shamay return -EPERM; 148551af33cfSIdo Shamay } 148651af33cfSIdo Shamay 1487ffe455adSEugenia Emantayev /* For IB, we only consider: 1488ffe455adSEugenia Emantayev * - The capability mask, which is set to the aggregate of all 1489ffe455adSEugenia Emantayev * slave function capabilities 1490ffe455adSEugenia Emantayev * - The QKey violatin counter - reset according to each request. 1491ffe455adSEugenia Emantayev */ 1492ffe455adSEugenia Emantayev 1493ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 1494ffe455adSEugenia Emantayev reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40; 1495ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[2]; 1496ffe455adSEugenia Emantayev } else { 1497ffe455adSEugenia Emantayev reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1; 1498ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[1]; 1499ffe455adSEugenia Emantayev } 1500ffe455adSEugenia Emantayev 1501efcd235dSJack Morgenstein /* slave may not set the IS_SM capability for the port */ 1502efcd235dSJack Morgenstein if (slave != mlx4_master_func_num(dev) && 1503efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM)) 1504efcd235dSJack Morgenstein return -EINVAL; 1505efcd235dSJack Morgenstein 1506efcd235dSJack Morgenstein /* No DEV_MGMT in multifunc mode */ 1507efcd235dSJack Morgenstein if (mlx4_is_mfunc(dev) && 1508efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP)) 1509efcd235dSJack Morgenstein return -EINVAL; 1510efcd235dSJack Morgenstein 1511ffe455adSEugenia Emantayev agg_cap_mask = 0; 1512ffe455adSEugenia Emantayev slave_cap_mask = 1513ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; 1514ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask; 1515ffe455adSEugenia Emantayev for (i = 0; i < dev->num_slaves; i++) 1516ffe455adSEugenia Emantayev agg_cap_mask |= 1517ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[i].ib_cap_mask[port]; 1518ffe455adSEugenia Emantayev 1519ffe455adSEugenia Emantayev /* only clear mailbox for guests. Master may be setting 1520ffe455adSEugenia Emantayev * MTU or PKEY table size 1521ffe455adSEugenia Emantayev */ 1522ffe455adSEugenia Emantayev if (slave != dev->caps.function) 1523ffe455adSEugenia Emantayev memset(inbox->buf, 0, 256); 1524ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 1525edc4a67eSJack Morgenstein *(u8 *) inbox->buf |= !!reset_qkey_viols << 6; 1526ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[2] = agg_cap_mask; 1527ffe455adSEugenia Emantayev } else { 1528edc4a67eSJack Morgenstein ((u8 *) inbox->buf)[3] |= !!reset_qkey_viols; 1529ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[1] = agg_cap_mask; 1530ffe455adSEugenia Emantayev } 1531ffe455adSEugenia Emantayev 1532ffe455adSEugenia Emantayev err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT, 1533ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1534ffe455adSEugenia Emantayev if (err) 1535ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = 1536ffe455adSEugenia Emantayev slave_cap_mask; 1537ffe455adSEugenia Emantayev return err; 1538ffe455adSEugenia Emantayev } 1539ffe455adSEugenia Emantayev 1540ffe455adSEugenia Emantayev int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, 1541ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1542ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1543ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1544ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1545ffe455adSEugenia Emantayev { 1546449fc488SMatan Barak int port = mlx4_slave_convert_port( 1547449fc488SMatan Barak dev, slave, vhcr->in_modifier & 0xFF); 1548449fc488SMatan Barak 1549449fc488SMatan Barak if (port < 0) 1550449fc488SMatan Barak return -EINVAL; 1551449fc488SMatan Barak 1552449fc488SMatan Barak vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) | 1553449fc488SMatan Barak (port & 0xFF); 1554449fc488SMatan Barak 1555ffe455adSEugenia Emantayev return mlx4_common_set_port(dev, slave, vhcr->in_modifier, 1556ffe455adSEugenia Emantayev vhcr->op_modifier, inbox); 1557ffe455adSEugenia Emantayev } 1558ffe455adSEugenia Emantayev 1559096335b3SOr Gerlitz /* bit locations for set port command with zero op modifier */ 1560096335b3SOr Gerlitz enum { 1561096335b3SOr Gerlitz MLX4_SET_PORT_VL_CAP = 4, /* bits 7:4 */ 1562096335b3SOr Gerlitz MLX4_SET_PORT_MTU_CAP = 12, /* bits 15:12 */ 15636634961cSJack Morgenstein MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20, 1564096335b3SOr Gerlitz MLX4_CHANGE_PORT_VL_CAP = 21, 1565096335b3SOr Gerlitz MLX4_CHANGE_PORT_MTU_CAP = 22, 1566096335b3SOr Gerlitz }; 1567096335b3SOr Gerlitz 15686634961cSJack Morgenstein int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz) 15695a2cc190SJeff Kirsher { 15705a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 15716634961cSJack Morgenstein int err, vl_cap, pkey_tbl_flag = 0; 15725a2cc190SJeff Kirsher 15735a2cc190SJeff Kirsher if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) 15745a2cc190SJeff Kirsher return 0; 15755a2cc190SJeff Kirsher 15765a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 15775a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 15785a2cc190SJeff Kirsher return PTR_ERR(mailbox); 15795a2cc190SJeff Kirsher 15805a2cc190SJeff Kirsher ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; 1581096335b3SOr Gerlitz 15826634961cSJack Morgenstein if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) { 15836634961cSJack Morgenstein pkey_tbl_flag = 1; 15846634961cSJack Morgenstein ((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz); 15856634961cSJack Morgenstein } 15866634961cSJack Morgenstein 1587096335b3SOr Gerlitz /* IB VL CAP enum isn't used by the firmware, just numerical values */ 1588096335b3SOr Gerlitz for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) { 1589096335b3SOr Gerlitz ((__be32 *) mailbox->buf)[0] = cpu_to_be32( 1590096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_MTU_CAP) | 1591096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_VL_CAP) | 15926634961cSJack Morgenstein (pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) | 1593096335b3SOr Gerlitz (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) | 1594096335b3SOr Gerlitz (vl_cap << MLX4_SET_PORT_VL_CAP)); 1595a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, port, 1596a130b590SIdo Shamay MLX4_SET_PORT_IB_OPCODE, MLX4_CMD_SET_PORT, 1597f9baff50SJack Morgenstein MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 1598096335b3SOr Gerlitz if (err != -ENOMEM) 1599096335b3SOr Gerlitz break; 1600096335b3SOr Gerlitz } 16015a2cc190SJeff Kirsher 16025a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 16035a2cc190SJeff Kirsher return err; 16045a2cc190SJeff Kirsher } 1605ffe455adSEugenia Emantayev 16061da494cbSMoni Shoua #define SET_PORT_ROCE_2_FLAGS 0x10 16071da494cbSMoni Shoua #define MLX4_SET_PORT_ROCE_V1_V2 0x2 1608cb9ffb76SJoerg Roedel int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, 1609ffe455adSEugenia Emantayev u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx) 1610ffe455adSEugenia Emantayev { 1611ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 1612ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *context; 1613ffe455adSEugenia Emantayev int err; 1614ffe455adSEugenia Emantayev u32 in_mod; 1615ffe455adSEugenia Emantayev 1616ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 1617ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 1618ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 1619ffe455adSEugenia Emantayev context = mailbox->buf; 1620ffe455adSEugenia Emantayev context->flags = SET_PORT_GEN_ALL_VALID; 1621ffe455adSEugenia Emantayev context->mtu = cpu_to_be16(mtu); 1622ffe455adSEugenia Emantayev context->pptx = (pptx * (!pfctx)) << 7; 1623ffe455adSEugenia Emantayev context->pfctx = pfctx; 1624ffe455adSEugenia Emantayev context->pprx = (pprx * (!pfcrx)) << 7; 1625ffe455adSEugenia Emantayev context->pfcrx = pfcrx; 1626ffe455adSEugenia Emantayev 16271da494cbSMoni Shoua if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2) { 16281da494cbSMoni Shoua context->flags |= SET_PORT_ROCE_2_FLAGS; 16291da494cbSMoni Shoua context->roce_mode |= 16301da494cbSMoni Shoua MLX4_SET_PORT_ROCE_V1_V2 << 4; 16311da494cbSMoni Shoua } 1632ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 1633a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1634a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1635a130b590SIdo Shamay MLX4_CMD_WRAPPED); 1636ffe455adSEugenia Emantayev 1637ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 1638ffe455adSEugenia Emantayev return err; 1639ffe455adSEugenia Emantayev } 1640ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_general); 1641ffe455adSEugenia Emantayev 1642cb9ffb76SJoerg Roedel int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, 1643ffe455adSEugenia Emantayev u8 promisc) 1644ffe455adSEugenia Emantayev { 1645ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 1646ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *context; 1647ffe455adSEugenia Emantayev int err; 1648ffe455adSEugenia Emantayev u32 in_mod; 1649ffe455adSEugenia Emantayev u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ? 1650ffe455adSEugenia Emantayev MCAST_DIRECT : MCAST_DEFAULT; 1651ffe455adSEugenia Emantayev 1652c96d97f4SHadar Hen Zion if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) 1653ffe455adSEugenia Emantayev return 0; 1654ffe455adSEugenia Emantayev 1655ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 1656ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 1657ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 1658ffe455adSEugenia Emantayev context = mailbox->buf; 1659ffe455adSEugenia Emantayev context->base_qpn = cpu_to_be32(base_qpn); 1660ffe455adSEugenia Emantayev context->n_mac = dev->caps.log_num_macs; 1661ffe455adSEugenia Emantayev context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | 1662ffe455adSEugenia Emantayev base_qpn); 1663ffe455adSEugenia Emantayev context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | 1664ffe455adSEugenia Emantayev base_qpn); 1665ffe455adSEugenia Emantayev context->intra_no_vlan = 0; 1666ffe455adSEugenia Emantayev context->no_vlan = MLX4_NO_VLAN_IDX; 1667ffe455adSEugenia Emantayev context->intra_vlan_miss = 0; 1668ffe455adSEugenia Emantayev context->vlan_miss = MLX4_VLAN_MISS_IDX; 1669ffe455adSEugenia Emantayev 1670ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_RQP_CALC << 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_WRAPPED); 1674ffe455adSEugenia Emantayev 1675ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 1676ffe455adSEugenia Emantayev return err; 1677ffe455adSEugenia Emantayev } 1678ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); 1679ffe455adSEugenia Emantayev 168040fb4fc1SShaker Daibes int mlx4_SET_PORT_user_mtu(struct mlx4_dev *dev, u8 port, u16 user_mtu) 168140fb4fc1SShaker Daibes { 168240fb4fc1SShaker Daibes struct mlx4_cmd_mailbox *mailbox; 168340fb4fc1SShaker Daibes struct mlx4_set_port_general_context *context; 168440fb4fc1SShaker Daibes u32 in_mod; 168540fb4fc1SShaker Daibes int err; 168640fb4fc1SShaker Daibes 168740fb4fc1SShaker Daibes mailbox = mlx4_alloc_cmd_mailbox(dev); 168840fb4fc1SShaker Daibes if (IS_ERR(mailbox)) 168940fb4fc1SShaker Daibes return PTR_ERR(mailbox); 169040fb4fc1SShaker Daibes context = mailbox->buf; 169140fb4fc1SShaker Daibes context->flags2 |= MLX4_FLAG2_V_USER_MTU_MASK; 169240fb4fc1SShaker Daibes context->user_mtu = cpu_to_be16(user_mtu); 169340fb4fc1SShaker Daibes 169440fb4fc1SShaker Daibes in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 169540fb4fc1SShaker Daibes err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 169640fb4fc1SShaker Daibes MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 169740fb4fc1SShaker Daibes MLX4_CMD_WRAPPED); 169840fb4fc1SShaker Daibes 169940fb4fc1SShaker Daibes mlx4_free_cmd_mailbox(dev, mailbox); 170040fb4fc1SShaker Daibes return err; 170140fb4fc1SShaker Daibes } 170240fb4fc1SShaker Daibes EXPORT_SYMBOL(mlx4_SET_PORT_user_mtu); 170340fb4fc1SShaker Daibes 1704be599603SMoshe Shemesh int mlx4_SET_PORT_user_mac(struct mlx4_dev *dev, u8 port, u8 *user_mac) 1705be599603SMoshe Shemesh { 1706be599603SMoshe Shemesh struct mlx4_cmd_mailbox *mailbox; 1707be599603SMoshe Shemesh struct mlx4_set_port_general_context *context; 1708be599603SMoshe Shemesh u32 in_mod; 1709be599603SMoshe Shemesh int err; 1710be599603SMoshe Shemesh 1711be599603SMoshe Shemesh mailbox = mlx4_alloc_cmd_mailbox(dev); 1712be599603SMoshe Shemesh if (IS_ERR(mailbox)) 1713be599603SMoshe Shemesh return PTR_ERR(mailbox); 1714be599603SMoshe Shemesh context = mailbox->buf; 1715be599603SMoshe Shemesh context->flags2 |= MLX4_FLAG2_V_USER_MAC_MASK; 1716be599603SMoshe Shemesh memcpy(context->user_mac, user_mac, sizeof(context->user_mac)); 1717be599603SMoshe Shemesh 1718be599603SMoshe Shemesh in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 1719be599603SMoshe Shemesh err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1720be599603SMoshe Shemesh MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1721be599603SMoshe Shemesh MLX4_CMD_NATIVE); 1722be599603SMoshe Shemesh 1723be599603SMoshe Shemesh mlx4_free_cmd_mailbox(dev, mailbox); 1724be599603SMoshe Shemesh return err; 1725be599603SMoshe Shemesh } 1726be599603SMoshe Shemesh EXPORT_SYMBOL(mlx4_SET_PORT_user_mac); 1727be599603SMoshe Shemesh 172878500b8cSMuhammad Mahajna int mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, u8 ignore_fcs_value) 172978500b8cSMuhammad Mahajna { 173078500b8cSMuhammad Mahajna struct mlx4_cmd_mailbox *mailbox; 173178500b8cSMuhammad Mahajna struct mlx4_set_port_general_context *context; 173278500b8cSMuhammad Mahajna u32 in_mod; 173378500b8cSMuhammad Mahajna int err; 173478500b8cSMuhammad Mahajna 173578500b8cSMuhammad Mahajna mailbox = mlx4_alloc_cmd_mailbox(dev); 173678500b8cSMuhammad Mahajna if (IS_ERR(mailbox)) 173778500b8cSMuhammad Mahajna return PTR_ERR(mailbox); 173878500b8cSMuhammad Mahajna context = mailbox->buf; 173940fb4fc1SShaker Daibes context->flags2 |= MLX4_FLAG2_V_IGNORE_FCS_MASK; 174078500b8cSMuhammad Mahajna if (ignore_fcs_value) 174178500b8cSMuhammad Mahajna context->ignore_fcs |= MLX4_IGNORE_FCS_MASK; 174278500b8cSMuhammad Mahajna else 174378500b8cSMuhammad Mahajna context->ignore_fcs &= ~MLX4_IGNORE_FCS_MASK; 174478500b8cSMuhammad Mahajna 174578500b8cSMuhammad Mahajna in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 174678500b8cSMuhammad Mahajna err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 174778500b8cSMuhammad Mahajna MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 174878500b8cSMuhammad Mahajna 174978500b8cSMuhammad Mahajna mlx4_free_cmd_mailbox(dev, mailbox); 175078500b8cSMuhammad Mahajna return err; 175178500b8cSMuhammad Mahajna } 175278500b8cSMuhammad Mahajna EXPORT_SYMBOL(mlx4_SET_PORT_fcs_check); 175378500b8cSMuhammad Mahajna 17547ffdf726SOr Gerlitz enum { 17557ffdf726SOr Gerlitz VXLAN_ENABLE_MODIFY = 1 << 7, 17567ffdf726SOr Gerlitz VXLAN_STEERING_MODIFY = 1 << 6, 17577ffdf726SOr Gerlitz 17587ffdf726SOr Gerlitz VXLAN_ENABLE = 1 << 7, 17597ffdf726SOr Gerlitz }; 17607ffdf726SOr Gerlitz 17617ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context { 17627ffdf726SOr Gerlitz u32 reserved1; 17637ffdf726SOr Gerlitz u8 modify_flags; 17647ffdf726SOr Gerlitz u8 reserved2; 17657ffdf726SOr Gerlitz u8 enable_flags; 17667ffdf726SOr Gerlitz u8 steering; 17677ffdf726SOr Gerlitz }; 17687ffdf726SOr Gerlitz 17691b136de1SOr Gerlitz int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable) 17707ffdf726SOr Gerlitz { 17717ffdf726SOr Gerlitz int err; 17727ffdf726SOr Gerlitz u32 in_mod; 17737ffdf726SOr Gerlitz struct mlx4_cmd_mailbox *mailbox; 17747ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context *context; 17757ffdf726SOr Gerlitz 17767ffdf726SOr Gerlitz mailbox = mlx4_alloc_cmd_mailbox(dev); 17777ffdf726SOr Gerlitz if (IS_ERR(mailbox)) 17787ffdf726SOr Gerlitz return PTR_ERR(mailbox); 17797ffdf726SOr Gerlitz context = mailbox->buf; 17807ffdf726SOr Gerlitz memset(context, 0, sizeof(*context)); 17817ffdf726SOr Gerlitz 17827ffdf726SOr Gerlitz context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY; 17831b136de1SOr Gerlitz if (enable) 17847ffdf726SOr Gerlitz context->enable_flags = VXLAN_ENABLE; 17857ffdf726SOr Gerlitz context->steering = steering; 17867ffdf726SOr Gerlitz 17877ffdf726SOr Gerlitz in_mod = MLX4_SET_PORT_VXLAN << 8 | port; 1788a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1789a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1790a130b590SIdo Shamay MLX4_CMD_NATIVE); 17917ffdf726SOr Gerlitz 17927ffdf726SOr Gerlitz mlx4_free_cmd_mailbox(dev, mailbox); 17937ffdf726SOr Gerlitz return err; 17947ffdf726SOr Gerlitz } 17957ffdf726SOr Gerlitz EXPORT_SYMBOL(mlx4_SET_PORT_VXLAN); 17967ffdf726SOr Gerlitz 179751af33cfSIdo Shamay int mlx4_SET_PORT_BEACON(struct mlx4_dev *dev, u8 port, u16 time) 179851af33cfSIdo Shamay { 179951af33cfSIdo Shamay int err; 180051af33cfSIdo Shamay struct mlx4_cmd_mailbox *mailbox; 180151af33cfSIdo Shamay 180251af33cfSIdo Shamay mailbox = mlx4_alloc_cmd_mailbox(dev); 180351af33cfSIdo Shamay if (IS_ERR(mailbox)) 180451af33cfSIdo Shamay return PTR_ERR(mailbox); 180551af33cfSIdo Shamay 180651af33cfSIdo Shamay *((__be32 *)mailbox->buf) = cpu_to_be32(time); 180751af33cfSIdo Shamay 180851af33cfSIdo Shamay err = mlx4_cmd(dev, mailbox->dma, port, MLX4_SET_PORT_BEACON_OPCODE, 180951af33cfSIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 181051af33cfSIdo Shamay MLX4_CMD_NATIVE); 181151af33cfSIdo Shamay 181251af33cfSIdo Shamay mlx4_free_cmd_mailbox(dev, mailbox); 181351af33cfSIdo Shamay return err; 181451af33cfSIdo Shamay } 181551af33cfSIdo Shamay EXPORT_SYMBOL(mlx4_SET_PORT_BEACON); 181651af33cfSIdo Shamay 1817ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1818ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1819ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1820ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1821ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1822ffe455adSEugenia Emantayev { 1823ffe455adSEugenia Emantayev int err = 0; 1824ffe455adSEugenia Emantayev 1825ffe455adSEugenia Emantayev return err; 1826ffe455adSEugenia Emantayev } 1827ffe455adSEugenia Emantayev 1828ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, 1829ffe455adSEugenia Emantayev u64 mac, u64 clear, u8 mode) 1830ffe455adSEugenia Emantayev { 1831ffe455adSEugenia Emantayev return mlx4_cmd(dev, (mac | (clear << 63)), port, mode, 1832ffe455adSEugenia Emantayev MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B, 1833ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 1834ffe455adSEugenia Emantayev } 1835ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR); 1836ffe455adSEugenia Emantayev 1837ffe455adSEugenia Emantayev int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1838ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1839ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1840ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1841ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1842ffe455adSEugenia Emantayev { 1843ffe455adSEugenia Emantayev int err = 0; 1844ffe455adSEugenia Emantayev 1845ffe455adSEugenia Emantayev return err; 1846ffe455adSEugenia Emantayev } 1847ffe455adSEugenia Emantayev 1848ffe455adSEugenia Emantayev int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, 1849ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1850ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1851ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1852ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1853ffe455adSEugenia Emantayev { 185435fb9afbSEugenia Emantayev return 0; 1855ffe455adSEugenia Emantayev } 185693ece0c1SEugenia Emantayev 18579cd59352SJack Morgenstein int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, 18589cd59352SJack Morgenstein int *slave_id) 18596ee51a4eSJack Morgenstein { 18606ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 18616ee51a4eSJack Morgenstein int i, found_ix = -1; 1862b6ffaeffSJack Morgenstein int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 1863449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 1864449fc488SMatan Barak unsigned num_vfs; 1865449fc488SMatan Barak int slave_gid; 18666ee51a4eSJack Morgenstein 18676ee51a4eSJack Morgenstein if (!mlx4_is_mfunc(dev)) 18686ee51a4eSJack Morgenstein return -EINVAL; 18696ee51a4eSJack Morgenstein 1870449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1871872bf2fbSYishai Hadas num_vfs = bitmap_weight(slaves_pport.slaves, 1872872bf2fbSYishai Hadas dev->persist->num_vfs + 1) - 1; 1873449fc488SMatan Barak 18746ee51a4eSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 1875111c6094SJack Morgenstein if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid, 1876111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE)) { 18776ee51a4eSJack Morgenstein found_ix = i; 18786ee51a4eSJack Morgenstein break; 18796ee51a4eSJack Morgenstein } 18806ee51a4eSJack Morgenstein } 18816ee51a4eSJack Morgenstein 1882b6ffaeffSJack Morgenstein if (found_ix >= 0) { 18830254bc82SMatan Barak /* Calculate a slave_gid which is the slave number in the gid 18840254bc82SMatan Barak * table and not a globally unique slave number. 18850254bc82SMatan Barak */ 1886b6ffaeffSJack Morgenstein if (found_ix < MLX4_ROCE_PF_GIDS) 1887449fc488SMatan Barak slave_gid = 0; 1888449fc488SMatan Barak else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) * 1889449fc488SMatan Barak (vf_gids / num_vfs + 1)) 1890449fc488SMatan Barak slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) / 1891449fc488SMatan Barak (vf_gids / num_vfs + 1)) + 1; 1892b6ffaeffSJack Morgenstein else 1893449fc488SMatan Barak slave_gid = 1894b6ffaeffSJack Morgenstein ((found_ix - MLX4_ROCE_PF_GIDS - 1895449fc488SMatan Barak ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) / 1896449fc488SMatan Barak (vf_gids / num_vfs)) + vf_gids % num_vfs + 1; 1897449fc488SMatan Barak 18980254bc82SMatan Barak /* Calculate the globally unique slave id */ 1899449fc488SMatan Barak if (slave_gid) { 1900449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 1901449fc488SMatan Barak struct mlx4_active_ports actv_ports; 1902449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 1903449fc488SMatan Barak unsigned max_port_p_one; 19040254bc82SMatan Barak int num_vfs_before = 0; 19050254bc82SMatan Barak int candidate_slave_gid; 1906449fc488SMatan Barak 19070254bc82SMatan Barak /* Calculate how many VFs are on the previous port, if exists */ 1908449fc488SMatan Barak for (i = 1; i < port; i++) { 1909449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 19100254bc82SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1911449fc488SMatan Barak slaves_pport_actv = 1912449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv( 1913449fc488SMatan Barak dev, &exclusive_ports); 19140254bc82SMatan Barak num_vfs_before += bitmap_weight( 1915449fc488SMatan Barak slaves_pport_actv.slaves, 1916872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1917449fc488SMatan Barak } 1918449fc488SMatan Barak 19190254bc82SMatan Barak /* candidate_slave_gid isn't necessarily the correct slave, but 19200254bc82SMatan Barak * it has the same number of ports and is assigned to the same 19210254bc82SMatan Barak * ports as the real slave we're looking for. On dual port VF, 19220254bc82SMatan Barak * slave_gid = [single port VFs on port <port>] + 19230254bc82SMatan Barak * [offset of the current slave from the first dual port VF] + 19240254bc82SMatan Barak * 1 (for the PF). 19250254bc82SMatan Barak */ 19260254bc82SMatan Barak candidate_slave_gid = slave_gid + num_vfs_before; 19270254bc82SMatan Barak 19280254bc82SMatan Barak actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid); 1929449fc488SMatan Barak max_port_p_one = find_first_bit( 1930449fc488SMatan Barak actv_ports.ports, dev->caps.num_ports) + 1931449fc488SMatan Barak bitmap_weight(actv_ports.ports, 1932449fc488SMatan Barak dev->caps.num_ports) + 1; 1933449fc488SMatan Barak 19340254bc82SMatan Barak /* Calculate the real slave number */ 1935449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 1936449fc488SMatan Barak if (i == port) 1937449fc488SMatan Barak continue; 1938449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, 1939449fc488SMatan Barak dev->caps.num_ports); 1940449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1941449fc488SMatan Barak slaves_pport_actv = 1942449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv( 1943449fc488SMatan Barak dev, &exclusive_ports); 1944449fc488SMatan Barak slave_gid += bitmap_weight( 1945449fc488SMatan Barak slaves_pport_actv.slaves, 1946872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1947449fc488SMatan Barak } 1948449fc488SMatan Barak } 1949449fc488SMatan Barak *slave_id = slave_gid; 1950b6ffaeffSJack Morgenstein } 19516ee51a4eSJack Morgenstein 19526ee51a4eSJack Morgenstein return (found_ix >= 0) ? 0 : -EINVAL; 19536ee51a4eSJack Morgenstein } 19546ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid); 19556ee51a4eSJack Morgenstein 19569cd59352SJack Morgenstein int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, 19579cd59352SJack Morgenstein u8 *gid) 19586ee51a4eSJack Morgenstein { 19596ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 19606ee51a4eSJack Morgenstein 19616ee51a4eSJack Morgenstein if (!mlx4_is_master(dev)) 19626ee51a4eSJack Morgenstein return -EINVAL; 19636ee51a4eSJack Morgenstein 1964111c6094SJack Morgenstein memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw, 1965111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 19666ee51a4eSJack Morgenstein return 0; 19676ee51a4eSJack Morgenstein } 19686ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); 196932a173c7SSaeed Mahameed 197032a173c7SSaeed Mahameed /* Cable Module Info */ 197132a173c7SSaeed Mahameed #define MODULE_INFO_MAX_READ 48 197232a173c7SSaeed Mahameed 197332a173c7SSaeed Mahameed #define I2C_ADDR_LOW 0x50 197432a173c7SSaeed Mahameed #define I2C_ADDR_HIGH 0x51 197532a173c7SSaeed Mahameed #define I2C_PAGE_SIZE 256 197632a173c7SSaeed Mahameed 197732a173c7SSaeed Mahameed /* Module Info Data */ 197832a173c7SSaeed Mahameed struct mlx4_cable_info { 197932a173c7SSaeed Mahameed u8 i2c_addr; 198032a173c7SSaeed Mahameed u8 page_num; 198132a173c7SSaeed Mahameed __be16 dev_mem_address; 198232a173c7SSaeed Mahameed __be16 reserved1; 198332a173c7SSaeed Mahameed __be16 size; 198432a173c7SSaeed Mahameed __be32 reserved2[2]; 198532a173c7SSaeed Mahameed u8 data[MODULE_INFO_MAX_READ]; 198632a173c7SSaeed Mahameed }; 198732a173c7SSaeed Mahameed 198832a173c7SSaeed Mahameed enum cable_info_err { 198932a173c7SSaeed Mahameed CABLE_INF_INV_PORT = 0x1, 199032a173c7SSaeed Mahameed CABLE_INF_OP_NOSUP = 0x2, 199132a173c7SSaeed Mahameed CABLE_INF_NOT_CONN = 0x3, 199232a173c7SSaeed Mahameed CABLE_INF_NO_EEPRM = 0x4, 199332a173c7SSaeed Mahameed CABLE_INF_PAGE_ERR = 0x5, 199432a173c7SSaeed Mahameed CABLE_INF_INV_ADDR = 0x6, 199532a173c7SSaeed Mahameed CABLE_INF_I2C_ADDR = 0x7, 199632a173c7SSaeed Mahameed CABLE_INF_QSFP_VIO = 0x8, 199732a173c7SSaeed Mahameed CABLE_INF_I2C_BUSY = 0x9, 199832a173c7SSaeed Mahameed }; 199932a173c7SSaeed Mahameed 200032a173c7SSaeed Mahameed #define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF) 200132a173c7SSaeed Mahameed 200232a173c7SSaeed Mahameed static inline const char *cable_info_mad_err_str(u16 mad_status) 200332a173c7SSaeed Mahameed { 200432a173c7SSaeed Mahameed u8 err = MAD_STATUS_2_CABLE_ERR(mad_status); 200532a173c7SSaeed Mahameed 200632a173c7SSaeed Mahameed switch (err) { 200732a173c7SSaeed Mahameed case CABLE_INF_INV_PORT: 200832a173c7SSaeed Mahameed return "invalid port selected"; 200932a173c7SSaeed Mahameed case CABLE_INF_OP_NOSUP: 201032a173c7SSaeed Mahameed return "operation not supported for this port (the port is of type CX4 or internal)"; 201132a173c7SSaeed Mahameed case CABLE_INF_NOT_CONN: 201232a173c7SSaeed Mahameed return "cable is not connected"; 201332a173c7SSaeed Mahameed case CABLE_INF_NO_EEPRM: 201432a173c7SSaeed Mahameed return "the connected cable has no EPROM (passive copper cable)"; 201532a173c7SSaeed Mahameed case CABLE_INF_PAGE_ERR: 201632a173c7SSaeed Mahameed return "page number is greater than 15"; 201732a173c7SSaeed Mahameed case CABLE_INF_INV_ADDR: 201832a173c7SSaeed Mahameed return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)"; 201932a173c7SSaeed Mahameed case CABLE_INF_I2C_ADDR: 202032a173c7SSaeed Mahameed return "invalid I2C slave address"; 202132a173c7SSaeed Mahameed case CABLE_INF_QSFP_VIO: 202232a173c7SSaeed Mahameed return "at least one cable violates the QSFP specification and ignores the modsel signal"; 202332a173c7SSaeed Mahameed case CABLE_INF_I2C_BUSY: 202432a173c7SSaeed Mahameed return "I2C bus is constantly busy"; 202532a173c7SSaeed Mahameed } 202632a173c7SSaeed Mahameed return "Unknown Error"; 202732a173c7SSaeed Mahameed } 202832a173c7SSaeed Mahameed 202932a173c7SSaeed Mahameed /** 203032a173c7SSaeed Mahameed * mlx4_get_module_info - Read cable module eeprom data 203132a173c7SSaeed Mahameed * @dev: mlx4_dev. 203232a173c7SSaeed Mahameed * @port: port number. 203332a173c7SSaeed Mahameed * @offset: byte offset in eeprom to start reading data from. 203432a173c7SSaeed Mahameed * @size: num of bytes to read. 203532a173c7SSaeed Mahameed * @data: output buffer to put the requested data into. 203632a173c7SSaeed Mahameed * 203732a173c7SSaeed Mahameed * Reads cable module eeprom data, puts the outcome data into 203832a173c7SSaeed Mahameed * data pointer paramer. 203932a173c7SSaeed Mahameed * Returns num of read bytes on success or a negative error 204032a173c7SSaeed Mahameed * code. 204132a173c7SSaeed Mahameed */ 204232a173c7SSaeed Mahameed int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, 204332a173c7SSaeed Mahameed u16 offset, u16 size, u8 *data) 204432a173c7SSaeed Mahameed { 204532a173c7SSaeed Mahameed struct mlx4_cmd_mailbox *inbox, *outbox; 204632a173c7SSaeed Mahameed struct mlx4_mad_ifc *inmad, *outmad; 204732a173c7SSaeed Mahameed struct mlx4_cable_info *cable_info; 204832a173c7SSaeed Mahameed u16 i2c_addr; 204932a173c7SSaeed Mahameed int ret; 205032a173c7SSaeed Mahameed 205132a173c7SSaeed Mahameed if (size > MODULE_INFO_MAX_READ) 205232a173c7SSaeed Mahameed size = MODULE_INFO_MAX_READ; 205332a173c7SSaeed Mahameed 205432a173c7SSaeed Mahameed inbox = mlx4_alloc_cmd_mailbox(dev); 205532a173c7SSaeed Mahameed if (IS_ERR(inbox)) 205632a173c7SSaeed Mahameed return PTR_ERR(inbox); 205732a173c7SSaeed Mahameed 205832a173c7SSaeed Mahameed outbox = mlx4_alloc_cmd_mailbox(dev); 205932a173c7SSaeed Mahameed if (IS_ERR(outbox)) { 206032a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, inbox); 206132a173c7SSaeed Mahameed return PTR_ERR(outbox); 206232a173c7SSaeed Mahameed } 206332a173c7SSaeed Mahameed 206432a173c7SSaeed Mahameed inmad = (struct mlx4_mad_ifc *)(inbox->buf); 206532a173c7SSaeed Mahameed outmad = (struct mlx4_mad_ifc *)(outbox->buf); 206632a173c7SSaeed Mahameed 206732a173c7SSaeed Mahameed inmad->method = 0x1; /* Get */ 206832a173c7SSaeed Mahameed inmad->class_version = 0x1; 206932a173c7SSaeed Mahameed inmad->mgmt_class = 0x1; 207032a173c7SSaeed Mahameed inmad->base_version = 0x1; 207132a173c7SSaeed Mahameed inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */ 207232a173c7SSaeed Mahameed 207332a173c7SSaeed Mahameed if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE) 207432a173c7SSaeed Mahameed /* Cross pages reads are not allowed 207532a173c7SSaeed Mahameed * read until offset 256 in low page 207632a173c7SSaeed Mahameed */ 207732a173c7SSaeed Mahameed size -= offset + size - I2C_PAGE_SIZE; 207832a173c7SSaeed Mahameed 207932a173c7SSaeed Mahameed i2c_addr = I2C_ADDR_LOW; 208032a173c7SSaeed Mahameed if (offset >= I2C_PAGE_SIZE) { 208132a173c7SSaeed Mahameed /* Reset offset to high page */ 208232a173c7SSaeed Mahameed i2c_addr = I2C_ADDR_HIGH; 208332a173c7SSaeed Mahameed offset -= I2C_PAGE_SIZE; 208432a173c7SSaeed Mahameed } 208532a173c7SSaeed Mahameed 208632a173c7SSaeed Mahameed cable_info = (struct mlx4_cable_info *)inmad->data; 208732a173c7SSaeed Mahameed cable_info->dev_mem_address = cpu_to_be16(offset); 208832a173c7SSaeed Mahameed cable_info->page_num = 0; 208932a173c7SSaeed Mahameed cable_info->i2c_addr = i2c_addr; 209032a173c7SSaeed Mahameed cable_info->size = cpu_to_be16(size); 209132a173c7SSaeed Mahameed 209232a173c7SSaeed Mahameed ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, 209332a173c7SSaeed Mahameed MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 209432a173c7SSaeed Mahameed MLX4_CMD_NATIVE); 209532a173c7SSaeed Mahameed if (ret) 209632a173c7SSaeed Mahameed goto out; 209732a173c7SSaeed Mahameed 209832a173c7SSaeed Mahameed if (be16_to_cpu(outmad->status)) { 209932a173c7SSaeed Mahameed /* Mad returned with bad status */ 210032a173c7SSaeed Mahameed ret = be16_to_cpu(outmad->status); 210132a173c7SSaeed Mahameed mlx4_warn(dev, 210232a173c7SSaeed 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", 210332a173c7SSaeed Mahameed 0xFF60, port, i2c_addr, offset, size, 210432a173c7SSaeed Mahameed ret, cable_info_mad_err_str(ret)); 210532a173c7SSaeed Mahameed 210632a173c7SSaeed Mahameed if (i2c_addr == I2C_ADDR_HIGH && 210732a173c7SSaeed Mahameed MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR) 210832a173c7SSaeed Mahameed /* Some SFP cables do not support i2c slave 210932a173c7SSaeed Mahameed * address 0x51 (high page), abort silently. 211032a173c7SSaeed Mahameed */ 211132a173c7SSaeed Mahameed ret = 0; 211232a173c7SSaeed Mahameed else 211332a173c7SSaeed Mahameed ret = -ret; 211432a173c7SSaeed Mahameed goto out; 211532a173c7SSaeed Mahameed } 211632a173c7SSaeed Mahameed cable_info = (struct mlx4_cable_info *)outmad->data; 211732a173c7SSaeed Mahameed memcpy(data, cable_info->data, size); 211832a173c7SSaeed Mahameed ret = size; 211932a173c7SSaeed Mahameed out: 212032a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, inbox); 212132a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, outbox); 212232a173c7SSaeed Mahameed return ret; 212332a173c7SSaeed Mahameed } 212432a173c7SSaeed Mahameed EXPORT_SYMBOL(mlx4_get_module_info); 2125af7d5185SRana Shahout 2126af7d5185SRana Shahout int mlx4_max_tc(struct mlx4_dev *dev) 2127af7d5185SRana Shahout { 2128af7d5185SRana Shahout u8 num_tc = dev->caps.max_tc_eth; 2129af7d5185SRana Shahout 2130af7d5185SRana Shahout if (!num_tc) 2131564ed9b1STariq Toukan num_tc = MLX4_TC_MAX_NUMBER; 2132af7d5185SRana Shahout 2133af7d5185SRana Shahout return num_tc; 2134af7d5185SRana Shahout } 2135af7d5185SRana Shahout EXPORT_SYMBOL(mlx4_max_tc); 2136