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) 55bf1f9396SShaker Daibes #define MLX4_FLAG_V_MTU_MASK BIT(0) 561f8176f7SShaker Daibes #define MLX4_FLAG_V_PPRX_MASK BIT(1) 571f8176f7SShaker Daibes #define MLX4_FLAG_V_PPTX_MASK BIT(2) 5878500b8cSMuhammad Mahajna #define MLX4_IGNORE_FCS_MASK 0x1 59564ed9b1STariq Toukan #define MLX4_TC_MAX_NUMBER 8 6078500b8cSMuhammad Mahajna 615a2cc190SJeff Kirsher void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table) 625a2cc190SJeff Kirsher { 635a2cc190SJeff Kirsher int i; 645a2cc190SJeff Kirsher 655a2cc190SJeff Kirsher mutex_init(&table->mutex); 665a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 675a2cc190SJeff Kirsher table->entries[i] = 0; 685a2cc190SJeff Kirsher table->refs[i] = 0; 695f61385dSMoni Shoua table->is_dup[i] = false; 705a2cc190SJeff Kirsher } 715a2cc190SJeff Kirsher table->max = 1 << dev->caps.log_num_macs; 725a2cc190SJeff Kirsher table->total = 0; 735a2cc190SJeff Kirsher } 745a2cc190SJeff Kirsher 755a2cc190SJeff Kirsher void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table) 765a2cc190SJeff Kirsher { 775a2cc190SJeff Kirsher int i; 785a2cc190SJeff Kirsher 795a2cc190SJeff Kirsher mutex_init(&table->mutex); 805a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 815a2cc190SJeff Kirsher table->entries[i] = 0; 825a2cc190SJeff Kirsher table->refs[i] = 0; 835f61385dSMoni Shoua table->is_dup[i] = false; 845a2cc190SJeff Kirsher } 85e72ebf5aSYevgeny Petrilin table->max = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR; 865a2cc190SJeff Kirsher table->total = 0; 875a2cc190SJeff Kirsher } 885a2cc190SJeff Kirsher 89111c6094SJack Morgenstein void mlx4_init_roce_gid_table(struct mlx4_dev *dev, 90111c6094SJack Morgenstein struct mlx4_roce_gid_table *table) 91111c6094SJack Morgenstein { 92111c6094SJack Morgenstein int i; 93111c6094SJack Morgenstein 94111c6094SJack Morgenstein mutex_init(&table->mutex); 95111c6094SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) 96111c6094SJack Morgenstein memset(table->roce_gids[i].raw, 0, MLX4_ROCE_GID_ENTRY_SIZE); 97111c6094SJack Morgenstein } 98111c6094SJack Morgenstein 995a2cc190SJeff Kirsher static int validate_index(struct mlx4_dev *dev, 1005a2cc190SJeff Kirsher struct mlx4_mac_table *table, int index) 1015a2cc190SJeff Kirsher { 1025a2cc190SJeff Kirsher int err = 0; 1035a2cc190SJeff Kirsher 1045a2cc190SJeff Kirsher if (index < 0 || index >= table->max || !table->entries[index]) { 1055a2cc190SJeff Kirsher mlx4_warn(dev, "No valid Mac entry for the given index\n"); 1065a2cc190SJeff Kirsher err = -EINVAL; 1075a2cc190SJeff Kirsher } 1085a2cc190SJeff Kirsher return err; 1095a2cc190SJeff Kirsher } 1105a2cc190SJeff Kirsher 1115a2cc190SJeff Kirsher static int find_index(struct mlx4_dev *dev, 1125a2cc190SJeff Kirsher struct mlx4_mac_table *table, u64 mac) 1135a2cc190SJeff Kirsher { 1145a2cc190SJeff Kirsher int i; 115ffe455adSEugenia Emantayev 1165a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 117f4fd40b2SJack Morgenstein if (table->refs[i] && 118f4fd40b2SJack Morgenstein (MLX4_MAC_MASK & mac) == 119ffe455adSEugenia Emantayev (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) 1205a2cc190SJeff Kirsher return i; 1215a2cc190SJeff Kirsher } 1225a2cc190SJeff Kirsher /* Mac not found */ 1235a2cc190SJeff Kirsher return -EINVAL; 1245a2cc190SJeff Kirsher } 1255a2cc190SJeff Kirsher 126ffe455adSEugenia Emantayev static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, 127ffe455adSEugenia Emantayev __be64 *entries) 128ffe455adSEugenia Emantayev { 129ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 130ffe455adSEugenia Emantayev u32 in_mod; 131ffe455adSEugenia Emantayev int err; 132ffe455adSEugenia Emantayev 133ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 134ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 135ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 136ffe455adSEugenia Emantayev 137ffe455adSEugenia Emantayev memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); 138ffe455adSEugenia Emantayev 139ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; 140ffe455adSEugenia Emantayev 141a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 142a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 143a130b590SIdo Shamay MLX4_CMD_NATIVE); 144ffe455adSEugenia Emantayev 145ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 146ffe455adSEugenia Emantayev return err; 147ffe455adSEugenia Emantayev } 148ffe455adSEugenia Emantayev 149297e0dadSMoni Shoua int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx) 150297e0dadSMoni Shoua { 151297e0dadSMoni Shoua struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 152297e0dadSMoni Shoua struct mlx4_mac_table *table = &info->mac_table; 153297e0dadSMoni Shoua int i; 154297e0dadSMoni Shoua 155297e0dadSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 156297e0dadSMoni Shoua if (!table->refs[i]) 157297e0dadSMoni Shoua continue; 158297e0dadSMoni Shoua 159297e0dadSMoni Shoua if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 160297e0dadSMoni Shoua *idx = i; 161297e0dadSMoni Shoua return 0; 162297e0dadSMoni Shoua } 163297e0dadSMoni Shoua } 164297e0dadSMoni Shoua 165297e0dadSMoni Shoua return -ENOENT; 166297e0dadSMoni Shoua } 167297e0dadSMoni Shoua EXPORT_SYMBOL_GPL(mlx4_find_cached_mac); 168297e0dadSMoni Shoua 1695f61385dSMoni Shoua static bool mlx4_need_mf_bond(struct mlx4_dev *dev) 1705f61385dSMoni Shoua { 1715f61385dSMoni Shoua int i, num_eth_ports = 0; 1725f61385dSMoni Shoua 1735f61385dSMoni Shoua if (!mlx4_is_mfunc(dev)) 1745f61385dSMoni Shoua return false; 1755f61385dSMoni Shoua mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) 1765f61385dSMoni Shoua ++num_eth_ports; 1775f61385dSMoni Shoua 1785f61385dSMoni Shoua return (num_eth_ports == 2) ? true : false; 1795f61385dSMoni Shoua } 1805f61385dSMoni Shoua 181ffe455adSEugenia Emantayev int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 182ffe455adSEugenia Emantayev { 183ffe455adSEugenia Emantayev struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 184ffe455adSEugenia Emantayev struct mlx4_mac_table *table = &info->mac_table; 185ffe455adSEugenia Emantayev int i, err = 0; 186ffe455adSEugenia Emantayev int free = -1; 1875f61385dSMoni Shoua int free_for_dup = -1; 1885f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 1895f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 1905f61385dSMoni Shoua struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table; 1915f61385dSMoni Shoua bool need_mf_bond = mlx4_need_mf_bond(dev); 1925f61385dSMoni Shoua bool can_mf_bond = true; 193ffe455adSEugenia Emantayev 1945f61385dSMoni Shoua mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d %s duplicate\n", 1955f61385dSMoni Shoua (unsigned long long)mac, port, 1965f61385dSMoni Shoua dup ? "with" : "without"); 197ffe455adSEugenia Emantayev 1985f61385dSMoni Shoua if (need_mf_bond) { 1995f61385dSMoni Shoua if (port == 1) { 200ffe455adSEugenia Emantayev mutex_lock(&table->mutex); 20103a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 2025f61385dSMoni Shoua } else { 2035f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 20403a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 2055f61385dSMoni Shoua } 2065f61385dSMoni Shoua } else { 2075f61385dSMoni Shoua mutex_lock(&table->mutex); 2085f61385dSMoni Shoua } 2095f61385dSMoni Shoua 2105f61385dSMoni Shoua if (need_mf_bond) { 2115f61385dSMoni Shoua int index_at_port = -1; 2125f61385dSMoni Shoua int index_at_dup_port = -1; 2135f61385dSMoni Shoua 2145f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 2155f61385dSMoni Shoua if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))) 2165f61385dSMoni Shoua index_at_port = i; 2175f61385dSMoni Shoua if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i])))) 2185f61385dSMoni Shoua index_at_dup_port = i; 2195f61385dSMoni Shoua } 2205f61385dSMoni Shoua 2215f61385dSMoni Shoua /* check that same mac is not in the tables at different indices */ 2225f61385dSMoni Shoua if ((index_at_port != index_at_dup_port) && 2235f61385dSMoni Shoua (index_at_port >= 0) && 2245f61385dSMoni Shoua (index_at_dup_port >= 0)) 2255f61385dSMoni Shoua can_mf_bond = false; 2265f61385dSMoni Shoua 2275f61385dSMoni Shoua /* If the mac is already in the primary table, the slot must be 2285f61385dSMoni Shoua * available in the duplicate table as well. 2295f61385dSMoni Shoua */ 2305f61385dSMoni Shoua if (index_at_port >= 0 && index_at_dup_port < 0 && 2315f61385dSMoni Shoua dup_table->refs[index_at_port]) { 2325f61385dSMoni Shoua can_mf_bond = false; 2335f61385dSMoni Shoua } 2345f61385dSMoni Shoua /* If the mac is already in the duplicate table, check that the 2355f61385dSMoni Shoua * corresponding index is not occupied in the primary table, or 2365f61385dSMoni Shoua * the primary table already contains the mac at the same index. 2375f61385dSMoni Shoua * Otherwise, you cannot bond (primary contains a different mac 2385f61385dSMoni Shoua * at that index). 2395f61385dSMoni Shoua */ 2405f61385dSMoni Shoua if (index_at_dup_port >= 0) { 2415f61385dSMoni Shoua if (!table->refs[index_at_dup_port] || 2425f61385dSMoni Shoua ((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[index_at_dup_port])))) 2435f61385dSMoni Shoua free_for_dup = index_at_dup_port; 2445f61385dSMoni Shoua else 2455f61385dSMoni Shoua can_mf_bond = false; 2465f61385dSMoni Shoua } 2475f61385dSMoni Shoua } 2485f61385dSMoni Shoua 249ffe455adSEugenia Emantayev for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 250f4fd40b2SJack Morgenstein if (!table->refs[i]) { 251f4fd40b2SJack Morgenstein if (free < 0) 252ffe455adSEugenia Emantayev free = i; 2535f61385dSMoni Shoua if (free_for_dup < 0 && need_mf_bond && can_mf_bond) { 2545f61385dSMoni Shoua if (!dup_table->refs[i]) 2555f61385dSMoni Shoua free_for_dup = i; 2565f61385dSMoni Shoua } 257ffe455adSEugenia Emantayev continue; 258ffe455adSEugenia Emantayev } 259ffe455adSEugenia Emantayev 260f4fd40b2SJack Morgenstein if ((MLX4_MAC_MASK & mac) == 261f4fd40b2SJack Morgenstein (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 2626ce71acdSRony Efraim /* MAC already registered, increment ref count */ 2636ce71acdSRony Efraim err = i; 2646ce71acdSRony Efraim ++table->refs[i]; 2655f61385dSMoni Shoua if (dup) { 2665f61385dSMoni Shoua u64 dup_mac = MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]); 2675f61385dSMoni Shoua 2685f61385dSMoni Shoua if (dup_mac != mac || !dup_table->is_dup[i]) { 2695f61385dSMoni Shoua mlx4_warn(dev, "register mac: expect duplicate mac 0x%llx on port %d index %d\n", 2705f61385dSMoni Shoua mac, dup_port, i); 2715f61385dSMoni Shoua } 2725f61385dSMoni Shoua } 273ffe455adSEugenia Emantayev goto out; 274ffe455adSEugenia Emantayev } 275ffe455adSEugenia Emantayev } 276ffe455adSEugenia Emantayev 2775f61385dSMoni Shoua if (need_mf_bond && (free_for_dup < 0)) { 2785f61385dSMoni Shoua if (dup) { 2795f61385dSMoni Shoua mlx4_warn(dev, "Fail to allocate duplicate MAC table entry\n"); 2805f61385dSMoni Shoua mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n"); 2815f61385dSMoni Shoua dup = false; 2825f61385dSMoni Shoua } 2835f61385dSMoni Shoua can_mf_bond = false; 2845f61385dSMoni Shoua } 2855f61385dSMoni Shoua 2865f61385dSMoni Shoua if (need_mf_bond && can_mf_bond) 2875f61385dSMoni Shoua free = free_for_dup; 2885f61385dSMoni Shoua 289ffe455adSEugenia Emantayev mlx4_dbg(dev, "Free MAC index is %d\n", free); 290ffe455adSEugenia Emantayev 291ffe455adSEugenia Emantayev if (table->total == table->max) { 292ffe455adSEugenia Emantayev /* No free mac entries */ 293ffe455adSEugenia Emantayev err = -ENOSPC; 294ffe455adSEugenia Emantayev goto out; 295ffe455adSEugenia Emantayev } 296ffe455adSEugenia Emantayev 297ffe455adSEugenia Emantayev /* Register new MAC */ 298ffe455adSEugenia Emantayev table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); 299ffe455adSEugenia Emantayev 300ffe455adSEugenia Emantayev err = mlx4_set_port_mac_table(dev, port, table->entries); 301ffe455adSEugenia Emantayev if (unlikely(err)) { 302ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 303ffe455adSEugenia Emantayev (unsigned long long) mac); 304ffe455adSEugenia Emantayev table->entries[free] = 0; 305ffe455adSEugenia Emantayev goto out; 306ffe455adSEugenia Emantayev } 3076ce71acdSRony Efraim table->refs[free] = 1; 3085f61385dSMoni Shoua table->is_dup[free] = false; 309ffe455adSEugenia Emantayev ++table->total; 3105f61385dSMoni Shoua if (dup) { 3115f61385dSMoni Shoua dup_table->refs[free] = 0; 3125f61385dSMoni Shoua dup_table->is_dup[free] = true; 3135f61385dSMoni Shoua dup_table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); 3145f61385dSMoni Shoua 3155f61385dSMoni Shoua err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries); 3165f61385dSMoni Shoua if (unlikely(err)) { 3175f61385dSMoni Shoua mlx4_warn(dev, "Failed adding duplicate mac: 0x%llx\n", mac); 3185f61385dSMoni Shoua dup_table->is_dup[free] = false; 3195f61385dSMoni Shoua dup_table->entries[free] = 0; 3205f61385dSMoni Shoua goto out; 3215f61385dSMoni Shoua } 3225f61385dSMoni Shoua ++dup_table->total; 3235f61385dSMoni Shoua } 3245f61385dSMoni Shoua err = free; 325ffe455adSEugenia Emantayev out: 3265f61385dSMoni Shoua if (need_mf_bond) { 3275f61385dSMoni Shoua if (port == 2) { 328ffe455adSEugenia Emantayev mutex_unlock(&table->mutex); 3295f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 3305f61385dSMoni Shoua } else { 3315f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 3325f61385dSMoni Shoua mutex_unlock(&table->mutex); 3335f61385dSMoni Shoua } 3345f61385dSMoni Shoua } else { 3355f61385dSMoni Shoua mutex_unlock(&table->mutex); 3365f61385dSMoni Shoua } 337ffe455adSEugenia Emantayev return err; 338ffe455adSEugenia Emantayev } 339ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_register_mac); 340ffe455adSEugenia Emantayev 341ffe455adSEugenia Emantayev int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 342ffe455adSEugenia Emantayev { 343e7dbeba8SJack Morgenstein u64 out_param = 0; 344acddd5ddSJack Morgenstein int err = -EINVAL; 345ffe455adSEugenia Emantayev 346ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 347acddd5ddSJack Morgenstein if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 348acddd5ddSJack Morgenstein err = mlx4_cmd_imm(dev, mac, &out_param, 349acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_MAC, 350acddd5ddSJack Morgenstein RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 351acddd5ddSJack Morgenstein MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 352acddd5ddSJack Morgenstein } 353acddd5ddSJack Morgenstein if (err && err == -EINVAL && mlx4_is_slave(dev)) { 354acddd5ddSJack Morgenstein /* retry using old REG_MAC format */ 355ffe455adSEugenia Emantayev set_param_l(&out_param, port); 356ffe455adSEugenia Emantayev err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 357ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 358ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 359acddd5ddSJack Morgenstein if (!err) 360acddd5ddSJack Morgenstein dev->flags |= MLX4_FLAG_OLD_REG_MAC; 361acddd5ddSJack Morgenstein } 362ffe455adSEugenia Emantayev if (err) 363ffe455adSEugenia Emantayev return err; 364ffe455adSEugenia Emantayev 365ffe455adSEugenia Emantayev return get_param_l(&out_param); 366ffe455adSEugenia Emantayev } 367ffe455adSEugenia Emantayev return __mlx4_register_mac(dev, port, mac); 368ffe455adSEugenia Emantayev } 369ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(mlx4_register_mac); 370ffe455adSEugenia Emantayev 37116a10ffdSYan Burman int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port) 37216a10ffdSYan Burman { 37316a10ffdSYan Burman return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] + 37416a10ffdSYan Burman (port - 1) * (1 << dev->caps.log_num_macs); 37516a10ffdSYan Burman } 37616a10ffdSYan Burman EXPORT_SYMBOL_GPL(mlx4_get_base_qpn); 377ffe455adSEugenia Emantayev 378ffe455adSEugenia Emantayev void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 379ffe455adSEugenia Emantayev { 380143b3efbSEugenia Emantayev struct mlx4_port_info *info; 381143b3efbSEugenia Emantayev struct mlx4_mac_table *table; 382ffe455adSEugenia Emantayev int index; 3835f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 3845f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 3855f61385dSMoni Shoua struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table; 386ffe455adSEugenia Emantayev 387143b3efbSEugenia Emantayev if (port < 1 || port > dev->caps.num_ports) { 388143b3efbSEugenia Emantayev mlx4_warn(dev, "invalid port number (%d), aborting...\n", port); 389143b3efbSEugenia Emantayev return; 390143b3efbSEugenia Emantayev } 391143b3efbSEugenia Emantayev info = &mlx4_priv(dev)->port[port]; 392143b3efbSEugenia Emantayev table = &info->mac_table; 3935f61385dSMoni Shoua 3945f61385dSMoni Shoua if (dup) { 3955f61385dSMoni Shoua if (port == 1) { 3965a2cc190SJeff Kirsher mutex_lock(&table->mutex); 39703a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 3985f61385dSMoni Shoua } else { 3995f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 40003a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 4015f61385dSMoni Shoua } 4025f61385dSMoni Shoua } else { 4035f61385dSMoni Shoua mutex_lock(&table->mutex); 4045f61385dSMoni Shoua } 4055f61385dSMoni Shoua 4066ce71acdSRony Efraim index = find_index(dev, table, mac); 4075a2cc190SJeff Kirsher 4085a2cc190SJeff Kirsher if (validate_index(dev, table, index)) 4095a2cc190SJeff Kirsher goto out; 4105f61385dSMoni Shoua 4115f61385dSMoni Shoua if (--table->refs[index] || table->is_dup[index]) { 4121a91de28SJoe Perches mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n", 4131a91de28SJoe Perches index); 4145f61385dSMoni Shoua if (!table->refs[index]) 4155f61385dSMoni Shoua dup_table->is_dup[index] = false; 4166ce71acdSRony Efraim goto out; 4176ce71acdSRony Efraim } 4185a2cc190SJeff Kirsher 4195a2cc190SJeff Kirsher table->entries[index] = 0; 4205f61385dSMoni Shoua if (mlx4_set_port_mac_table(dev, port, table->entries)) 4215f61385dSMoni Shoua mlx4_warn(dev, "Fail to set mac in port %d during unregister\n", port); 4225a2cc190SJeff Kirsher --table->total; 4235f61385dSMoni Shoua 4245f61385dSMoni Shoua if (dup) { 4255f61385dSMoni Shoua dup_table->is_dup[index] = false; 4265f61385dSMoni Shoua if (dup_table->refs[index]) 4275f61385dSMoni Shoua goto out; 4285f61385dSMoni Shoua dup_table->entries[index] = 0; 4295f61385dSMoni Shoua if (mlx4_set_port_mac_table(dev, dup_port, dup_table->entries)) 4305f61385dSMoni Shoua mlx4_warn(dev, "Fail to set mac in duplicate port %d during unregister\n", dup_port); 4315f61385dSMoni Shoua 4325f61385dSMoni Shoua --table->total; 4335f61385dSMoni Shoua } 4345a2cc190SJeff Kirsher out: 4355f61385dSMoni Shoua if (dup) { 4365f61385dSMoni Shoua if (port == 2) { 4375a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 4385f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 4395f61385dSMoni Shoua } else { 4405f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 4415f61385dSMoni Shoua mutex_unlock(&table->mutex); 4425f61385dSMoni Shoua } 4435f61385dSMoni Shoua } else { 4445f61385dSMoni Shoua mutex_unlock(&table->mutex); 4455f61385dSMoni Shoua } 4465a2cc190SJeff Kirsher } 447ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_unregister_mac); 448ffe455adSEugenia Emantayev 449ffe455adSEugenia Emantayev void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 450ffe455adSEugenia Emantayev { 451e7dbeba8SJack Morgenstein u64 out_param = 0; 452ffe455adSEugenia Emantayev 453ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 454acddd5ddSJack Morgenstein if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 455acddd5ddSJack Morgenstein (void) mlx4_cmd_imm(dev, mac, &out_param, 456acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_MAC, 457acddd5ddSJack Morgenstein RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 458acddd5ddSJack Morgenstein MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 459acddd5ddSJack Morgenstein } else { 460acddd5ddSJack Morgenstein /* use old unregister mac format */ 461ffe455adSEugenia Emantayev set_param_l(&out_param, port); 462162344edSOr Gerlitz (void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 463ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 464ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 465acddd5ddSJack Morgenstein } 466ffe455adSEugenia Emantayev return; 467ffe455adSEugenia Emantayev } 468ffe455adSEugenia Emantayev __mlx4_unregister_mac(dev, port, mac); 469ffe455adSEugenia Emantayev return; 470ffe455adSEugenia Emantayev } 4715a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_mac); 4725a2cc190SJeff Kirsher 47316a10ffdSYan Burman int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac) 4745a2cc190SJeff Kirsher { 4755a2cc190SJeff Kirsher struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 4765a2cc190SJeff Kirsher struct mlx4_mac_table *table = &info->mac_table; 477ffe455adSEugenia Emantayev int index = qpn - info->base_qpn; 478ffe455adSEugenia Emantayev int err = 0; 4795f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 4805f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 4815f61385dSMoni Shoua struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table; 4825a2cc190SJeff Kirsher 483ffe455adSEugenia Emantayev /* CX1 doesn't support multi-functions */ 4845f61385dSMoni Shoua if (dup) { 4855f61385dSMoni Shoua if (port == 1) { 4865a2cc190SJeff Kirsher mutex_lock(&table->mutex); 48703a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 4885f61385dSMoni Shoua } else { 4895f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 49003a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 4915f61385dSMoni Shoua } 4925f61385dSMoni Shoua } else { 4935f61385dSMoni Shoua mutex_lock(&table->mutex); 4945f61385dSMoni Shoua } 4955a2cc190SJeff Kirsher 4965a2cc190SJeff Kirsher err = validate_index(dev, table, index); 4975a2cc190SJeff Kirsher if (err) 4985a2cc190SJeff Kirsher goto out; 4995a2cc190SJeff Kirsher 5005a2cc190SJeff Kirsher table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); 5015a2cc190SJeff Kirsher 5025a2cc190SJeff Kirsher err = mlx4_set_port_mac_table(dev, port, table->entries); 5035a2cc190SJeff Kirsher if (unlikely(err)) { 504ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 505ffe455adSEugenia Emantayev (unsigned long long) new_mac); 5065a2cc190SJeff Kirsher table->entries[index] = 0; 5075f61385dSMoni Shoua } else { 5085f61385dSMoni Shoua if (dup) { 5095f61385dSMoni Shoua dup_table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); 5105f61385dSMoni Shoua 5115f61385dSMoni Shoua err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries); 5125f61385dSMoni Shoua if (unlikely(err)) { 5135f61385dSMoni Shoua mlx4_err(dev, "Failed adding duplicate MAC: 0x%llx\n", 5145f61385dSMoni Shoua (unsigned long long)new_mac); 5155f61385dSMoni Shoua dup_table->entries[index] = 0; 5165f61385dSMoni Shoua } 5175f61385dSMoni Shoua } 5185a2cc190SJeff Kirsher } 5195a2cc190SJeff Kirsher out: 5205f61385dSMoni Shoua if (dup) { 5215f61385dSMoni Shoua if (port == 2) { 5225a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 5235f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 5245f61385dSMoni Shoua } else { 5255f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 5265f61385dSMoni Shoua mutex_unlock(&table->mutex); 5275f61385dSMoni Shoua } 5285f61385dSMoni Shoua } else { 5295f61385dSMoni Shoua mutex_unlock(&table->mutex); 5305f61385dSMoni Shoua } 5315a2cc190SJeff Kirsher return err; 5325a2cc190SJeff Kirsher } 53316a10ffdSYan Burman EXPORT_SYMBOL_GPL(__mlx4_replace_mac); 534ffe455adSEugenia Emantayev 5355a2cc190SJeff Kirsher static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, 5365a2cc190SJeff Kirsher __be32 *entries) 5375a2cc190SJeff Kirsher { 5385a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 5395a2cc190SJeff Kirsher u32 in_mod; 5405a2cc190SJeff Kirsher int err; 5415a2cc190SJeff Kirsher 5425a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 5435a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 5445a2cc190SJeff Kirsher return PTR_ERR(mailbox); 5455a2cc190SJeff Kirsher 5465a2cc190SJeff Kirsher memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); 5475a2cc190SJeff Kirsher in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; 548a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 549a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 550a130b590SIdo Shamay MLX4_CMD_NATIVE); 5515a2cc190SJeff Kirsher 5525a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 5535a2cc190SJeff Kirsher 5545a2cc190SJeff Kirsher return err; 5555a2cc190SJeff Kirsher } 5565a2cc190SJeff Kirsher 5575a2cc190SJeff Kirsher int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx) 5585a2cc190SJeff Kirsher { 5595a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 5605a2cc190SJeff Kirsher int i; 5615a2cc190SJeff Kirsher 5625a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) { 5635a2cc190SJeff Kirsher if (table->refs[i] && 5645a2cc190SJeff Kirsher (vid == (MLX4_VLAN_MASK & 5655a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 5665a2cc190SJeff Kirsher /* VLAN already registered, increase reference count */ 5675a2cc190SJeff Kirsher *idx = i; 5685a2cc190SJeff Kirsher return 0; 5695a2cc190SJeff Kirsher } 5705a2cc190SJeff Kirsher } 5715a2cc190SJeff Kirsher 5725a2cc190SJeff Kirsher return -ENOENT; 5735a2cc190SJeff Kirsher } 5745a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan); 5755a2cc190SJeff Kirsher 5763f7fb021SRony Efraim int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, 577ffe455adSEugenia Emantayev int *index) 5785a2cc190SJeff Kirsher { 5795a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 5805a2cc190SJeff Kirsher int i, err = 0; 5815a2cc190SJeff Kirsher int free = -1; 5825f61385dSMoni Shoua int free_for_dup = -1; 5835f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 5845f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 5855f61385dSMoni Shoua struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table; 5865f61385dSMoni Shoua bool need_mf_bond = mlx4_need_mf_bond(dev); 5875f61385dSMoni Shoua bool can_mf_bond = true; 5885a2cc190SJeff Kirsher 5895f61385dSMoni Shoua mlx4_dbg(dev, "Registering VLAN: %d for port %d %s duplicate\n", 5905f61385dSMoni Shoua vlan, port, 5915f61385dSMoni Shoua dup ? "with" : "without"); 5925f61385dSMoni Shoua 5935f61385dSMoni Shoua if (need_mf_bond) { 5945f61385dSMoni Shoua if (port == 1) { 5955a2cc190SJeff Kirsher mutex_lock(&table->mutex); 59603a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 5975f61385dSMoni Shoua } else { 5985f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 59903a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 6005f61385dSMoni Shoua } 6015f61385dSMoni Shoua } else { 6025f61385dSMoni Shoua mutex_lock(&table->mutex); 6035f61385dSMoni Shoua } 604e72ebf5aSYevgeny Petrilin 605e72ebf5aSYevgeny Petrilin if (table->total == table->max) { 606e72ebf5aSYevgeny Petrilin /* No free vlan entries */ 607e72ebf5aSYevgeny Petrilin err = -ENOSPC; 608e72ebf5aSYevgeny Petrilin goto out; 609e72ebf5aSYevgeny Petrilin } 610e72ebf5aSYevgeny Petrilin 6115f61385dSMoni Shoua if (need_mf_bond) { 6125f61385dSMoni Shoua int index_at_port = -1; 6135f61385dSMoni Shoua int index_at_dup_port = -1; 6145f61385dSMoni Shoua 6155a2cc190SJeff Kirsher for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 6165f61385dSMoni Shoua if ((vlan == (MLX4_VLAN_MASK & be32_to_cpu(table->entries[i])))) 6175f61385dSMoni Shoua index_at_port = i; 6185f61385dSMoni Shoua if ((vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i])))) 6195f61385dSMoni Shoua index_at_dup_port = i; 6205f61385dSMoni Shoua } 6215f61385dSMoni Shoua /* check that same vlan is not in the tables at different indices */ 6225f61385dSMoni Shoua if ((index_at_port != index_at_dup_port) && 6235f61385dSMoni Shoua (index_at_port >= 0) && 6245f61385dSMoni Shoua (index_at_dup_port >= 0)) 6255f61385dSMoni Shoua can_mf_bond = false; 6265f61385dSMoni Shoua 6275f61385dSMoni Shoua /* If the vlan is already in the primary table, the slot must be 6285f61385dSMoni Shoua * available in the duplicate table as well. 6295f61385dSMoni Shoua */ 6305f61385dSMoni Shoua if (index_at_port >= 0 && index_at_dup_port < 0 && 6315f61385dSMoni Shoua dup_table->refs[index_at_port]) { 6325f61385dSMoni Shoua can_mf_bond = false; 6335f61385dSMoni Shoua } 6345f61385dSMoni Shoua /* If the vlan is already in the duplicate table, check that the 6355f61385dSMoni Shoua * corresponding index is not occupied in the primary table, or 6365f61385dSMoni Shoua * the primary table already contains the vlan at the same index. 6375f61385dSMoni Shoua * Otherwise, you cannot bond (primary contains a different vlan 6385f61385dSMoni Shoua * at that index). 6395f61385dSMoni Shoua */ 6405f61385dSMoni Shoua if (index_at_dup_port >= 0) { 6415f61385dSMoni Shoua if (!table->refs[index_at_dup_port] || 6425f61385dSMoni Shoua (vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[index_at_dup_port])))) 6435f61385dSMoni Shoua free_for_dup = index_at_dup_port; 6445f61385dSMoni Shoua else 6455f61385dSMoni Shoua can_mf_bond = false; 6465f61385dSMoni Shoua } 6475a2cc190SJeff Kirsher } 6485a2cc190SJeff Kirsher 6495f61385dSMoni Shoua for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 6505f61385dSMoni Shoua if (!table->refs[i]) { 6515f61385dSMoni Shoua if (free < 0) 6525f61385dSMoni Shoua free = i; 6535f61385dSMoni Shoua if (free_for_dup < 0 && need_mf_bond && can_mf_bond) { 6545f61385dSMoni Shoua if (!dup_table->refs[i]) 6555f61385dSMoni Shoua free_for_dup = i; 6565f61385dSMoni Shoua } 6575f61385dSMoni Shoua } 6585f61385dSMoni Shoua 6595f61385dSMoni Shoua if ((table->refs[i] || table->is_dup[i]) && 6605a2cc190SJeff Kirsher (vlan == (MLX4_VLAN_MASK & 6615a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 6625a2cc190SJeff Kirsher /* Vlan already registered, increase references count */ 6635f61385dSMoni Shoua mlx4_dbg(dev, "vlan %u is already registered.\n", vlan); 6645a2cc190SJeff Kirsher *index = i; 6655a2cc190SJeff Kirsher ++table->refs[i]; 6665f61385dSMoni Shoua if (dup) { 6675f61385dSMoni Shoua u16 dup_vlan = MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i]); 6685f61385dSMoni Shoua 6695f61385dSMoni Shoua if (dup_vlan != vlan || !dup_table->is_dup[i]) { 6705f61385dSMoni Shoua mlx4_warn(dev, "register vlan: expected duplicate vlan %u on port %d index %d\n", 6715f61385dSMoni Shoua vlan, dup_port, i); 6725f61385dSMoni Shoua } 6735f61385dSMoni Shoua } 6745a2cc190SJeff Kirsher goto out; 6755a2cc190SJeff Kirsher } 6765a2cc190SJeff Kirsher } 6775a2cc190SJeff Kirsher 6785f61385dSMoni Shoua if (need_mf_bond && (free_for_dup < 0)) { 6795f61385dSMoni Shoua if (dup) { 6805f61385dSMoni Shoua mlx4_warn(dev, "Fail to allocate duplicate VLAN table entry\n"); 6815f61385dSMoni Shoua mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n"); 6825f61385dSMoni Shoua dup = false; 6835f61385dSMoni Shoua } 6845f61385dSMoni Shoua can_mf_bond = false; 6855f61385dSMoni Shoua } 6865f61385dSMoni Shoua 6875f61385dSMoni Shoua if (need_mf_bond && can_mf_bond) 6885f61385dSMoni Shoua free = free_for_dup; 6895f61385dSMoni Shoua 6905a2cc190SJeff Kirsher if (free < 0) { 6915a2cc190SJeff Kirsher err = -ENOMEM; 6925a2cc190SJeff Kirsher goto out; 6935a2cc190SJeff Kirsher } 6945a2cc190SJeff Kirsher 695ffe455adSEugenia Emantayev /* Register new VLAN */ 6965a2cc190SJeff Kirsher table->refs[free] = 1; 6975f61385dSMoni Shoua table->is_dup[free] = false; 6985a2cc190SJeff Kirsher table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 6995a2cc190SJeff Kirsher 7005a2cc190SJeff Kirsher err = mlx4_set_port_vlan_table(dev, port, table->entries); 7015a2cc190SJeff Kirsher if (unlikely(err)) { 7025a2cc190SJeff Kirsher mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); 7035a2cc190SJeff Kirsher table->refs[free] = 0; 7045a2cc190SJeff Kirsher table->entries[free] = 0; 7055a2cc190SJeff Kirsher goto out; 7065a2cc190SJeff Kirsher } 7075f61385dSMoni Shoua ++table->total; 7085f61385dSMoni Shoua if (dup) { 7095f61385dSMoni Shoua dup_table->refs[free] = 0; 7105f61385dSMoni Shoua dup_table->is_dup[free] = true; 7115f61385dSMoni Shoua dup_table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 7125f61385dSMoni Shoua 7135f61385dSMoni Shoua err = mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries); 7145f61385dSMoni Shoua if (unlikely(err)) { 7155f61385dSMoni Shoua mlx4_warn(dev, "Failed adding duplicate vlan: %u\n", vlan); 7165f61385dSMoni Shoua dup_table->is_dup[free] = false; 7175f61385dSMoni Shoua dup_table->entries[free] = 0; 7185f61385dSMoni Shoua goto out; 7195f61385dSMoni Shoua } 7205f61385dSMoni Shoua ++dup_table->total; 7215f61385dSMoni Shoua } 7225a2cc190SJeff Kirsher 7235a2cc190SJeff Kirsher *index = free; 7245a2cc190SJeff Kirsher out: 7255f61385dSMoni Shoua if (need_mf_bond) { 7265f61385dSMoni Shoua if (port == 2) { 7275a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 7285f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 7295f61385dSMoni Shoua } else { 7305f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 7315f61385dSMoni Shoua mutex_unlock(&table->mutex); 7325f61385dSMoni Shoua } 7335f61385dSMoni Shoua } else { 7345f61385dSMoni Shoua mutex_unlock(&table->mutex); 7355f61385dSMoni Shoua } 7365a2cc190SJeff Kirsher return err; 7375a2cc190SJeff Kirsher } 738ffe455adSEugenia Emantayev 739ffe455adSEugenia Emantayev int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) 740ffe455adSEugenia Emantayev { 741e7dbeba8SJack Morgenstein u64 out_param = 0; 742ffe455adSEugenia Emantayev int err; 743ffe455adSEugenia Emantayev 744162226a1SJack Morgenstein if (vlan > 4095) 745162226a1SJack Morgenstein return -EINVAL; 746162226a1SJack Morgenstein 747ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 748acddd5ddSJack Morgenstein err = mlx4_cmd_imm(dev, vlan, &out_param, 749acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN, 750ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 751ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 752ffe455adSEugenia Emantayev if (!err) 753ffe455adSEugenia Emantayev *index = get_param_l(&out_param); 754ffe455adSEugenia Emantayev 755ffe455adSEugenia Emantayev return err; 756ffe455adSEugenia Emantayev } 757ffe455adSEugenia Emantayev return __mlx4_register_vlan(dev, port, vlan, index); 758ffe455adSEugenia Emantayev } 7595a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_register_vlan); 7605a2cc190SJeff Kirsher 7612009d005SJack Morgenstein void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 7625a2cc190SJeff Kirsher { 7635a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 7642009d005SJack Morgenstein int index; 7655f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev); 7665f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1; 7675f61385dSMoni Shoua struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table; 7682009d005SJack Morgenstein 7695f61385dSMoni Shoua if (dup) { 7705f61385dSMoni Shoua if (port == 1) { 7712009d005SJack Morgenstein mutex_lock(&table->mutex); 77203a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING); 7735f61385dSMoni Shoua } else { 7745f61385dSMoni Shoua mutex_lock(&dup_table->mutex); 77503a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING); 7765f61385dSMoni Shoua } 7775f61385dSMoni Shoua } else { 7785f61385dSMoni Shoua mutex_lock(&table->mutex); 7795f61385dSMoni Shoua } 7805f61385dSMoni Shoua 7812009d005SJack Morgenstein if (mlx4_find_cached_vlan(dev, port, vlan, &index)) { 7822009d005SJack Morgenstein mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan); 7832009d005SJack Morgenstein goto out; 7842009d005SJack Morgenstein } 7855a2cc190SJeff Kirsher 7865a2cc190SJeff Kirsher if (index < MLX4_VLAN_REGULAR) { 7875a2cc190SJeff Kirsher mlx4_warn(dev, "Trying to free special vlan index %d\n", index); 7885a2cc190SJeff Kirsher goto out; 7895a2cc190SJeff Kirsher } 7902009d005SJack Morgenstein 7915f61385dSMoni Shoua if (--table->refs[index] || table->is_dup[index]) { 7921a91de28SJoe Perches mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n", 7931a91de28SJoe Perches table->refs[index], index); 7945f61385dSMoni Shoua if (!table->refs[index]) 7955f61385dSMoni Shoua dup_table->is_dup[index] = false; 7965a2cc190SJeff Kirsher goto out; 7975a2cc190SJeff Kirsher } 7985a2cc190SJeff Kirsher table->entries[index] = 0; 7995f61385dSMoni Shoua if (mlx4_set_port_vlan_table(dev, port, table->entries)) 8005f61385dSMoni Shoua mlx4_warn(dev, "Fail to set vlan in port %d during unregister\n", port); 8015a2cc190SJeff Kirsher --table->total; 8025f61385dSMoni Shoua if (dup) { 8035f61385dSMoni Shoua dup_table->is_dup[index] = false; 8045f61385dSMoni Shoua if (dup_table->refs[index]) 8055f61385dSMoni Shoua goto out; 8065f61385dSMoni Shoua dup_table->entries[index] = 0; 8075f61385dSMoni Shoua if (mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries)) 8085f61385dSMoni Shoua mlx4_warn(dev, "Fail to set vlan in duplicate port %d during unregister\n", dup_port); 8095f61385dSMoni Shoua --dup_table->total; 8105f61385dSMoni Shoua } 8115a2cc190SJeff Kirsher out: 8125f61385dSMoni Shoua if (dup) { 8135f61385dSMoni Shoua if (port == 2) { 8145a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 8155f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 8165f61385dSMoni Shoua } else { 8175f61385dSMoni Shoua mutex_unlock(&dup_table->mutex); 8185f61385dSMoni Shoua mutex_unlock(&table->mutex); 8195f61385dSMoni Shoua } 8205f61385dSMoni Shoua } else { 8215f61385dSMoni Shoua mutex_unlock(&table->mutex); 8225f61385dSMoni Shoua } 8235a2cc190SJeff Kirsher } 824ffe455adSEugenia Emantayev 8252009d005SJack Morgenstein void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 826ffe455adSEugenia Emantayev { 827162226a1SJack Morgenstein u64 out_param = 0; 828ffe455adSEugenia Emantayev 829ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 8302009d005SJack Morgenstein (void) mlx4_cmd_imm(dev, vlan, &out_param, 831acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN, 832162226a1SJack Morgenstein RES_OP_RESERVE_AND_MAP, 833ffe455adSEugenia Emantayev MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, 834ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 835ffe455adSEugenia Emantayev return; 836ffe455adSEugenia Emantayev } 8372009d005SJack Morgenstein __mlx4_unregister_vlan(dev, port, vlan); 838ffe455adSEugenia Emantayev } 8395a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_vlan); 8405a2cc190SJeff Kirsher 8415f61385dSMoni Shoua int mlx4_bond_mac_table(struct mlx4_dev *dev) 8425f61385dSMoni Shoua { 8435f61385dSMoni Shoua struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table; 8445f61385dSMoni Shoua struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table; 8455f61385dSMoni Shoua int ret = 0; 8465f61385dSMoni Shoua int i; 8475f61385dSMoni Shoua bool update1 = false; 8485f61385dSMoni Shoua bool update2 = false; 8495f61385dSMoni Shoua 8505f61385dSMoni Shoua mutex_lock(&t1->mutex); 8515f61385dSMoni Shoua mutex_lock(&t2->mutex); 8525f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 8535f61385dSMoni Shoua if ((t1->entries[i] != t2->entries[i]) && 8545f61385dSMoni Shoua t1->entries[i] && t2->entries[i]) { 8555f61385dSMoni Shoua mlx4_warn(dev, "can't duplicate entry %d in mac table\n", i); 8565f61385dSMoni Shoua ret = -EINVAL; 8575f61385dSMoni Shoua goto unlock; 8585f61385dSMoni Shoua } 8595f61385dSMoni Shoua } 8605f61385dSMoni Shoua 8615f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 8625f61385dSMoni Shoua if (t1->entries[i] && !t2->entries[i]) { 8635f61385dSMoni Shoua t2->entries[i] = t1->entries[i]; 8645f61385dSMoni Shoua t2->is_dup[i] = true; 8655f61385dSMoni Shoua update2 = true; 8665f61385dSMoni Shoua } else if (!t1->entries[i] && t2->entries[i]) { 8675f61385dSMoni Shoua t1->entries[i] = t2->entries[i]; 8685f61385dSMoni Shoua t1->is_dup[i] = true; 8695f61385dSMoni Shoua update1 = true; 8705f61385dSMoni Shoua } else if (t1->entries[i] && t2->entries[i]) { 8715f61385dSMoni Shoua t1->is_dup[i] = true; 8725f61385dSMoni Shoua t2->is_dup[i] = true; 8735f61385dSMoni Shoua } 8745f61385dSMoni Shoua } 8755f61385dSMoni Shoua 8765f61385dSMoni Shoua if (update1) { 8775f61385dSMoni Shoua ret = mlx4_set_port_mac_table(dev, 1, t1->entries); 8785f61385dSMoni Shoua if (ret) 8795f61385dSMoni Shoua mlx4_warn(dev, "failed to set MAC table for port 1 (%d)\n", ret); 8805f61385dSMoni Shoua } 8815f61385dSMoni Shoua if (!ret && update2) { 8825f61385dSMoni Shoua ret = mlx4_set_port_mac_table(dev, 2, t2->entries); 8835f61385dSMoni Shoua if (ret) 8845f61385dSMoni Shoua mlx4_warn(dev, "failed to set MAC table for port 2 (%d)\n", ret); 8855f61385dSMoni Shoua } 8865f61385dSMoni Shoua 8875f61385dSMoni Shoua if (ret) 8885f61385dSMoni Shoua mlx4_warn(dev, "failed to create mirror MAC tables\n"); 8895f61385dSMoni Shoua unlock: 8905f61385dSMoni Shoua mutex_unlock(&t2->mutex); 8915f61385dSMoni Shoua mutex_unlock(&t1->mutex); 8925f61385dSMoni Shoua return ret; 8935f61385dSMoni Shoua } 8945f61385dSMoni Shoua 8955f61385dSMoni Shoua int mlx4_unbond_mac_table(struct mlx4_dev *dev) 8965f61385dSMoni Shoua { 8975f61385dSMoni Shoua struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table; 8985f61385dSMoni Shoua struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table; 8995f61385dSMoni Shoua int ret = 0; 9005f61385dSMoni Shoua int ret1; 9015f61385dSMoni Shoua int i; 9025f61385dSMoni Shoua bool update1 = false; 9035f61385dSMoni Shoua bool update2 = false; 9045f61385dSMoni Shoua 9055f61385dSMoni Shoua mutex_lock(&t1->mutex); 9065f61385dSMoni Shoua mutex_lock(&t2->mutex); 9075f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 9085f61385dSMoni Shoua if (t1->entries[i] != t2->entries[i]) { 9095f61385dSMoni Shoua mlx4_warn(dev, "mac table is in an unexpected state when trying to unbond\n"); 9105f61385dSMoni Shoua ret = -EINVAL; 9115f61385dSMoni Shoua goto unlock; 9125f61385dSMoni Shoua } 9135f61385dSMoni Shoua } 9145f61385dSMoni Shoua 9155f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 9165f61385dSMoni Shoua if (!t1->entries[i]) 9175f61385dSMoni Shoua continue; 9185f61385dSMoni Shoua t1->is_dup[i] = false; 9195f61385dSMoni Shoua if (!t1->refs[i]) { 9205f61385dSMoni Shoua t1->entries[i] = 0; 9215f61385dSMoni Shoua update1 = true; 9225f61385dSMoni Shoua } 9235f61385dSMoni Shoua t2->is_dup[i] = false; 9245f61385dSMoni Shoua if (!t2->refs[i]) { 9255f61385dSMoni Shoua t2->entries[i] = 0; 9265f61385dSMoni Shoua update2 = true; 9275f61385dSMoni Shoua } 9285f61385dSMoni Shoua } 9295f61385dSMoni Shoua 9305f61385dSMoni Shoua if (update1) { 9315f61385dSMoni Shoua ret = mlx4_set_port_mac_table(dev, 1, t1->entries); 9325f61385dSMoni Shoua if (ret) 9335f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror MAC tables for port 1(%d)\n", ret); 9345f61385dSMoni Shoua } 9355f61385dSMoni Shoua if (update2) { 9365f61385dSMoni Shoua ret1 = mlx4_set_port_mac_table(dev, 2, t2->entries); 9375f61385dSMoni Shoua if (ret1) { 9385f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror MAC tables for port 2(%d)\n", ret1); 9395f61385dSMoni Shoua ret = ret1; 9405f61385dSMoni Shoua } 9415f61385dSMoni Shoua } 9425f61385dSMoni Shoua unlock: 9435f61385dSMoni Shoua mutex_unlock(&t2->mutex); 9445f61385dSMoni Shoua mutex_unlock(&t1->mutex); 9455f61385dSMoni Shoua return ret; 9465f61385dSMoni Shoua } 9475f61385dSMoni Shoua 9485f61385dSMoni Shoua int mlx4_bond_vlan_table(struct mlx4_dev *dev) 9495f61385dSMoni Shoua { 9505f61385dSMoni Shoua struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table; 9515f61385dSMoni Shoua struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table; 9525f61385dSMoni Shoua int ret = 0; 9535f61385dSMoni Shoua int i; 9545f61385dSMoni Shoua bool update1 = false; 9555f61385dSMoni Shoua bool update2 = false; 9565f61385dSMoni Shoua 9575f61385dSMoni Shoua mutex_lock(&t1->mutex); 9585f61385dSMoni Shoua mutex_lock(&t2->mutex); 9595f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 9605f61385dSMoni Shoua if ((t1->entries[i] != t2->entries[i]) && 9615f61385dSMoni Shoua t1->entries[i] && t2->entries[i]) { 9625f61385dSMoni Shoua mlx4_warn(dev, "can't duplicate entry %d in vlan table\n", i); 9635f61385dSMoni Shoua ret = -EINVAL; 9645f61385dSMoni Shoua goto unlock; 9655f61385dSMoni Shoua } 9665f61385dSMoni Shoua } 9675f61385dSMoni Shoua 9685f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 9695f61385dSMoni Shoua if (t1->entries[i] && !t2->entries[i]) { 9705f61385dSMoni Shoua t2->entries[i] = t1->entries[i]; 9715f61385dSMoni Shoua t2->is_dup[i] = true; 9725f61385dSMoni Shoua update2 = true; 9735f61385dSMoni Shoua } else if (!t1->entries[i] && t2->entries[i]) { 9745f61385dSMoni Shoua t1->entries[i] = t2->entries[i]; 9755f61385dSMoni Shoua t1->is_dup[i] = true; 9765f61385dSMoni Shoua update1 = true; 9775f61385dSMoni Shoua } else if (t1->entries[i] && t2->entries[i]) { 9785f61385dSMoni Shoua t1->is_dup[i] = true; 9795f61385dSMoni Shoua t2->is_dup[i] = true; 9805f61385dSMoni Shoua } 9815f61385dSMoni Shoua } 9825f61385dSMoni Shoua 9835f61385dSMoni Shoua if (update1) { 9845f61385dSMoni Shoua ret = mlx4_set_port_vlan_table(dev, 1, t1->entries); 9855f61385dSMoni Shoua if (ret) 9865f61385dSMoni Shoua mlx4_warn(dev, "failed to set VLAN table for port 1 (%d)\n", ret); 9875f61385dSMoni Shoua } 9885f61385dSMoni Shoua if (!ret && update2) { 9895f61385dSMoni Shoua ret = mlx4_set_port_vlan_table(dev, 2, t2->entries); 9905f61385dSMoni Shoua if (ret) 9915f61385dSMoni Shoua mlx4_warn(dev, "failed to set VLAN table for port 2 (%d)\n", ret); 9925f61385dSMoni Shoua } 9935f61385dSMoni Shoua 9945f61385dSMoni Shoua if (ret) 9955f61385dSMoni Shoua mlx4_warn(dev, "failed to create mirror VLAN tables\n"); 9965f61385dSMoni Shoua unlock: 9975f61385dSMoni Shoua mutex_unlock(&t2->mutex); 9985f61385dSMoni Shoua mutex_unlock(&t1->mutex); 9995f61385dSMoni Shoua return ret; 10005f61385dSMoni Shoua } 10015f61385dSMoni Shoua 10025f61385dSMoni Shoua int mlx4_unbond_vlan_table(struct mlx4_dev *dev) 10035f61385dSMoni Shoua { 10045f61385dSMoni Shoua struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table; 10055f61385dSMoni Shoua struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table; 10065f61385dSMoni Shoua int ret = 0; 10075f61385dSMoni Shoua int ret1; 10085f61385dSMoni Shoua int i; 10095f61385dSMoni Shoua bool update1 = false; 10105f61385dSMoni Shoua bool update2 = false; 10115f61385dSMoni Shoua 10125f61385dSMoni Shoua mutex_lock(&t1->mutex); 10135f61385dSMoni Shoua mutex_lock(&t2->mutex); 10145f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 10155f61385dSMoni Shoua if (t1->entries[i] != t2->entries[i]) { 10165f61385dSMoni Shoua mlx4_warn(dev, "vlan table is in an unexpected state when trying to unbond\n"); 10175f61385dSMoni Shoua ret = -EINVAL; 10185f61385dSMoni Shoua goto unlock; 10195f61385dSMoni Shoua } 10205f61385dSMoni Shoua } 10215f61385dSMoni Shoua 10225f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 10235f61385dSMoni Shoua if (!t1->entries[i]) 10245f61385dSMoni Shoua continue; 10255f61385dSMoni Shoua t1->is_dup[i] = false; 10265f61385dSMoni Shoua if (!t1->refs[i]) { 10275f61385dSMoni Shoua t1->entries[i] = 0; 10285f61385dSMoni Shoua update1 = true; 10295f61385dSMoni Shoua } 10305f61385dSMoni Shoua t2->is_dup[i] = false; 10315f61385dSMoni Shoua if (!t2->refs[i]) { 10325f61385dSMoni Shoua t2->entries[i] = 0; 10335f61385dSMoni Shoua update2 = true; 10345f61385dSMoni Shoua } 10355f61385dSMoni Shoua } 10365f61385dSMoni Shoua 10375f61385dSMoni Shoua if (update1) { 10385f61385dSMoni Shoua ret = mlx4_set_port_vlan_table(dev, 1, t1->entries); 10395f61385dSMoni Shoua if (ret) 10405f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror VLAN tables for port 1(%d)\n", ret); 10415f61385dSMoni Shoua } 10425f61385dSMoni Shoua if (update2) { 10435f61385dSMoni Shoua ret1 = mlx4_set_port_vlan_table(dev, 2, t2->entries); 10445f61385dSMoni Shoua if (ret1) { 10455f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror VLAN tables for port 2(%d)\n", ret1); 10465f61385dSMoni Shoua ret = ret1; 10475f61385dSMoni Shoua } 10485f61385dSMoni Shoua } 10495f61385dSMoni Shoua unlock: 10505f61385dSMoni Shoua mutex_unlock(&t2->mutex); 10515f61385dSMoni Shoua mutex_unlock(&t1->mutex); 10525f61385dSMoni Shoua return ret; 10535f61385dSMoni Shoua } 10545f61385dSMoni Shoua 10555a2cc190SJeff Kirsher int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) 10565a2cc190SJeff Kirsher { 10575a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *inmailbox, *outmailbox; 10585a2cc190SJeff Kirsher u8 *inbuf, *outbuf; 10595a2cc190SJeff Kirsher int err; 10605a2cc190SJeff Kirsher 10615a2cc190SJeff Kirsher inmailbox = mlx4_alloc_cmd_mailbox(dev); 10625a2cc190SJeff Kirsher if (IS_ERR(inmailbox)) 10635a2cc190SJeff Kirsher return PTR_ERR(inmailbox); 10645a2cc190SJeff Kirsher 10655a2cc190SJeff Kirsher outmailbox = mlx4_alloc_cmd_mailbox(dev); 10665a2cc190SJeff Kirsher if (IS_ERR(outmailbox)) { 10675a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 10685a2cc190SJeff Kirsher return PTR_ERR(outmailbox); 10695a2cc190SJeff Kirsher } 10705a2cc190SJeff Kirsher 10715a2cc190SJeff Kirsher inbuf = inmailbox->buf; 10725a2cc190SJeff Kirsher outbuf = outmailbox->buf; 10735a2cc190SJeff Kirsher inbuf[0] = 1; 10745a2cc190SJeff Kirsher inbuf[1] = 1; 10755a2cc190SJeff Kirsher inbuf[2] = 1; 10765a2cc190SJeff Kirsher inbuf[3] = 1; 10775a2cc190SJeff Kirsher *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015); 10785a2cc190SJeff Kirsher *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); 10795a2cc190SJeff Kirsher 10805a2cc190SJeff Kirsher err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, 1081f9baff50SJack Morgenstein MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 1082f9baff50SJack Morgenstein MLX4_CMD_NATIVE); 10835a2cc190SJeff Kirsher if (!err) 10845a2cc190SJeff Kirsher *caps = *(__be32 *) (outbuf + 84); 10855a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 10865a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, outmailbox); 10875a2cc190SJeff Kirsher return err; 10885a2cc190SJeff Kirsher } 10899cd59352SJack Morgenstein static struct mlx4_roce_gid_entry zgid_entry; 10905a2cc190SJeff Kirsher 1091449fc488SMatan Barak int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port) 1092b6ffaeffSJack Morgenstein { 1093449fc488SMatan Barak int vfs; 1094449fc488SMatan Barak int slave_gid = slave; 1095449fc488SMatan Barak unsigned i; 1096449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 1097449fc488SMatan Barak struct mlx4_active_ports actv_ports; 1098449fc488SMatan Barak unsigned max_port_p_one; 1099449fc488SMatan Barak 1100b6ffaeffSJack Morgenstein if (slave == 0) 1101b6ffaeffSJack Morgenstein return MLX4_ROCE_PF_GIDS; 1102449fc488SMatan Barak 1103449fc488SMatan Barak /* Slave is a VF */ 1104449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1105449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave); 1106449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 1107449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 1108449fc488SMatan Barak 1109449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 1110449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 1111449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 1112449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 1113449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1114449fc488SMatan Barak if (i == port) 1115449fc488SMatan Barak continue; 1116449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 1117449fc488SMatan Barak dev, &exclusive_ports); 1118449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 1119872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1120449fc488SMatan Barak } 1121872bf2fbSYishai Hadas vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; 1122449fc488SMatan Barak if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs)) 1123449fc488SMatan Barak return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1; 1124449fc488SMatan Barak return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs; 1125b6ffaeffSJack Morgenstein } 1126b6ffaeffSJack Morgenstein 1127449fc488SMatan Barak int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port) 1128b6ffaeffSJack Morgenstein { 1129b6ffaeffSJack Morgenstein int gids; 1130449fc488SMatan Barak unsigned i; 1131449fc488SMatan Barak int slave_gid = slave; 1132b6ffaeffSJack Morgenstein int vfs; 1133b6ffaeffSJack Morgenstein 1134449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 1135449fc488SMatan Barak struct mlx4_active_ports actv_ports; 1136449fc488SMatan Barak unsigned max_port_p_one; 1137b6ffaeffSJack Morgenstein 1138b6ffaeffSJack Morgenstein if (slave == 0) 1139b6ffaeffSJack Morgenstein return 0; 1140b6ffaeffSJack Morgenstein 1141449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1142449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave); 1143449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 1144449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 1145449fc488SMatan Barak 1146449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 1147449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 1148449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 1149449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 1150449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1151449fc488SMatan Barak if (i == port) 1152449fc488SMatan Barak continue; 1153449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 1154449fc488SMatan Barak dev, &exclusive_ports); 1155449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 1156872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1157b6ffaeffSJack Morgenstein } 1158449fc488SMatan Barak gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 1159872bf2fbSYishai Hadas vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; 1160449fc488SMatan Barak if (slave_gid <= gids % vfs) 1161449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1); 1162449fc488SMatan Barak 1163449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + (gids % vfs) + 1164449fc488SMatan Barak ((gids / vfs) * (slave_gid - 1)); 1165449fc488SMatan Barak } 1166449fc488SMatan Barak EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix); 1167b6ffaeffSJack Morgenstein 1168111c6094SJack Morgenstein static int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave, 1169111c6094SJack Morgenstein int port, struct mlx4_cmd_mailbox *mailbox) 1170111c6094SJack Morgenstein { 1171111c6094SJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_mbox; 1172111c6094SJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 1173111c6094SJack Morgenstein int num_gids, base, offset; 1174111c6094SJack Morgenstein int i, err; 1175111c6094SJack Morgenstein 1176111c6094SJack Morgenstein num_gids = mlx4_get_slave_num_gids(dev, slave, port); 1177111c6094SJack Morgenstein base = mlx4_get_base_gid_ix(dev, slave, port); 1178111c6094SJack Morgenstein 1179111c6094SJack Morgenstein memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE); 1180111c6094SJack Morgenstein 1181111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex)); 1182111c6094SJack Morgenstein /* Zero-out gids belonging to that slave in the port GID table */ 1183111c6094SJack Morgenstein for (i = 0, offset = base; i < num_gids; offset++, i++) 1184111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 1185111c6094SJack Morgenstein zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE); 1186111c6094SJack Morgenstein 1187111c6094SJack Morgenstein /* Now, copy roce port gids table to mailbox for passing to FW */ 1188111c6094SJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf; 1189111c6094SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 1190111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw, 1191111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw, 1192111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 1193111c6094SJack Morgenstein 1194111c6094SJack Morgenstein err = mlx4_cmd(dev, mailbox->dma, 1195a130b590SIdo Shamay ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8), 1196a130b590SIdo Shamay MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT, 1197a130b590SIdo Shamay MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1198111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 1199111c6094SJack Morgenstein return err; 1200111c6094SJack Morgenstein } 1201111c6094SJack Morgenstein 1202111c6094SJack Morgenstein 1203111c6094SJack Morgenstein void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave) 1204111c6094SJack Morgenstein { 1205111c6094SJack Morgenstein struct mlx4_active_ports actv_ports; 1206111c6094SJack Morgenstein struct mlx4_cmd_mailbox *mailbox; 1207111c6094SJack Morgenstein int num_eth_ports, err; 1208111c6094SJack Morgenstein int i; 1209111c6094SJack Morgenstein 1210872bf2fbSYishai Hadas if (slave < 0 || slave > dev->persist->num_vfs) 1211111c6094SJack Morgenstein return; 1212111c6094SJack Morgenstein 1213111c6094SJack Morgenstein actv_ports = mlx4_get_active_ports(dev, slave); 1214111c6094SJack Morgenstein 1215111c6094SJack Morgenstein for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) { 1216111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) { 1217111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 1218111c6094SJack Morgenstein continue; 1219111c6094SJack Morgenstein num_eth_ports++; 1220111c6094SJack Morgenstein } 1221111c6094SJack Morgenstein } 1222111c6094SJack Morgenstein 1223111c6094SJack Morgenstein if (!num_eth_ports) 1224111c6094SJack Morgenstein return; 1225111c6094SJack Morgenstein 1226111c6094SJack Morgenstein /* have ETH ports. Alloc mailbox for SET_PORT command */ 1227111c6094SJack Morgenstein mailbox = mlx4_alloc_cmd_mailbox(dev); 1228111c6094SJack Morgenstein if (IS_ERR(mailbox)) 1229111c6094SJack Morgenstein return; 1230111c6094SJack Morgenstein 1231111c6094SJack Morgenstein for (i = 0; i < dev->caps.num_ports; i++) { 1232111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) { 1233111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 1234111c6094SJack Morgenstein continue; 1235111c6094SJack Morgenstein err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox); 1236111c6094SJack Morgenstein if (err) 1237111c6094SJack Morgenstein mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n", 1238111c6094SJack Morgenstein slave, i + 1, err); 1239111c6094SJack Morgenstein } 1240111c6094SJack Morgenstein } 1241111c6094SJack Morgenstein 1242111c6094SJack Morgenstein mlx4_free_cmd_mailbox(dev, mailbox); 1243111c6094SJack Morgenstein return; 1244111c6094SJack Morgenstein } 1245111c6094SJack Morgenstein 124640fb4fc1SShaker Daibes static void 1247bf1f9396SShaker Daibes mlx4_en_set_port_mtu(struct mlx4_dev *dev, int slave, int port, 1248bf1f9396SShaker Daibes struct mlx4_set_port_general_context *gen_context) 1249bf1f9396SShaker Daibes { 1250bf1f9396SShaker Daibes struct mlx4_priv *priv = mlx4_priv(dev); 1251bf1f9396SShaker Daibes struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; 1252bf1f9396SShaker Daibes struct mlx4_slave_state *slave_st = &master->slave_state[slave]; 1253bf1f9396SShaker Daibes u16 mtu, prev_mtu; 1254bf1f9396SShaker Daibes 1255bf1f9396SShaker Daibes /* Mtu is configured as the max USER_MTU among all 1256bf1f9396SShaker Daibes * the functions on the port. 1257bf1f9396SShaker Daibes */ 1258bf1f9396SShaker Daibes mtu = be16_to_cpu(gen_context->mtu); 1259bf1f9396SShaker Daibes mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] + 1260bf1f9396SShaker Daibes ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); 1261bf1f9396SShaker Daibes prev_mtu = slave_st->mtu[port]; 1262bf1f9396SShaker Daibes slave_st->mtu[port] = mtu; 1263bf1f9396SShaker Daibes if (mtu > master->max_mtu[port]) 1264bf1f9396SShaker Daibes master->max_mtu[port] = mtu; 1265bf1f9396SShaker Daibes if (mtu < prev_mtu && prev_mtu == master->max_mtu[port]) { 1266bf1f9396SShaker Daibes int i; 1267bf1f9396SShaker Daibes 1268bf1f9396SShaker Daibes slave_st->mtu[port] = mtu; 1269bf1f9396SShaker Daibes master->max_mtu[port] = mtu; 1270bf1f9396SShaker Daibes for (i = 0; i < dev->num_slaves; i++) 1271bf1f9396SShaker Daibes master->max_mtu[port] = 1272bf1f9396SShaker Daibes max_t(u16, master->max_mtu[port], 1273bf1f9396SShaker Daibes master->slave_state[i].mtu[port]); 1274bf1f9396SShaker Daibes } 1275bf1f9396SShaker Daibes gen_context->mtu = cpu_to_be16(master->max_mtu[port]); 1276bf1f9396SShaker Daibes } 1277bf1f9396SShaker Daibes 1278bf1f9396SShaker Daibes static void 127940fb4fc1SShaker Daibes mlx4_en_set_port_user_mtu(struct mlx4_dev *dev, int slave, int port, 128040fb4fc1SShaker Daibes struct mlx4_set_port_general_context *gen_context) 128140fb4fc1SShaker Daibes { 128240fb4fc1SShaker Daibes struct mlx4_priv *priv = mlx4_priv(dev); 128340fb4fc1SShaker Daibes struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; 128440fb4fc1SShaker Daibes struct mlx4_slave_state *slave_st = &master->slave_state[slave]; 128540fb4fc1SShaker Daibes u16 user_mtu, prev_user_mtu; 128640fb4fc1SShaker Daibes 128740fb4fc1SShaker Daibes /* User Mtu is configured as the max USER_MTU among all 128840fb4fc1SShaker Daibes * the functions on the port. 128940fb4fc1SShaker Daibes */ 129040fb4fc1SShaker Daibes user_mtu = be16_to_cpu(gen_context->user_mtu); 129140fb4fc1SShaker Daibes user_mtu = min_t(int, user_mtu, dev->caps.eth_mtu_cap[port]); 129240fb4fc1SShaker Daibes prev_user_mtu = slave_st->user_mtu[port]; 129340fb4fc1SShaker Daibes slave_st->user_mtu[port] = user_mtu; 129440fb4fc1SShaker Daibes if (user_mtu > master->max_user_mtu[port]) 129540fb4fc1SShaker Daibes master->max_user_mtu[port] = user_mtu; 129640fb4fc1SShaker Daibes if (user_mtu < prev_user_mtu && 129740fb4fc1SShaker Daibes prev_user_mtu == master->max_user_mtu[port]) { 129840fb4fc1SShaker Daibes int i; 129940fb4fc1SShaker Daibes 130040fb4fc1SShaker Daibes slave_st->user_mtu[port] = user_mtu; 130140fb4fc1SShaker Daibes master->max_user_mtu[port] = user_mtu; 130240fb4fc1SShaker Daibes for (i = 0; i < dev->num_slaves; i++) 130340fb4fc1SShaker Daibes master->max_user_mtu[port] = 130440fb4fc1SShaker Daibes max_t(u16, master->max_user_mtu[port], 130540fb4fc1SShaker Daibes master->slave_state[i].user_mtu[port]); 130640fb4fc1SShaker Daibes } 130740fb4fc1SShaker Daibes gen_context->user_mtu = cpu_to_be16(master->max_user_mtu[port]); 130840fb4fc1SShaker Daibes } 130940fb4fc1SShaker Daibes 13101f8176f7SShaker Daibes static void 13111f8176f7SShaker Daibes mlx4_en_set_port_global_pause(struct mlx4_dev *dev, int slave, 13121f8176f7SShaker Daibes struct mlx4_set_port_general_context *gen_context) 13131f8176f7SShaker Daibes { 13141f8176f7SShaker Daibes struct mlx4_priv *priv = mlx4_priv(dev); 13151f8176f7SShaker Daibes struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; 13161f8176f7SShaker Daibes 13171f8176f7SShaker Daibes /* Slave cannot change Global Pause configuration */ 13181f8176f7SShaker Daibes if (slave != mlx4_master_func_num(dev) && 13191f8176f7SShaker Daibes (gen_context->pptx != master->pptx || 13201f8176f7SShaker Daibes gen_context->pprx != master->pprx)) { 13211f8176f7SShaker Daibes gen_context->pptx = master->pptx; 13221f8176f7SShaker Daibes gen_context->pprx = master->pprx; 13231f8176f7SShaker Daibes mlx4_warn(dev, "denying Global Pause change for slave:%d\n", 13241f8176f7SShaker Daibes slave); 13251f8176f7SShaker Daibes } else { 13261f8176f7SShaker Daibes master->pptx = gen_context->pptx; 13271f8176f7SShaker Daibes master->pprx = gen_context->pprx; 13281f8176f7SShaker Daibes } 13291f8176f7SShaker Daibes } 13301f8176f7SShaker Daibes 1331ffe455adSEugenia Emantayev static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, 1332ffe455adSEugenia Emantayev u8 op_mod, struct mlx4_cmd_mailbox *inbox) 1333ffe455adSEugenia Emantayev { 1334ffe455adSEugenia Emantayev struct mlx4_priv *priv = mlx4_priv(dev); 1335ffe455adSEugenia Emantayev struct mlx4_port_info *port_info; 1336ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *qpn_context; 1337ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *gen_context; 1338b6ffaeffSJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1; 1339ffe455adSEugenia Emantayev int reset_qkey_viols; 1340ffe455adSEugenia Emantayev int port; 1341ffe455adSEugenia Emantayev int is_eth; 1342b6ffaeffSJack Morgenstein int num_gids; 1343b6ffaeffSJack Morgenstein int base; 1344ffe455adSEugenia Emantayev u32 in_modifier; 1345ffe455adSEugenia Emantayev u32 promisc; 1346ffe455adSEugenia Emantayev int err; 1347b6ffaeffSJack Morgenstein int i, j; 1348b6ffaeffSJack Morgenstein int offset; 1349ffe455adSEugenia Emantayev __be32 agg_cap_mask; 1350ffe455adSEugenia Emantayev __be32 slave_cap_mask; 1351ffe455adSEugenia Emantayev __be32 new_cap_mask; 1352ffe455adSEugenia Emantayev 1353ffe455adSEugenia Emantayev port = in_mod & 0xff; 1354ffe455adSEugenia Emantayev in_modifier = in_mod >> 8; 1355ffe455adSEugenia Emantayev is_eth = op_mod; 1356ffe455adSEugenia Emantayev port_info = &priv->port[port]; 1357ffe455adSEugenia Emantayev 135840fb4fc1SShaker Daibes /* Slaves cannot perform SET_PORT operations, 135940fb4fc1SShaker Daibes * except for changing MTU and USER_MTU. 136040fb4fc1SShaker Daibes */ 1361ffe455adSEugenia Emantayev if (is_eth) { 1362ffe455adSEugenia Emantayev if (slave != dev->caps.function && 13639cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GENERAL && 13649cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GID_TABLE) { 1365ffe455adSEugenia Emantayev mlx4_warn(dev, "denying SET_PORT for slave:%d\n", 1366ffe455adSEugenia Emantayev slave); 1367ffe455adSEugenia Emantayev return -EINVAL; 1368ffe455adSEugenia Emantayev } 1369ffe455adSEugenia Emantayev switch (in_modifier) { 1370ffe455adSEugenia Emantayev case MLX4_SET_PORT_RQP_CALC: 1371ffe455adSEugenia Emantayev qpn_context = inbox->buf; 1372ffe455adSEugenia Emantayev qpn_context->base_qpn = 1373ffe455adSEugenia Emantayev cpu_to_be32(port_info->base_qpn); 1374ffe455adSEugenia Emantayev qpn_context->n_mac = 0x7; 1375ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->promisc) >> 1376ffe455adSEugenia Emantayev SET_PORT_PROMISC_SHIFT; 1377ffe455adSEugenia Emantayev qpn_context->promisc = cpu_to_be32( 1378ffe455adSEugenia Emantayev promisc << SET_PORT_PROMISC_SHIFT | 1379ffe455adSEugenia Emantayev port_info->base_qpn); 1380ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->mcast) >> 1381ffe455adSEugenia Emantayev SET_PORT_MC_PROMISC_SHIFT; 1382ffe455adSEugenia Emantayev qpn_context->mcast = cpu_to_be32( 1383ffe455adSEugenia Emantayev promisc << SET_PORT_MC_PROMISC_SHIFT | 1384ffe455adSEugenia Emantayev port_info->base_qpn); 1385ffe455adSEugenia Emantayev break; 1386ffe455adSEugenia Emantayev case MLX4_SET_PORT_GENERAL: 1387ffe455adSEugenia Emantayev gen_context = inbox->buf; 1388bf1f9396SShaker Daibes 1389bf1f9396SShaker Daibes if (gen_context->flags & MLX4_FLAG_V_MTU_MASK) 1390bf1f9396SShaker Daibes mlx4_en_set_port_mtu(dev, slave, port, 1391bf1f9396SShaker Daibes gen_context); 139240fb4fc1SShaker Daibes 139340fb4fc1SShaker Daibes if (gen_context->flags2 & MLX4_FLAG2_V_USER_MTU_MASK) 139440fb4fc1SShaker Daibes mlx4_en_set_port_user_mtu(dev, slave, port, 139540fb4fc1SShaker Daibes gen_context); 139640fb4fc1SShaker Daibes 13971f8176f7SShaker Daibes if (gen_context->flags & 139873cfb2a2SDan Carpenter (MLX4_FLAG_V_PPRX_MASK | MLX4_FLAG_V_PPTX_MASK)) 13991f8176f7SShaker Daibes mlx4_en_set_port_global_pause(dev, slave, 14001f8176f7SShaker Daibes gen_context); 14011f8176f7SShaker Daibes 1402ffe455adSEugenia Emantayev break; 14039cd59352SJack Morgenstein case MLX4_SET_PORT_GID_TABLE: 1404b6ffaeffSJack Morgenstein /* change to MULTIPLE entries: number of guest's gids 1405b6ffaeffSJack Morgenstein * need a FOR-loop here over number of gids the guest has. 1406b6ffaeffSJack Morgenstein * 1. Check no duplicates in gids passed by slave 1407b6ffaeffSJack Morgenstein */ 1408449fc488SMatan Barak num_gids = mlx4_get_slave_num_gids(dev, slave, port); 1409449fc488SMatan Barak base = mlx4_get_base_gid_ix(dev, slave, port); 1410b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1411b6ffaeffSJack Morgenstein for (i = 0; i < num_gids; gid_entry_mbox++, i++) { 1412b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 1413b6ffaeffSJack Morgenstein sizeof(zgid_entry))) 1414b6ffaeffSJack Morgenstein continue; 1415b6ffaeffSJack Morgenstein gid_entry_mb1 = gid_entry_mbox + 1; 1416b6ffaeffSJack Morgenstein for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) { 1417b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw, 1418b6ffaeffSJack Morgenstein zgid_entry.raw, sizeof(zgid_entry))) 1419b6ffaeffSJack Morgenstein continue; 1420b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw, 1421b6ffaeffSJack Morgenstein sizeof(gid_entry_mbox->raw))) { 1422b6ffaeffSJack Morgenstein /* found duplicate */ 1423b6ffaeffSJack Morgenstein return -EINVAL; 1424b6ffaeffSJack Morgenstein } 1425b6ffaeffSJack Morgenstein } 1426b6ffaeffSJack Morgenstein } 1427b6ffaeffSJack Morgenstein 1428b6ffaeffSJack Morgenstein /* 2. Check that do not have duplicates in OTHER 1429b6ffaeffSJack Morgenstein * entries in the port GID table 1430b6ffaeffSJack Morgenstein */ 1431111c6094SJack Morgenstein 1432111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex)); 14339cd59352SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 1434b6ffaeffSJack Morgenstein if (i >= base && i < base + num_gids) 1435b6ffaeffSJack Morgenstein continue; /* don't compare to slave's current gids */ 1436111c6094SJack Morgenstein gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i]; 1437b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry))) 1438b6ffaeffSJack Morgenstein continue; 1439b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1440b6ffaeffSJack Morgenstein for (j = 0; j < num_gids; gid_entry_mbox++, j++) { 1441b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 1442b6ffaeffSJack Morgenstein sizeof(zgid_entry))) 1443b6ffaeffSJack Morgenstein continue; 1444b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw, 1445b6ffaeffSJack Morgenstein sizeof(gid_entry_tbl->raw))) { 1446b6ffaeffSJack Morgenstein /* found duplicate */ 14471a91de28SJoe Perches mlx4_warn(dev, "requested gid entry for slave:%d is a duplicate of gid at index %d\n", 14489cd59352SJack Morgenstein slave, i); 1449111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 1450b6ffaeffSJack Morgenstein return -EINVAL; 14519cd59352SJack Morgenstein } 14529cd59352SJack Morgenstein } 14539cd59352SJack Morgenstein } 1454b6ffaeffSJack Morgenstein 1455b6ffaeffSJack Morgenstein /* insert slave GIDs with memcpy, starting at slave's base index */ 1456b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1457b6ffaeffSJack Morgenstein for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++) 1458111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 1459111c6094SJack Morgenstein gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE); 1460b6ffaeffSJack Morgenstein 1461b6ffaeffSJack Morgenstein /* Now, copy roce port gids table to current mailbox for passing to FW */ 1462b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 1463b6ffaeffSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 1464111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw, 1465111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw, 1466111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 1467b6ffaeffSJack Morgenstein 1468111c6094SJack Morgenstein err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 1469111c6094SJack Morgenstein MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1470111c6094SJack Morgenstein MLX4_CMD_NATIVE); 1471111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 1472111c6094SJack Morgenstein return err; 1473ffe455adSEugenia Emantayev } 1474111c6094SJack Morgenstein 1475111c6094SJack Morgenstein return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 1476ffe455adSEugenia Emantayev MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1477ffe455adSEugenia Emantayev MLX4_CMD_NATIVE); 1478ffe455adSEugenia Emantayev } 1479ffe455adSEugenia Emantayev 148051af33cfSIdo Shamay /* Slaves are not allowed to SET_PORT beacon (LED) blink */ 148151af33cfSIdo Shamay if (op_mod == MLX4_SET_PORT_BEACON_OPCODE) { 148251af33cfSIdo Shamay mlx4_warn(dev, "denying SET_PORT Beacon slave:%d\n", slave); 148351af33cfSIdo Shamay return -EPERM; 148451af33cfSIdo Shamay } 148551af33cfSIdo Shamay 1486ffe455adSEugenia Emantayev /* For IB, we only consider: 1487ffe455adSEugenia Emantayev * - The capability mask, which is set to the aggregate of all 1488ffe455adSEugenia Emantayev * slave function capabilities 1489ffe455adSEugenia Emantayev * - The QKey violatin counter - reset according to each request. 1490ffe455adSEugenia Emantayev */ 1491ffe455adSEugenia Emantayev 1492ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 1493ffe455adSEugenia Emantayev reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40; 1494ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[2]; 1495ffe455adSEugenia Emantayev } else { 1496ffe455adSEugenia Emantayev reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1; 1497ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[1]; 1498ffe455adSEugenia Emantayev } 1499ffe455adSEugenia Emantayev 1500efcd235dSJack Morgenstein /* slave may not set the IS_SM capability for the port */ 1501efcd235dSJack Morgenstein if (slave != mlx4_master_func_num(dev) && 1502efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM)) 1503efcd235dSJack Morgenstein return -EINVAL; 1504efcd235dSJack Morgenstein 1505efcd235dSJack Morgenstein /* No DEV_MGMT in multifunc mode */ 1506efcd235dSJack Morgenstein if (mlx4_is_mfunc(dev) && 1507efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP)) 1508efcd235dSJack Morgenstein return -EINVAL; 1509efcd235dSJack Morgenstein 1510ffe455adSEugenia Emantayev agg_cap_mask = 0; 1511ffe455adSEugenia Emantayev slave_cap_mask = 1512ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; 1513ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask; 1514ffe455adSEugenia Emantayev for (i = 0; i < dev->num_slaves; i++) 1515ffe455adSEugenia Emantayev agg_cap_mask |= 1516ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[i].ib_cap_mask[port]; 1517ffe455adSEugenia Emantayev 1518ffe455adSEugenia Emantayev /* only clear mailbox for guests. Master may be setting 1519ffe455adSEugenia Emantayev * MTU or PKEY table size 1520ffe455adSEugenia Emantayev */ 1521ffe455adSEugenia Emantayev if (slave != dev->caps.function) 1522ffe455adSEugenia Emantayev memset(inbox->buf, 0, 256); 1523ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 1524edc4a67eSJack Morgenstein *(u8 *) inbox->buf |= !!reset_qkey_viols << 6; 1525ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[2] = agg_cap_mask; 1526ffe455adSEugenia Emantayev } else { 1527edc4a67eSJack Morgenstein ((u8 *) inbox->buf)[3] |= !!reset_qkey_viols; 1528ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[1] = agg_cap_mask; 1529ffe455adSEugenia Emantayev } 1530ffe455adSEugenia Emantayev 1531ffe455adSEugenia Emantayev err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT, 1532ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1533ffe455adSEugenia Emantayev if (err) 1534ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = 1535ffe455adSEugenia Emantayev slave_cap_mask; 1536ffe455adSEugenia Emantayev return err; 1537ffe455adSEugenia Emantayev } 1538ffe455adSEugenia Emantayev 1539ffe455adSEugenia Emantayev int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, 1540ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1541ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1542ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1543ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1544ffe455adSEugenia Emantayev { 1545449fc488SMatan Barak int port = mlx4_slave_convert_port( 1546449fc488SMatan Barak dev, slave, vhcr->in_modifier & 0xFF); 1547449fc488SMatan Barak 1548449fc488SMatan Barak if (port < 0) 1549449fc488SMatan Barak return -EINVAL; 1550449fc488SMatan Barak 1551449fc488SMatan Barak vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) | 1552449fc488SMatan Barak (port & 0xFF); 1553449fc488SMatan Barak 1554ffe455adSEugenia Emantayev return mlx4_common_set_port(dev, slave, vhcr->in_modifier, 1555ffe455adSEugenia Emantayev vhcr->op_modifier, inbox); 1556ffe455adSEugenia Emantayev } 1557ffe455adSEugenia Emantayev 1558096335b3SOr Gerlitz /* bit locations for set port command with zero op modifier */ 1559096335b3SOr Gerlitz enum { 1560096335b3SOr Gerlitz MLX4_SET_PORT_VL_CAP = 4, /* bits 7:4 */ 1561096335b3SOr Gerlitz MLX4_SET_PORT_MTU_CAP = 12, /* bits 15:12 */ 15626634961cSJack Morgenstein MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20, 1563096335b3SOr Gerlitz MLX4_CHANGE_PORT_VL_CAP = 21, 1564096335b3SOr Gerlitz MLX4_CHANGE_PORT_MTU_CAP = 22, 1565096335b3SOr Gerlitz }; 1566096335b3SOr Gerlitz 15676634961cSJack Morgenstein int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz) 15685a2cc190SJeff Kirsher { 15695a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 15706634961cSJack Morgenstein int err, vl_cap, pkey_tbl_flag = 0; 15715a2cc190SJeff Kirsher 15725a2cc190SJeff Kirsher if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) 15735a2cc190SJeff Kirsher return 0; 15745a2cc190SJeff Kirsher 15755a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 15765a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 15775a2cc190SJeff Kirsher return PTR_ERR(mailbox); 15785a2cc190SJeff Kirsher 15795a2cc190SJeff Kirsher ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; 1580096335b3SOr Gerlitz 15816634961cSJack Morgenstein if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) { 15826634961cSJack Morgenstein pkey_tbl_flag = 1; 15836634961cSJack Morgenstein ((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz); 15846634961cSJack Morgenstein } 15856634961cSJack Morgenstein 1586096335b3SOr Gerlitz /* IB VL CAP enum isn't used by the firmware, just numerical values */ 1587096335b3SOr Gerlitz for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) { 1588096335b3SOr Gerlitz ((__be32 *) mailbox->buf)[0] = cpu_to_be32( 1589096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_MTU_CAP) | 1590096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_VL_CAP) | 15916634961cSJack Morgenstein (pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) | 1592096335b3SOr Gerlitz (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) | 1593096335b3SOr Gerlitz (vl_cap << MLX4_SET_PORT_VL_CAP)); 1594a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, port, 1595a130b590SIdo Shamay MLX4_SET_PORT_IB_OPCODE, MLX4_CMD_SET_PORT, 1596f9baff50SJack Morgenstein MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 1597096335b3SOr Gerlitz if (err != -ENOMEM) 1598096335b3SOr Gerlitz break; 1599096335b3SOr Gerlitz } 16005a2cc190SJeff Kirsher 16015a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 16025a2cc190SJeff Kirsher return err; 16035a2cc190SJeff Kirsher } 1604ffe455adSEugenia Emantayev 16051da494cbSMoni Shoua #define SET_PORT_ROCE_2_FLAGS 0x10 16061da494cbSMoni Shoua #define MLX4_SET_PORT_ROCE_V1_V2 0x2 1607cb9ffb76SJoerg Roedel int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, 1608ffe455adSEugenia Emantayev u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx) 1609ffe455adSEugenia Emantayev { 1610ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 1611ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *context; 1612ffe455adSEugenia Emantayev int err; 1613ffe455adSEugenia Emantayev u32 in_mod; 1614ffe455adSEugenia Emantayev 1615ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 1616ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 1617ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 1618ffe455adSEugenia Emantayev context = mailbox->buf; 1619ffe455adSEugenia Emantayev context->flags = SET_PORT_GEN_ALL_VALID; 1620ffe455adSEugenia Emantayev context->mtu = cpu_to_be16(mtu); 1621ffe455adSEugenia Emantayev context->pptx = (pptx * (!pfctx)) << 7; 1622ffe455adSEugenia Emantayev context->pfctx = pfctx; 1623ffe455adSEugenia Emantayev context->pprx = (pprx * (!pfcrx)) << 7; 1624ffe455adSEugenia Emantayev context->pfcrx = pfcrx; 1625ffe455adSEugenia Emantayev 16261da494cbSMoni Shoua if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2) { 16271da494cbSMoni Shoua context->flags |= SET_PORT_ROCE_2_FLAGS; 16281da494cbSMoni Shoua context->roce_mode |= 16291da494cbSMoni Shoua MLX4_SET_PORT_ROCE_V1_V2 << 4; 16301da494cbSMoni Shoua } 1631ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 1632a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1633a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1634a130b590SIdo Shamay MLX4_CMD_WRAPPED); 1635ffe455adSEugenia Emantayev 1636ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 1637ffe455adSEugenia Emantayev return err; 1638ffe455adSEugenia Emantayev } 1639ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_general); 1640ffe455adSEugenia Emantayev 1641cb9ffb76SJoerg Roedel int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, 1642ffe455adSEugenia Emantayev u8 promisc) 1643ffe455adSEugenia Emantayev { 1644ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 1645ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *context; 1646ffe455adSEugenia Emantayev int err; 1647ffe455adSEugenia Emantayev u32 in_mod; 1648ffe455adSEugenia Emantayev u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ? 1649ffe455adSEugenia Emantayev MCAST_DIRECT : MCAST_DEFAULT; 1650ffe455adSEugenia Emantayev 1651c96d97f4SHadar Hen Zion if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) 1652ffe455adSEugenia Emantayev return 0; 1653ffe455adSEugenia Emantayev 1654ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 1655ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 1656ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 1657ffe455adSEugenia Emantayev context = mailbox->buf; 1658ffe455adSEugenia Emantayev context->base_qpn = cpu_to_be32(base_qpn); 1659ffe455adSEugenia Emantayev context->n_mac = dev->caps.log_num_macs; 1660ffe455adSEugenia Emantayev context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | 1661ffe455adSEugenia Emantayev base_qpn); 1662ffe455adSEugenia Emantayev context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | 1663ffe455adSEugenia Emantayev base_qpn); 1664ffe455adSEugenia Emantayev context->intra_no_vlan = 0; 1665ffe455adSEugenia Emantayev context->no_vlan = MLX4_NO_VLAN_IDX; 1666ffe455adSEugenia Emantayev context->intra_vlan_miss = 0; 1667ffe455adSEugenia Emantayev context->vlan_miss = MLX4_VLAN_MISS_IDX; 1668ffe455adSEugenia Emantayev 1669ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port; 1670a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1671a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1672a130b590SIdo Shamay MLX4_CMD_WRAPPED); 1673ffe455adSEugenia Emantayev 1674ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 1675ffe455adSEugenia Emantayev return err; 1676ffe455adSEugenia Emantayev } 1677ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); 1678ffe455adSEugenia Emantayev 167940fb4fc1SShaker Daibes int mlx4_SET_PORT_user_mtu(struct mlx4_dev *dev, u8 port, u16 user_mtu) 168040fb4fc1SShaker Daibes { 168140fb4fc1SShaker Daibes struct mlx4_cmd_mailbox *mailbox; 168240fb4fc1SShaker Daibes struct mlx4_set_port_general_context *context; 168340fb4fc1SShaker Daibes u32 in_mod; 168440fb4fc1SShaker Daibes int err; 168540fb4fc1SShaker Daibes 168640fb4fc1SShaker Daibes mailbox = mlx4_alloc_cmd_mailbox(dev); 168740fb4fc1SShaker Daibes if (IS_ERR(mailbox)) 168840fb4fc1SShaker Daibes return PTR_ERR(mailbox); 168940fb4fc1SShaker Daibes context = mailbox->buf; 169040fb4fc1SShaker Daibes context->flags2 |= MLX4_FLAG2_V_USER_MTU_MASK; 169140fb4fc1SShaker Daibes context->user_mtu = cpu_to_be16(user_mtu); 169240fb4fc1SShaker Daibes 169340fb4fc1SShaker Daibes in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 169440fb4fc1SShaker Daibes err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 169540fb4fc1SShaker Daibes MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 169640fb4fc1SShaker Daibes MLX4_CMD_WRAPPED); 169740fb4fc1SShaker Daibes 169840fb4fc1SShaker Daibes mlx4_free_cmd_mailbox(dev, mailbox); 169940fb4fc1SShaker Daibes return err; 170040fb4fc1SShaker Daibes } 170140fb4fc1SShaker Daibes EXPORT_SYMBOL(mlx4_SET_PORT_user_mtu); 170240fb4fc1SShaker Daibes 170378500b8cSMuhammad Mahajna int mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, u8 ignore_fcs_value) 170478500b8cSMuhammad Mahajna { 170578500b8cSMuhammad Mahajna struct mlx4_cmd_mailbox *mailbox; 170678500b8cSMuhammad Mahajna struct mlx4_set_port_general_context *context; 170778500b8cSMuhammad Mahajna u32 in_mod; 170878500b8cSMuhammad Mahajna int err; 170978500b8cSMuhammad Mahajna 171078500b8cSMuhammad Mahajna mailbox = mlx4_alloc_cmd_mailbox(dev); 171178500b8cSMuhammad Mahajna if (IS_ERR(mailbox)) 171278500b8cSMuhammad Mahajna return PTR_ERR(mailbox); 171378500b8cSMuhammad Mahajna context = mailbox->buf; 171440fb4fc1SShaker Daibes context->flags2 |= MLX4_FLAG2_V_IGNORE_FCS_MASK; 171578500b8cSMuhammad Mahajna if (ignore_fcs_value) 171678500b8cSMuhammad Mahajna context->ignore_fcs |= MLX4_IGNORE_FCS_MASK; 171778500b8cSMuhammad Mahajna else 171878500b8cSMuhammad Mahajna context->ignore_fcs &= ~MLX4_IGNORE_FCS_MASK; 171978500b8cSMuhammad Mahajna 172078500b8cSMuhammad Mahajna in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 172178500b8cSMuhammad Mahajna err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 172278500b8cSMuhammad Mahajna MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 172378500b8cSMuhammad Mahajna 172478500b8cSMuhammad Mahajna mlx4_free_cmd_mailbox(dev, mailbox); 172578500b8cSMuhammad Mahajna return err; 172678500b8cSMuhammad Mahajna } 172778500b8cSMuhammad Mahajna EXPORT_SYMBOL(mlx4_SET_PORT_fcs_check); 172878500b8cSMuhammad Mahajna 17297ffdf726SOr Gerlitz enum { 17307ffdf726SOr Gerlitz VXLAN_ENABLE_MODIFY = 1 << 7, 17317ffdf726SOr Gerlitz VXLAN_STEERING_MODIFY = 1 << 6, 17327ffdf726SOr Gerlitz 17337ffdf726SOr Gerlitz VXLAN_ENABLE = 1 << 7, 17347ffdf726SOr Gerlitz }; 17357ffdf726SOr Gerlitz 17367ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context { 17377ffdf726SOr Gerlitz u32 reserved1; 17387ffdf726SOr Gerlitz u8 modify_flags; 17397ffdf726SOr Gerlitz u8 reserved2; 17407ffdf726SOr Gerlitz u8 enable_flags; 17417ffdf726SOr Gerlitz u8 steering; 17427ffdf726SOr Gerlitz }; 17437ffdf726SOr Gerlitz 17441b136de1SOr Gerlitz int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable) 17457ffdf726SOr Gerlitz { 17467ffdf726SOr Gerlitz int err; 17477ffdf726SOr Gerlitz u32 in_mod; 17487ffdf726SOr Gerlitz struct mlx4_cmd_mailbox *mailbox; 17497ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context *context; 17507ffdf726SOr Gerlitz 17517ffdf726SOr Gerlitz mailbox = mlx4_alloc_cmd_mailbox(dev); 17527ffdf726SOr Gerlitz if (IS_ERR(mailbox)) 17537ffdf726SOr Gerlitz return PTR_ERR(mailbox); 17547ffdf726SOr Gerlitz context = mailbox->buf; 17557ffdf726SOr Gerlitz memset(context, 0, sizeof(*context)); 17567ffdf726SOr Gerlitz 17577ffdf726SOr Gerlitz context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY; 17581b136de1SOr Gerlitz if (enable) 17597ffdf726SOr Gerlitz context->enable_flags = VXLAN_ENABLE; 17607ffdf726SOr Gerlitz context->steering = steering; 17617ffdf726SOr Gerlitz 17627ffdf726SOr Gerlitz in_mod = MLX4_SET_PORT_VXLAN << 8 | port; 1763a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1764a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1765a130b590SIdo Shamay MLX4_CMD_NATIVE); 17667ffdf726SOr Gerlitz 17677ffdf726SOr Gerlitz mlx4_free_cmd_mailbox(dev, mailbox); 17687ffdf726SOr Gerlitz return err; 17697ffdf726SOr Gerlitz } 17707ffdf726SOr Gerlitz EXPORT_SYMBOL(mlx4_SET_PORT_VXLAN); 17717ffdf726SOr Gerlitz 177251af33cfSIdo Shamay int mlx4_SET_PORT_BEACON(struct mlx4_dev *dev, u8 port, u16 time) 177351af33cfSIdo Shamay { 177451af33cfSIdo Shamay int err; 177551af33cfSIdo Shamay struct mlx4_cmd_mailbox *mailbox; 177651af33cfSIdo Shamay 177751af33cfSIdo Shamay mailbox = mlx4_alloc_cmd_mailbox(dev); 177851af33cfSIdo Shamay if (IS_ERR(mailbox)) 177951af33cfSIdo Shamay return PTR_ERR(mailbox); 178051af33cfSIdo Shamay 178151af33cfSIdo Shamay *((__be32 *)mailbox->buf) = cpu_to_be32(time); 178251af33cfSIdo Shamay 178351af33cfSIdo Shamay err = mlx4_cmd(dev, mailbox->dma, port, MLX4_SET_PORT_BEACON_OPCODE, 178451af33cfSIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 178551af33cfSIdo Shamay MLX4_CMD_NATIVE); 178651af33cfSIdo Shamay 178751af33cfSIdo Shamay mlx4_free_cmd_mailbox(dev, mailbox); 178851af33cfSIdo Shamay return err; 178951af33cfSIdo Shamay } 179051af33cfSIdo Shamay EXPORT_SYMBOL(mlx4_SET_PORT_BEACON); 179151af33cfSIdo Shamay 1792ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1793ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1794ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1795ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1796ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1797ffe455adSEugenia Emantayev { 1798ffe455adSEugenia Emantayev int err = 0; 1799ffe455adSEugenia Emantayev 1800ffe455adSEugenia Emantayev return err; 1801ffe455adSEugenia Emantayev } 1802ffe455adSEugenia Emantayev 1803ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, 1804ffe455adSEugenia Emantayev u64 mac, u64 clear, u8 mode) 1805ffe455adSEugenia Emantayev { 1806ffe455adSEugenia Emantayev return mlx4_cmd(dev, (mac | (clear << 63)), port, mode, 1807ffe455adSEugenia Emantayev MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B, 1808ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 1809ffe455adSEugenia Emantayev } 1810ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR); 1811ffe455adSEugenia Emantayev 1812ffe455adSEugenia Emantayev int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1813ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1814ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1815ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1816ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1817ffe455adSEugenia Emantayev { 1818ffe455adSEugenia Emantayev int err = 0; 1819ffe455adSEugenia Emantayev 1820ffe455adSEugenia Emantayev return err; 1821ffe455adSEugenia Emantayev } 1822ffe455adSEugenia Emantayev 1823ffe455adSEugenia Emantayev int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, 1824ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1825ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1826ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1827ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1828ffe455adSEugenia Emantayev { 182935fb9afbSEugenia Emantayev return 0; 1830ffe455adSEugenia Emantayev } 183193ece0c1SEugenia Emantayev 18329cd59352SJack Morgenstein int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, 18339cd59352SJack Morgenstein int *slave_id) 18346ee51a4eSJack Morgenstein { 18356ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 18366ee51a4eSJack Morgenstein int i, found_ix = -1; 1837b6ffaeffSJack Morgenstein int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 1838449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 1839449fc488SMatan Barak unsigned num_vfs; 1840449fc488SMatan Barak int slave_gid; 18416ee51a4eSJack Morgenstein 18426ee51a4eSJack Morgenstein if (!mlx4_is_mfunc(dev)) 18436ee51a4eSJack Morgenstein return -EINVAL; 18446ee51a4eSJack Morgenstein 1845449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1846872bf2fbSYishai Hadas num_vfs = bitmap_weight(slaves_pport.slaves, 1847872bf2fbSYishai Hadas dev->persist->num_vfs + 1) - 1; 1848449fc488SMatan Barak 18496ee51a4eSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 1850111c6094SJack Morgenstein if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid, 1851111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE)) { 18526ee51a4eSJack Morgenstein found_ix = i; 18536ee51a4eSJack Morgenstein break; 18546ee51a4eSJack Morgenstein } 18556ee51a4eSJack Morgenstein } 18566ee51a4eSJack Morgenstein 1857b6ffaeffSJack Morgenstein if (found_ix >= 0) { 18580254bc82SMatan Barak /* Calculate a slave_gid which is the slave number in the gid 18590254bc82SMatan Barak * table and not a globally unique slave number. 18600254bc82SMatan Barak */ 1861b6ffaeffSJack Morgenstein if (found_ix < MLX4_ROCE_PF_GIDS) 1862449fc488SMatan Barak slave_gid = 0; 1863449fc488SMatan Barak else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) * 1864449fc488SMatan Barak (vf_gids / num_vfs + 1)) 1865449fc488SMatan Barak slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) / 1866449fc488SMatan Barak (vf_gids / num_vfs + 1)) + 1; 1867b6ffaeffSJack Morgenstein else 1868449fc488SMatan Barak slave_gid = 1869b6ffaeffSJack Morgenstein ((found_ix - MLX4_ROCE_PF_GIDS - 1870449fc488SMatan Barak ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) / 1871449fc488SMatan Barak (vf_gids / num_vfs)) + vf_gids % num_vfs + 1; 1872449fc488SMatan Barak 18730254bc82SMatan Barak /* Calculate the globally unique slave id */ 1874449fc488SMatan Barak if (slave_gid) { 1875449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 1876449fc488SMatan Barak struct mlx4_active_ports actv_ports; 1877449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 1878449fc488SMatan Barak unsigned max_port_p_one; 18790254bc82SMatan Barak int num_vfs_before = 0; 18800254bc82SMatan Barak int candidate_slave_gid; 1881449fc488SMatan Barak 18820254bc82SMatan Barak /* Calculate how many VFs are on the previous port, if exists */ 1883449fc488SMatan Barak for (i = 1; i < port; i++) { 1884449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 18850254bc82SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1886449fc488SMatan Barak slaves_pport_actv = 1887449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv( 1888449fc488SMatan Barak dev, &exclusive_ports); 18890254bc82SMatan Barak num_vfs_before += bitmap_weight( 1890449fc488SMatan Barak slaves_pport_actv.slaves, 1891872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1892449fc488SMatan Barak } 1893449fc488SMatan Barak 18940254bc82SMatan Barak /* candidate_slave_gid isn't necessarily the correct slave, but 18950254bc82SMatan Barak * it has the same number of ports and is assigned to the same 18960254bc82SMatan Barak * ports as the real slave we're looking for. On dual port VF, 18970254bc82SMatan Barak * slave_gid = [single port VFs on port <port>] + 18980254bc82SMatan Barak * [offset of the current slave from the first dual port VF] + 18990254bc82SMatan Barak * 1 (for the PF). 19000254bc82SMatan Barak */ 19010254bc82SMatan Barak candidate_slave_gid = slave_gid + num_vfs_before; 19020254bc82SMatan Barak 19030254bc82SMatan Barak actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid); 1904449fc488SMatan Barak max_port_p_one = find_first_bit( 1905449fc488SMatan Barak actv_ports.ports, dev->caps.num_ports) + 1906449fc488SMatan Barak bitmap_weight(actv_ports.ports, 1907449fc488SMatan Barak dev->caps.num_ports) + 1; 1908449fc488SMatan Barak 19090254bc82SMatan Barak /* Calculate the real slave number */ 1910449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 1911449fc488SMatan Barak if (i == port) 1912449fc488SMatan Barak continue; 1913449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, 1914449fc488SMatan Barak dev->caps.num_ports); 1915449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1916449fc488SMatan Barak slaves_pport_actv = 1917449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv( 1918449fc488SMatan Barak dev, &exclusive_ports); 1919449fc488SMatan Barak slave_gid += bitmap_weight( 1920449fc488SMatan Barak slaves_pport_actv.slaves, 1921872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1922449fc488SMatan Barak } 1923449fc488SMatan Barak } 1924449fc488SMatan Barak *slave_id = slave_gid; 1925b6ffaeffSJack Morgenstein } 19266ee51a4eSJack Morgenstein 19276ee51a4eSJack Morgenstein return (found_ix >= 0) ? 0 : -EINVAL; 19286ee51a4eSJack Morgenstein } 19296ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid); 19306ee51a4eSJack Morgenstein 19319cd59352SJack Morgenstein int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, 19329cd59352SJack Morgenstein u8 *gid) 19336ee51a4eSJack Morgenstein { 19346ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 19356ee51a4eSJack Morgenstein 19366ee51a4eSJack Morgenstein if (!mlx4_is_master(dev)) 19376ee51a4eSJack Morgenstein return -EINVAL; 19386ee51a4eSJack Morgenstein 1939111c6094SJack Morgenstein memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw, 1940111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 19416ee51a4eSJack Morgenstein return 0; 19426ee51a4eSJack Morgenstein } 19436ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); 194432a173c7SSaeed Mahameed 194532a173c7SSaeed Mahameed /* Cable Module Info */ 194632a173c7SSaeed Mahameed #define MODULE_INFO_MAX_READ 48 194732a173c7SSaeed Mahameed 194832a173c7SSaeed Mahameed #define I2C_ADDR_LOW 0x50 194932a173c7SSaeed Mahameed #define I2C_ADDR_HIGH 0x51 195032a173c7SSaeed Mahameed #define I2C_PAGE_SIZE 256 195132a173c7SSaeed Mahameed 195232a173c7SSaeed Mahameed /* Module Info Data */ 195332a173c7SSaeed Mahameed struct mlx4_cable_info { 195432a173c7SSaeed Mahameed u8 i2c_addr; 195532a173c7SSaeed Mahameed u8 page_num; 195632a173c7SSaeed Mahameed __be16 dev_mem_address; 195732a173c7SSaeed Mahameed __be16 reserved1; 195832a173c7SSaeed Mahameed __be16 size; 195932a173c7SSaeed Mahameed __be32 reserved2[2]; 196032a173c7SSaeed Mahameed u8 data[MODULE_INFO_MAX_READ]; 196132a173c7SSaeed Mahameed }; 196232a173c7SSaeed Mahameed 196332a173c7SSaeed Mahameed enum cable_info_err { 196432a173c7SSaeed Mahameed CABLE_INF_INV_PORT = 0x1, 196532a173c7SSaeed Mahameed CABLE_INF_OP_NOSUP = 0x2, 196632a173c7SSaeed Mahameed CABLE_INF_NOT_CONN = 0x3, 196732a173c7SSaeed Mahameed CABLE_INF_NO_EEPRM = 0x4, 196832a173c7SSaeed Mahameed CABLE_INF_PAGE_ERR = 0x5, 196932a173c7SSaeed Mahameed CABLE_INF_INV_ADDR = 0x6, 197032a173c7SSaeed Mahameed CABLE_INF_I2C_ADDR = 0x7, 197132a173c7SSaeed Mahameed CABLE_INF_QSFP_VIO = 0x8, 197232a173c7SSaeed Mahameed CABLE_INF_I2C_BUSY = 0x9, 197332a173c7SSaeed Mahameed }; 197432a173c7SSaeed Mahameed 197532a173c7SSaeed Mahameed #define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF) 197632a173c7SSaeed Mahameed 197732a173c7SSaeed Mahameed static inline const char *cable_info_mad_err_str(u16 mad_status) 197832a173c7SSaeed Mahameed { 197932a173c7SSaeed Mahameed u8 err = MAD_STATUS_2_CABLE_ERR(mad_status); 198032a173c7SSaeed Mahameed 198132a173c7SSaeed Mahameed switch (err) { 198232a173c7SSaeed Mahameed case CABLE_INF_INV_PORT: 198332a173c7SSaeed Mahameed return "invalid port selected"; 198432a173c7SSaeed Mahameed case CABLE_INF_OP_NOSUP: 198532a173c7SSaeed Mahameed return "operation not supported for this port (the port is of type CX4 or internal)"; 198632a173c7SSaeed Mahameed case CABLE_INF_NOT_CONN: 198732a173c7SSaeed Mahameed return "cable is not connected"; 198832a173c7SSaeed Mahameed case CABLE_INF_NO_EEPRM: 198932a173c7SSaeed Mahameed return "the connected cable has no EPROM (passive copper cable)"; 199032a173c7SSaeed Mahameed case CABLE_INF_PAGE_ERR: 199132a173c7SSaeed Mahameed return "page number is greater than 15"; 199232a173c7SSaeed Mahameed case CABLE_INF_INV_ADDR: 199332a173c7SSaeed Mahameed return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)"; 199432a173c7SSaeed Mahameed case CABLE_INF_I2C_ADDR: 199532a173c7SSaeed Mahameed return "invalid I2C slave address"; 199632a173c7SSaeed Mahameed case CABLE_INF_QSFP_VIO: 199732a173c7SSaeed Mahameed return "at least one cable violates the QSFP specification and ignores the modsel signal"; 199832a173c7SSaeed Mahameed case CABLE_INF_I2C_BUSY: 199932a173c7SSaeed Mahameed return "I2C bus is constantly busy"; 200032a173c7SSaeed Mahameed } 200132a173c7SSaeed Mahameed return "Unknown Error"; 200232a173c7SSaeed Mahameed } 200332a173c7SSaeed Mahameed 200432a173c7SSaeed Mahameed /** 200532a173c7SSaeed Mahameed * mlx4_get_module_info - Read cable module eeprom data 200632a173c7SSaeed Mahameed * @dev: mlx4_dev. 200732a173c7SSaeed Mahameed * @port: port number. 200832a173c7SSaeed Mahameed * @offset: byte offset in eeprom to start reading data from. 200932a173c7SSaeed Mahameed * @size: num of bytes to read. 201032a173c7SSaeed Mahameed * @data: output buffer to put the requested data into. 201132a173c7SSaeed Mahameed * 201232a173c7SSaeed Mahameed * Reads cable module eeprom data, puts the outcome data into 201332a173c7SSaeed Mahameed * data pointer paramer. 201432a173c7SSaeed Mahameed * Returns num of read bytes on success or a negative error 201532a173c7SSaeed Mahameed * code. 201632a173c7SSaeed Mahameed */ 201732a173c7SSaeed Mahameed int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, 201832a173c7SSaeed Mahameed u16 offset, u16 size, u8 *data) 201932a173c7SSaeed Mahameed { 202032a173c7SSaeed Mahameed struct mlx4_cmd_mailbox *inbox, *outbox; 202132a173c7SSaeed Mahameed struct mlx4_mad_ifc *inmad, *outmad; 202232a173c7SSaeed Mahameed struct mlx4_cable_info *cable_info; 202332a173c7SSaeed Mahameed u16 i2c_addr; 202432a173c7SSaeed Mahameed int ret; 202532a173c7SSaeed Mahameed 202632a173c7SSaeed Mahameed if (size > MODULE_INFO_MAX_READ) 202732a173c7SSaeed Mahameed size = MODULE_INFO_MAX_READ; 202832a173c7SSaeed Mahameed 202932a173c7SSaeed Mahameed inbox = mlx4_alloc_cmd_mailbox(dev); 203032a173c7SSaeed Mahameed if (IS_ERR(inbox)) 203132a173c7SSaeed Mahameed return PTR_ERR(inbox); 203232a173c7SSaeed Mahameed 203332a173c7SSaeed Mahameed outbox = mlx4_alloc_cmd_mailbox(dev); 203432a173c7SSaeed Mahameed if (IS_ERR(outbox)) { 203532a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, inbox); 203632a173c7SSaeed Mahameed return PTR_ERR(outbox); 203732a173c7SSaeed Mahameed } 203832a173c7SSaeed Mahameed 203932a173c7SSaeed Mahameed inmad = (struct mlx4_mad_ifc *)(inbox->buf); 204032a173c7SSaeed Mahameed outmad = (struct mlx4_mad_ifc *)(outbox->buf); 204132a173c7SSaeed Mahameed 204232a173c7SSaeed Mahameed inmad->method = 0x1; /* Get */ 204332a173c7SSaeed Mahameed inmad->class_version = 0x1; 204432a173c7SSaeed Mahameed inmad->mgmt_class = 0x1; 204532a173c7SSaeed Mahameed inmad->base_version = 0x1; 204632a173c7SSaeed Mahameed inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */ 204732a173c7SSaeed Mahameed 204832a173c7SSaeed Mahameed if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE) 204932a173c7SSaeed Mahameed /* Cross pages reads are not allowed 205032a173c7SSaeed Mahameed * read until offset 256 in low page 205132a173c7SSaeed Mahameed */ 205232a173c7SSaeed Mahameed size -= offset + size - I2C_PAGE_SIZE; 205332a173c7SSaeed Mahameed 205432a173c7SSaeed Mahameed i2c_addr = I2C_ADDR_LOW; 205532a173c7SSaeed Mahameed if (offset >= I2C_PAGE_SIZE) { 205632a173c7SSaeed Mahameed /* Reset offset to high page */ 205732a173c7SSaeed Mahameed i2c_addr = I2C_ADDR_HIGH; 205832a173c7SSaeed Mahameed offset -= I2C_PAGE_SIZE; 205932a173c7SSaeed Mahameed } 206032a173c7SSaeed Mahameed 206132a173c7SSaeed Mahameed cable_info = (struct mlx4_cable_info *)inmad->data; 206232a173c7SSaeed Mahameed cable_info->dev_mem_address = cpu_to_be16(offset); 206332a173c7SSaeed Mahameed cable_info->page_num = 0; 206432a173c7SSaeed Mahameed cable_info->i2c_addr = i2c_addr; 206532a173c7SSaeed Mahameed cable_info->size = cpu_to_be16(size); 206632a173c7SSaeed Mahameed 206732a173c7SSaeed Mahameed ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, 206832a173c7SSaeed Mahameed MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 206932a173c7SSaeed Mahameed MLX4_CMD_NATIVE); 207032a173c7SSaeed Mahameed if (ret) 207132a173c7SSaeed Mahameed goto out; 207232a173c7SSaeed Mahameed 207332a173c7SSaeed Mahameed if (be16_to_cpu(outmad->status)) { 207432a173c7SSaeed Mahameed /* Mad returned with bad status */ 207532a173c7SSaeed Mahameed ret = be16_to_cpu(outmad->status); 207632a173c7SSaeed Mahameed mlx4_warn(dev, 207732a173c7SSaeed 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", 207832a173c7SSaeed Mahameed 0xFF60, port, i2c_addr, offset, size, 207932a173c7SSaeed Mahameed ret, cable_info_mad_err_str(ret)); 208032a173c7SSaeed Mahameed 208132a173c7SSaeed Mahameed if (i2c_addr == I2C_ADDR_HIGH && 208232a173c7SSaeed Mahameed MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR) 208332a173c7SSaeed Mahameed /* Some SFP cables do not support i2c slave 208432a173c7SSaeed Mahameed * address 0x51 (high page), abort silently. 208532a173c7SSaeed Mahameed */ 208632a173c7SSaeed Mahameed ret = 0; 208732a173c7SSaeed Mahameed else 208832a173c7SSaeed Mahameed ret = -ret; 208932a173c7SSaeed Mahameed goto out; 209032a173c7SSaeed Mahameed } 209132a173c7SSaeed Mahameed cable_info = (struct mlx4_cable_info *)outmad->data; 209232a173c7SSaeed Mahameed memcpy(data, cable_info->data, size); 209332a173c7SSaeed Mahameed ret = size; 209432a173c7SSaeed Mahameed out: 209532a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, inbox); 209632a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, outbox); 209732a173c7SSaeed Mahameed return ret; 209832a173c7SSaeed Mahameed } 209932a173c7SSaeed Mahameed EXPORT_SYMBOL(mlx4_get_module_info); 2100af7d5185SRana Shahout 2101af7d5185SRana Shahout int mlx4_max_tc(struct mlx4_dev *dev) 2102af7d5185SRana Shahout { 2103af7d5185SRana Shahout u8 num_tc = dev->caps.max_tc_eth; 2104af7d5185SRana Shahout 2105af7d5185SRana Shahout if (!num_tc) 2106564ed9b1STariq Toukan num_tc = MLX4_TC_MAX_NUMBER; 2107af7d5185SRana Shahout 2108af7d5185SRana Shahout return num_tc; 2109af7d5185SRana Shahout } 2110af7d5185SRana Shahout EXPORT_SYMBOL(mlx4_max_tc); 2111