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 485a2cc190SJeff Kirsher void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table) 495a2cc190SJeff Kirsher { 505a2cc190SJeff Kirsher int i; 515a2cc190SJeff Kirsher 525a2cc190SJeff Kirsher mutex_init(&table->mutex); 535a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 545a2cc190SJeff Kirsher table->entries[i] = 0; 555a2cc190SJeff Kirsher table->refs[i] = 0; 565a2cc190SJeff Kirsher } 575a2cc190SJeff Kirsher table->max = 1 << dev->caps.log_num_macs; 585a2cc190SJeff Kirsher table->total = 0; 595a2cc190SJeff Kirsher } 605a2cc190SJeff Kirsher 615a2cc190SJeff Kirsher void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table) 625a2cc190SJeff Kirsher { 635a2cc190SJeff Kirsher int i; 645a2cc190SJeff Kirsher 655a2cc190SJeff Kirsher mutex_init(&table->mutex); 665a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 675a2cc190SJeff Kirsher table->entries[i] = 0; 685a2cc190SJeff Kirsher table->refs[i] = 0; 695a2cc190SJeff Kirsher } 70e72ebf5aSYevgeny Petrilin table->max = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR; 715a2cc190SJeff Kirsher table->total = 0; 725a2cc190SJeff Kirsher } 735a2cc190SJeff Kirsher 74111c6094SJack Morgenstein void mlx4_init_roce_gid_table(struct mlx4_dev *dev, 75111c6094SJack Morgenstein struct mlx4_roce_gid_table *table) 76111c6094SJack Morgenstein { 77111c6094SJack Morgenstein int i; 78111c6094SJack Morgenstein 79111c6094SJack Morgenstein mutex_init(&table->mutex); 80111c6094SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) 81111c6094SJack Morgenstein memset(table->roce_gids[i].raw, 0, MLX4_ROCE_GID_ENTRY_SIZE); 82111c6094SJack Morgenstein } 83111c6094SJack Morgenstein 845a2cc190SJeff Kirsher static int validate_index(struct mlx4_dev *dev, 855a2cc190SJeff Kirsher struct mlx4_mac_table *table, int index) 865a2cc190SJeff Kirsher { 875a2cc190SJeff Kirsher int err = 0; 885a2cc190SJeff Kirsher 895a2cc190SJeff Kirsher if (index < 0 || index >= table->max || !table->entries[index]) { 905a2cc190SJeff Kirsher mlx4_warn(dev, "No valid Mac entry for the given index\n"); 915a2cc190SJeff Kirsher err = -EINVAL; 925a2cc190SJeff Kirsher } 935a2cc190SJeff Kirsher return err; 945a2cc190SJeff Kirsher } 955a2cc190SJeff Kirsher 965a2cc190SJeff Kirsher static int find_index(struct mlx4_dev *dev, 975a2cc190SJeff Kirsher struct mlx4_mac_table *table, u64 mac) 985a2cc190SJeff Kirsher { 995a2cc190SJeff Kirsher int i; 100ffe455adSEugenia Emantayev 1015a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 102f4fd40b2SJack Morgenstein if (table->refs[i] && 103f4fd40b2SJack Morgenstein (MLX4_MAC_MASK & mac) == 104ffe455adSEugenia Emantayev (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) 1055a2cc190SJeff Kirsher return i; 1065a2cc190SJeff Kirsher } 1075a2cc190SJeff Kirsher /* Mac not found */ 1085a2cc190SJeff Kirsher return -EINVAL; 1095a2cc190SJeff Kirsher } 1105a2cc190SJeff Kirsher 111ffe455adSEugenia Emantayev static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, 112ffe455adSEugenia Emantayev __be64 *entries) 113ffe455adSEugenia Emantayev { 114ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 115ffe455adSEugenia Emantayev u32 in_mod; 116ffe455adSEugenia Emantayev int err; 117ffe455adSEugenia Emantayev 118ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 119ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 120ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 121ffe455adSEugenia Emantayev 122ffe455adSEugenia Emantayev memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); 123ffe455adSEugenia Emantayev 124ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; 125ffe455adSEugenia Emantayev 126a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 127a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 128a130b590SIdo Shamay MLX4_CMD_NATIVE); 129ffe455adSEugenia Emantayev 130ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 131ffe455adSEugenia Emantayev return err; 132ffe455adSEugenia Emantayev } 133ffe455adSEugenia Emantayev 134297e0dadSMoni Shoua int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx) 135297e0dadSMoni Shoua { 136297e0dadSMoni Shoua struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 137297e0dadSMoni Shoua struct mlx4_mac_table *table = &info->mac_table; 138297e0dadSMoni Shoua int i; 139297e0dadSMoni Shoua 140297e0dadSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 141297e0dadSMoni Shoua if (!table->refs[i]) 142297e0dadSMoni Shoua continue; 143297e0dadSMoni Shoua 144297e0dadSMoni Shoua if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 145297e0dadSMoni Shoua *idx = i; 146297e0dadSMoni Shoua return 0; 147297e0dadSMoni Shoua } 148297e0dadSMoni Shoua } 149297e0dadSMoni Shoua 150297e0dadSMoni Shoua return -ENOENT; 151297e0dadSMoni Shoua } 152297e0dadSMoni Shoua EXPORT_SYMBOL_GPL(mlx4_find_cached_mac); 153297e0dadSMoni Shoua 154ffe455adSEugenia Emantayev int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 155ffe455adSEugenia Emantayev { 156ffe455adSEugenia Emantayev struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 157ffe455adSEugenia Emantayev struct mlx4_mac_table *table = &info->mac_table; 158ffe455adSEugenia Emantayev int i, err = 0; 159ffe455adSEugenia Emantayev int free = -1; 160ffe455adSEugenia Emantayev 161ffe455adSEugenia Emantayev mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d\n", 162ffe455adSEugenia Emantayev (unsigned long long) mac, port); 163ffe455adSEugenia Emantayev 164ffe455adSEugenia Emantayev mutex_lock(&table->mutex); 165ffe455adSEugenia Emantayev for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 166f4fd40b2SJack Morgenstein if (!table->refs[i]) { 167f4fd40b2SJack Morgenstein if (free < 0) 168ffe455adSEugenia Emantayev free = i; 169ffe455adSEugenia Emantayev continue; 170ffe455adSEugenia Emantayev } 171ffe455adSEugenia Emantayev 172f4fd40b2SJack Morgenstein if ((MLX4_MAC_MASK & mac) == 173f4fd40b2SJack Morgenstein (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 1746ce71acdSRony Efraim /* MAC already registered, increment ref count */ 1756ce71acdSRony Efraim err = i; 1766ce71acdSRony Efraim ++table->refs[i]; 177ffe455adSEugenia Emantayev goto out; 178ffe455adSEugenia Emantayev } 179ffe455adSEugenia Emantayev } 180ffe455adSEugenia Emantayev 181ffe455adSEugenia Emantayev mlx4_dbg(dev, "Free MAC index is %d\n", free); 182ffe455adSEugenia Emantayev 183ffe455adSEugenia Emantayev if (table->total == table->max) { 184ffe455adSEugenia Emantayev /* No free mac entries */ 185ffe455adSEugenia Emantayev err = -ENOSPC; 186ffe455adSEugenia Emantayev goto out; 187ffe455adSEugenia Emantayev } 188ffe455adSEugenia Emantayev 189ffe455adSEugenia Emantayev /* Register new MAC */ 190ffe455adSEugenia Emantayev table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); 191ffe455adSEugenia Emantayev 192ffe455adSEugenia Emantayev err = mlx4_set_port_mac_table(dev, port, table->entries); 193ffe455adSEugenia Emantayev if (unlikely(err)) { 194ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 195ffe455adSEugenia Emantayev (unsigned long long) mac); 196ffe455adSEugenia Emantayev table->entries[free] = 0; 197ffe455adSEugenia Emantayev goto out; 198ffe455adSEugenia Emantayev } 1996ce71acdSRony Efraim table->refs[free] = 1; 200ffe455adSEugenia Emantayev err = free; 201ffe455adSEugenia Emantayev ++table->total; 202ffe455adSEugenia Emantayev out: 203ffe455adSEugenia Emantayev mutex_unlock(&table->mutex); 204ffe455adSEugenia Emantayev return err; 205ffe455adSEugenia Emantayev } 206ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_register_mac); 207ffe455adSEugenia Emantayev 208ffe455adSEugenia Emantayev int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 209ffe455adSEugenia Emantayev { 210e7dbeba8SJack Morgenstein u64 out_param = 0; 211acddd5ddSJack Morgenstein int err = -EINVAL; 212ffe455adSEugenia Emantayev 213ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 214acddd5ddSJack Morgenstein if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 215acddd5ddSJack Morgenstein err = mlx4_cmd_imm(dev, mac, &out_param, 216acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_MAC, 217acddd5ddSJack Morgenstein RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 218acddd5ddSJack Morgenstein MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 219acddd5ddSJack Morgenstein } 220acddd5ddSJack Morgenstein if (err && err == -EINVAL && mlx4_is_slave(dev)) { 221acddd5ddSJack Morgenstein /* retry using old REG_MAC format */ 222ffe455adSEugenia Emantayev set_param_l(&out_param, port); 223ffe455adSEugenia Emantayev err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 224ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 225ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 226acddd5ddSJack Morgenstein if (!err) 227acddd5ddSJack Morgenstein dev->flags |= MLX4_FLAG_OLD_REG_MAC; 228acddd5ddSJack Morgenstein } 229ffe455adSEugenia Emantayev if (err) 230ffe455adSEugenia Emantayev return err; 231ffe455adSEugenia Emantayev 232ffe455adSEugenia Emantayev return get_param_l(&out_param); 233ffe455adSEugenia Emantayev } 234ffe455adSEugenia Emantayev return __mlx4_register_mac(dev, port, mac); 235ffe455adSEugenia Emantayev } 236ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(mlx4_register_mac); 237ffe455adSEugenia Emantayev 23816a10ffdSYan Burman int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port) 23916a10ffdSYan Burman { 24016a10ffdSYan Burman return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] + 24116a10ffdSYan Burman (port - 1) * (1 << dev->caps.log_num_macs); 24216a10ffdSYan Burman } 24316a10ffdSYan Burman EXPORT_SYMBOL_GPL(mlx4_get_base_qpn); 244ffe455adSEugenia Emantayev 245ffe455adSEugenia Emantayev void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 246ffe455adSEugenia Emantayev { 247143b3efbSEugenia Emantayev struct mlx4_port_info *info; 248143b3efbSEugenia Emantayev struct mlx4_mac_table *table; 249ffe455adSEugenia Emantayev int index; 250ffe455adSEugenia Emantayev 251143b3efbSEugenia Emantayev if (port < 1 || port > dev->caps.num_ports) { 252143b3efbSEugenia Emantayev mlx4_warn(dev, "invalid port number (%d), aborting...\n", port); 253143b3efbSEugenia Emantayev return; 254143b3efbSEugenia Emantayev } 255143b3efbSEugenia Emantayev info = &mlx4_priv(dev)->port[port]; 256143b3efbSEugenia Emantayev table = &info->mac_table; 2575a2cc190SJeff Kirsher mutex_lock(&table->mutex); 2586ce71acdSRony Efraim index = find_index(dev, table, mac); 2595a2cc190SJeff Kirsher 2605a2cc190SJeff Kirsher if (validate_index(dev, table, index)) 2615a2cc190SJeff Kirsher goto out; 2626ce71acdSRony Efraim if (--table->refs[index]) { 2631a91de28SJoe Perches mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n", 2641a91de28SJoe Perches index); 2656ce71acdSRony Efraim goto out; 2666ce71acdSRony Efraim } 2675a2cc190SJeff Kirsher 2685a2cc190SJeff Kirsher table->entries[index] = 0; 2695a2cc190SJeff Kirsher mlx4_set_port_mac_table(dev, port, table->entries); 2705a2cc190SJeff Kirsher --table->total; 2715a2cc190SJeff Kirsher out: 2725a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 2735a2cc190SJeff Kirsher } 274ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_unregister_mac); 275ffe455adSEugenia Emantayev 276ffe455adSEugenia Emantayev void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 277ffe455adSEugenia Emantayev { 278e7dbeba8SJack Morgenstein u64 out_param = 0; 279ffe455adSEugenia Emantayev 280ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 281acddd5ddSJack Morgenstein if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 282acddd5ddSJack Morgenstein (void) mlx4_cmd_imm(dev, mac, &out_param, 283acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_MAC, 284acddd5ddSJack Morgenstein RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 285acddd5ddSJack Morgenstein MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 286acddd5ddSJack Morgenstein } else { 287acddd5ddSJack Morgenstein /* use old unregister mac format */ 288ffe455adSEugenia Emantayev set_param_l(&out_param, port); 289162344edSOr Gerlitz (void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 290ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 291ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 292acddd5ddSJack Morgenstein } 293ffe455adSEugenia Emantayev return; 294ffe455adSEugenia Emantayev } 295ffe455adSEugenia Emantayev __mlx4_unregister_mac(dev, port, mac); 296ffe455adSEugenia Emantayev return; 297ffe455adSEugenia Emantayev } 2985a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_mac); 2995a2cc190SJeff Kirsher 30016a10ffdSYan Burman int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac) 3015a2cc190SJeff Kirsher { 3025a2cc190SJeff Kirsher struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 3035a2cc190SJeff Kirsher struct mlx4_mac_table *table = &info->mac_table; 304ffe455adSEugenia Emantayev int index = qpn - info->base_qpn; 305ffe455adSEugenia Emantayev int err = 0; 3065a2cc190SJeff Kirsher 307ffe455adSEugenia Emantayev /* CX1 doesn't support multi-functions */ 3085a2cc190SJeff Kirsher mutex_lock(&table->mutex); 3095a2cc190SJeff Kirsher 3105a2cc190SJeff Kirsher err = validate_index(dev, table, index); 3115a2cc190SJeff Kirsher if (err) 3125a2cc190SJeff Kirsher goto out; 3135a2cc190SJeff Kirsher 3145a2cc190SJeff Kirsher table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); 3155a2cc190SJeff Kirsher 3165a2cc190SJeff Kirsher err = mlx4_set_port_mac_table(dev, port, table->entries); 3175a2cc190SJeff Kirsher if (unlikely(err)) { 318ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 319ffe455adSEugenia Emantayev (unsigned long long) new_mac); 3205a2cc190SJeff Kirsher table->entries[index] = 0; 3215a2cc190SJeff Kirsher } 3225a2cc190SJeff Kirsher out: 3235a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 3245a2cc190SJeff Kirsher return err; 3255a2cc190SJeff Kirsher } 32616a10ffdSYan Burman EXPORT_SYMBOL_GPL(__mlx4_replace_mac); 327ffe455adSEugenia Emantayev 3285a2cc190SJeff Kirsher static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, 3295a2cc190SJeff Kirsher __be32 *entries) 3305a2cc190SJeff Kirsher { 3315a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 3325a2cc190SJeff Kirsher u32 in_mod; 3335a2cc190SJeff Kirsher int err; 3345a2cc190SJeff Kirsher 3355a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 3365a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 3375a2cc190SJeff Kirsher return PTR_ERR(mailbox); 3385a2cc190SJeff Kirsher 3395a2cc190SJeff Kirsher memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); 3405a2cc190SJeff Kirsher in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; 341a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 342a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 343a130b590SIdo Shamay MLX4_CMD_NATIVE); 3445a2cc190SJeff Kirsher 3455a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 3465a2cc190SJeff Kirsher 3475a2cc190SJeff Kirsher return err; 3485a2cc190SJeff Kirsher } 3495a2cc190SJeff Kirsher 3505a2cc190SJeff Kirsher int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx) 3515a2cc190SJeff Kirsher { 3525a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 3535a2cc190SJeff Kirsher int i; 3545a2cc190SJeff Kirsher 3555a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) { 3565a2cc190SJeff Kirsher if (table->refs[i] && 3575a2cc190SJeff Kirsher (vid == (MLX4_VLAN_MASK & 3585a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 3595a2cc190SJeff Kirsher /* VLAN already registered, increase reference count */ 3605a2cc190SJeff Kirsher *idx = i; 3615a2cc190SJeff Kirsher return 0; 3625a2cc190SJeff Kirsher } 3635a2cc190SJeff Kirsher } 3645a2cc190SJeff Kirsher 3655a2cc190SJeff Kirsher return -ENOENT; 3665a2cc190SJeff Kirsher } 3675a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan); 3685a2cc190SJeff Kirsher 3693f7fb021SRony Efraim int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, 370ffe455adSEugenia Emantayev int *index) 3715a2cc190SJeff Kirsher { 3725a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 3735a2cc190SJeff Kirsher int i, err = 0; 3745a2cc190SJeff Kirsher int free = -1; 3755a2cc190SJeff Kirsher 3765a2cc190SJeff Kirsher mutex_lock(&table->mutex); 377e72ebf5aSYevgeny Petrilin 378e72ebf5aSYevgeny Petrilin if (table->total == table->max) { 379e72ebf5aSYevgeny Petrilin /* No free vlan entries */ 380e72ebf5aSYevgeny Petrilin err = -ENOSPC; 381e72ebf5aSYevgeny Petrilin goto out; 382e72ebf5aSYevgeny Petrilin } 383e72ebf5aSYevgeny Petrilin 3845a2cc190SJeff Kirsher for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 3855a2cc190SJeff Kirsher if (free < 0 && (table->refs[i] == 0)) { 3865a2cc190SJeff Kirsher free = i; 3875a2cc190SJeff Kirsher continue; 3885a2cc190SJeff Kirsher } 3895a2cc190SJeff Kirsher 3905a2cc190SJeff Kirsher if (table->refs[i] && 3915a2cc190SJeff Kirsher (vlan == (MLX4_VLAN_MASK & 3925a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 3935a2cc190SJeff Kirsher /* Vlan already registered, increase references count */ 3945a2cc190SJeff Kirsher *index = i; 3955a2cc190SJeff Kirsher ++table->refs[i]; 3965a2cc190SJeff Kirsher goto out; 3975a2cc190SJeff Kirsher } 3985a2cc190SJeff Kirsher } 3995a2cc190SJeff Kirsher 4005a2cc190SJeff Kirsher if (free < 0) { 4015a2cc190SJeff Kirsher err = -ENOMEM; 4025a2cc190SJeff Kirsher goto out; 4035a2cc190SJeff Kirsher } 4045a2cc190SJeff Kirsher 405ffe455adSEugenia Emantayev /* Register new VLAN */ 4065a2cc190SJeff Kirsher table->refs[free] = 1; 4075a2cc190SJeff Kirsher table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 4085a2cc190SJeff Kirsher 4095a2cc190SJeff Kirsher err = mlx4_set_port_vlan_table(dev, port, table->entries); 4105a2cc190SJeff Kirsher if (unlikely(err)) { 4115a2cc190SJeff Kirsher mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); 4125a2cc190SJeff Kirsher table->refs[free] = 0; 4135a2cc190SJeff Kirsher table->entries[free] = 0; 4145a2cc190SJeff Kirsher goto out; 4155a2cc190SJeff Kirsher } 4165a2cc190SJeff Kirsher 4175a2cc190SJeff Kirsher *index = free; 4185a2cc190SJeff Kirsher ++table->total; 4195a2cc190SJeff Kirsher out: 4205a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 4215a2cc190SJeff Kirsher return err; 4225a2cc190SJeff Kirsher } 423ffe455adSEugenia Emantayev 424ffe455adSEugenia Emantayev int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) 425ffe455adSEugenia Emantayev { 426e7dbeba8SJack Morgenstein u64 out_param = 0; 427ffe455adSEugenia Emantayev int err; 428ffe455adSEugenia Emantayev 429162226a1SJack Morgenstein if (vlan > 4095) 430162226a1SJack Morgenstein return -EINVAL; 431162226a1SJack Morgenstein 432ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 433acddd5ddSJack Morgenstein err = mlx4_cmd_imm(dev, vlan, &out_param, 434acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN, 435ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 436ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 437ffe455adSEugenia Emantayev if (!err) 438ffe455adSEugenia Emantayev *index = get_param_l(&out_param); 439ffe455adSEugenia Emantayev 440ffe455adSEugenia Emantayev return err; 441ffe455adSEugenia Emantayev } 442ffe455adSEugenia Emantayev return __mlx4_register_vlan(dev, port, vlan, index); 443ffe455adSEugenia Emantayev } 4445a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_register_vlan); 4455a2cc190SJeff Kirsher 4462009d005SJack Morgenstein void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 4475a2cc190SJeff Kirsher { 4485a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 4492009d005SJack Morgenstein int index; 4502009d005SJack Morgenstein 4512009d005SJack Morgenstein mutex_lock(&table->mutex); 4522009d005SJack Morgenstein if (mlx4_find_cached_vlan(dev, port, vlan, &index)) { 4532009d005SJack Morgenstein mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan); 4542009d005SJack Morgenstein goto out; 4552009d005SJack Morgenstein } 4565a2cc190SJeff Kirsher 4575a2cc190SJeff Kirsher if (index < MLX4_VLAN_REGULAR) { 4585a2cc190SJeff Kirsher mlx4_warn(dev, "Trying to free special vlan index %d\n", index); 4595a2cc190SJeff Kirsher goto out; 4605a2cc190SJeff Kirsher } 4612009d005SJack Morgenstein 4625a2cc190SJeff Kirsher if (--table->refs[index]) { 4631a91de28SJoe Perches mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n", 4641a91de28SJoe Perches table->refs[index], index); 4655a2cc190SJeff Kirsher goto out; 4665a2cc190SJeff Kirsher } 4675a2cc190SJeff Kirsher table->entries[index] = 0; 4685a2cc190SJeff Kirsher mlx4_set_port_vlan_table(dev, port, table->entries); 4695a2cc190SJeff Kirsher --table->total; 4705a2cc190SJeff Kirsher out: 4715a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 4725a2cc190SJeff Kirsher } 473ffe455adSEugenia Emantayev 4742009d005SJack Morgenstein void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 475ffe455adSEugenia Emantayev { 476162226a1SJack Morgenstein u64 out_param = 0; 477ffe455adSEugenia Emantayev 478ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 4792009d005SJack Morgenstein (void) mlx4_cmd_imm(dev, vlan, &out_param, 480acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN, 481162226a1SJack Morgenstein RES_OP_RESERVE_AND_MAP, 482ffe455adSEugenia Emantayev MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, 483ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 484ffe455adSEugenia Emantayev return; 485ffe455adSEugenia Emantayev } 4862009d005SJack Morgenstein __mlx4_unregister_vlan(dev, port, vlan); 487ffe455adSEugenia Emantayev } 4885a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_vlan); 4895a2cc190SJeff Kirsher 4905a2cc190SJeff Kirsher int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) 4915a2cc190SJeff Kirsher { 4925a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *inmailbox, *outmailbox; 4935a2cc190SJeff Kirsher u8 *inbuf, *outbuf; 4945a2cc190SJeff Kirsher int err; 4955a2cc190SJeff Kirsher 4965a2cc190SJeff Kirsher inmailbox = mlx4_alloc_cmd_mailbox(dev); 4975a2cc190SJeff Kirsher if (IS_ERR(inmailbox)) 4985a2cc190SJeff Kirsher return PTR_ERR(inmailbox); 4995a2cc190SJeff Kirsher 5005a2cc190SJeff Kirsher outmailbox = mlx4_alloc_cmd_mailbox(dev); 5015a2cc190SJeff Kirsher if (IS_ERR(outmailbox)) { 5025a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 5035a2cc190SJeff Kirsher return PTR_ERR(outmailbox); 5045a2cc190SJeff Kirsher } 5055a2cc190SJeff Kirsher 5065a2cc190SJeff Kirsher inbuf = inmailbox->buf; 5075a2cc190SJeff Kirsher outbuf = outmailbox->buf; 5085a2cc190SJeff Kirsher inbuf[0] = 1; 5095a2cc190SJeff Kirsher inbuf[1] = 1; 5105a2cc190SJeff Kirsher inbuf[2] = 1; 5115a2cc190SJeff Kirsher inbuf[3] = 1; 5125a2cc190SJeff Kirsher *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015); 5135a2cc190SJeff Kirsher *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); 5145a2cc190SJeff Kirsher 5155a2cc190SJeff Kirsher err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, 516f9baff50SJack Morgenstein MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 517f9baff50SJack Morgenstein MLX4_CMD_NATIVE); 5185a2cc190SJeff Kirsher if (!err) 5195a2cc190SJeff Kirsher *caps = *(__be32 *) (outbuf + 84); 5205a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 5215a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, outmailbox); 5225a2cc190SJeff Kirsher return err; 5235a2cc190SJeff Kirsher } 5249cd59352SJack Morgenstein static struct mlx4_roce_gid_entry zgid_entry; 5255a2cc190SJeff Kirsher 526449fc488SMatan Barak int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port) 527b6ffaeffSJack Morgenstein { 528449fc488SMatan Barak int vfs; 529449fc488SMatan Barak int slave_gid = slave; 530449fc488SMatan Barak unsigned i; 531449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 532449fc488SMatan Barak struct mlx4_active_ports actv_ports; 533449fc488SMatan Barak unsigned max_port_p_one; 534449fc488SMatan Barak 535b6ffaeffSJack Morgenstein if (slave == 0) 536b6ffaeffSJack Morgenstein return MLX4_ROCE_PF_GIDS; 537449fc488SMatan Barak 538449fc488SMatan Barak /* Slave is a VF */ 539449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 540449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave); 541449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 542449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 543449fc488SMatan Barak 544449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 545449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 546449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 547449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 548449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 549449fc488SMatan Barak if (i == port) 550449fc488SMatan Barak continue; 551449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 552449fc488SMatan Barak dev, &exclusive_ports); 553449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 554872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 555449fc488SMatan Barak } 556872bf2fbSYishai Hadas vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; 557449fc488SMatan Barak if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs)) 558449fc488SMatan Barak return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1; 559449fc488SMatan Barak return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs; 560b6ffaeffSJack Morgenstein } 561b6ffaeffSJack Morgenstein 562449fc488SMatan Barak int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port) 563b6ffaeffSJack Morgenstein { 564b6ffaeffSJack Morgenstein int gids; 565449fc488SMatan Barak unsigned i; 566449fc488SMatan Barak int slave_gid = slave; 567b6ffaeffSJack Morgenstein int vfs; 568b6ffaeffSJack Morgenstein 569449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 570449fc488SMatan Barak struct mlx4_active_ports actv_ports; 571449fc488SMatan Barak unsigned max_port_p_one; 572b6ffaeffSJack Morgenstein 573b6ffaeffSJack Morgenstein if (slave == 0) 574b6ffaeffSJack Morgenstein return 0; 575b6ffaeffSJack Morgenstein 576449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 577449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave); 578449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 579449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 580449fc488SMatan Barak 581449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 582449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 583449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 584449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 585449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 586449fc488SMatan Barak if (i == port) 587449fc488SMatan Barak continue; 588449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 589449fc488SMatan Barak dev, &exclusive_ports); 590449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 591872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 592b6ffaeffSJack Morgenstein } 593449fc488SMatan Barak gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 594872bf2fbSYishai Hadas vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1; 595449fc488SMatan Barak if (slave_gid <= gids % vfs) 596449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1); 597449fc488SMatan Barak 598449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + (gids % vfs) + 599449fc488SMatan Barak ((gids / vfs) * (slave_gid - 1)); 600449fc488SMatan Barak } 601449fc488SMatan Barak EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix); 602b6ffaeffSJack Morgenstein 603111c6094SJack Morgenstein static int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave, 604111c6094SJack Morgenstein int port, struct mlx4_cmd_mailbox *mailbox) 605111c6094SJack Morgenstein { 606111c6094SJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_mbox; 607111c6094SJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 608111c6094SJack Morgenstein int num_gids, base, offset; 609111c6094SJack Morgenstein int i, err; 610111c6094SJack Morgenstein 611111c6094SJack Morgenstein num_gids = mlx4_get_slave_num_gids(dev, slave, port); 612111c6094SJack Morgenstein base = mlx4_get_base_gid_ix(dev, slave, port); 613111c6094SJack Morgenstein 614111c6094SJack Morgenstein memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE); 615111c6094SJack Morgenstein 616111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex)); 617111c6094SJack Morgenstein /* Zero-out gids belonging to that slave in the port GID table */ 618111c6094SJack Morgenstein for (i = 0, offset = base; i < num_gids; offset++, i++) 619111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 620111c6094SJack Morgenstein zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE); 621111c6094SJack Morgenstein 622111c6094SJack Morgenstein /* Now, copy roce port gids table to mailbox for passing to FW */ 623111c6094SJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf; 624111c6094SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 625111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw, 626111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw, 627111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 628111c6094SJack Morgenstein 629111c6094SJack Morgenstein err = mlx4_cmd(dev, mailbox->dma, 630a130b590SIdo Shamay ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8), 631a130b590SIdo Shamay MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT, 632a130b590SIdo Shamay MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 633111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 634111c6094SJack Morgenstein return err; 635111c6094SJack Morgenstein } 636111c6094SJack Morgenstein 637111c6094SJack Morgenstein 638111c6094SJack Morgenstein void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave) 639111c6094SJack Morgenstein { 640111c6094SJack Morgenstein struct mlx4_active_ports actv_ports; 641111c6094SJack Morgenstein struct mlx4_cmd_mailbox *mailbox; 642111c6094SJack Morgenstein int num_eth_ports, err; 643111c6094SJack Morgenstein int i; 644111c6094SJack Morgenstein 645872bf2fbSYishai Hadas if (slave < 0 || slave > dev->persist->num_vfs) 646111c6094SJack Morgenstein return; 647111c6094SJack Morgenstein 648111c6094SJack Morgenstein actv_ports = mlx4_get_active_ports(dev, slave); 649111c6094SJack Morgenstein 650111c6094SJack Morgenstein for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) { 651111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) { 652111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 653111c6094SJack Morgenstein continue; 654111c6094SJack Morgenstein num_eth_ports++; 655111c6094SJack Morgenstein } 656111c6094SJack Morgenstein } 657111c6094SJack Morgenstein 658111c6094SJack Morgenstein if (!num_eth_ports) 659111c6094SJack Morgenstein return; 660111c6094SJack Morgenstein 661111c6094SJack Morgenstein /* have ETH ports. Alloc mailbox for SET_PORT command */ 662111c6094SJack Morgenstein mailbox = mlx4_alloc_cmd_mailbox(dev); 663111c6094SJack Morgenstein if (IS_ERR(mailbox)) 664111c6094SJack Morgenstein return; 665111c6094SJack Morgenstein 666111c6094SJack Morgenstein for (i = 0; i < dev->caps.num_ports; i++) { 667111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) { 668111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 669111c6094SJack Morgenstein continue; 670111c6094SJack Morgenstein err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox); 671111c6094SJack Morgenstein if (err) 672111c6094SJack Morgenstein mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n", 673111c6094SJack Morgenstein slave, i + 1, err); 674111c6094SJack Morgenstein } 675111c6094SJack Morgenstein } 676111c6094SJack Morgenstein 677111c6094SJack Morgenstein mlx4_free_cmd_mailbox(dev, mailbox); 678111c6094SJack Morgenstein return; 679111c6094SJack Morgenstein } 680111c6094SJack Morgenstein 681ffe455adSEugenia Emantayev static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, 682ffe455adSEugenia Emantayev u8 op_mod, struct mlx4_cmd_mailbox *inbox) 683ffe455adSEugenia Emantayev { 684ffe455adSEugenia Emantayev struct mlx4_priv *priv = mlx4_priv(dev); 685ffe455adSEugenia Emantayev struct mlx4_port_info *port_info; 686ffe455adSEugenia Emantayev struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; 687ffe455adSEugenia Emantayev struct mlx4_slave_state *slave_st = &master->slave_state[slave]; 688ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *qpn_context; 689ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *gen_context; 690b6ffaeffSJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1; 691ffe455adSEugenia Emantayev int reset_qkey_viols; 692ffe455adSEugenia Emantayev int port; 693ffe455adSEugenia Emantayev int is_eth; 694b6ffaeffSJack Morgenstein int num_gids; 695b6ffaeffSJack Morgenstein int base; 696ffe455adSEugenia Emantayev u32 in_modifier; 697ffe455adSEugenia Emantayev u32 promisc; 698ffe455adSEugenia Emantayev u16 mtu, prev_mtu; 699ffe455adSEugenia Emantayev int err; 700b6ffaeffSJack Morgenstein int i, j; 701b6ffaeffSJack Morgenstein int offset; 702ffe455adSEugenia Emantayev __be32 agg_cap_mask; 703ffe455adSEugenia Emantayev __be32 slave_cap_mask; 704ffe455adSEugenia Emantayev __be32 new_cap_mask; 705ffe455adSEugenia Emantayev 706ffe455adSEugenia Emantayev port = in_mod & 0xff; 707ffe455adSEugenia Emantayev in_modifier = in_mod >> 8; 708ffe455adSEugenia Emantayev is_eth = op_mod; 709ffe455adSEugenia Emantayev port_info = &priv->port[port]; 710ffe455adSEugenia Emantayev 711ffe455adSEugenia Emantayev /* Slaves cannot perform SET_PORT operations except changing MTU */ 712ffe455adSEugenia Emantayev if (is_eth) { 713ffe455adSEugenia Emantayev if (slave != dev->caps.function && 7149cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GENERAL && 7159cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GID_TABLE) { 716ffe455adSEugenia Emantayev mlx4_warn(dev, "denying SET_PORT for slave:%d\n", 717ffe455adSEugenia Emantayev slave); 718ffe455adSEugenia Emantayev return -EINVAL; 719ffe455adSEugenia Emantayev } 720ffe455adSEugenia Emantayev switch (in_modifier) { 721ffe455adSEugenia Emantayev case MLX4_SET_PORT_RQP_CALC: 722ffe455adSEugenia Emantayev qpn_context = inbox->buf; 723ffe455adSEugenia Emantayev qpn_context->base_qpn = 724ffe455adSEugenia Emantayev cpu_to_be32(port_info->base_qpn); 725ffe455adSEugenia Emantayev qpn_context->n_mac = 0x7; 726ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->promisc) >> 727ffe455adSEugenia Emantayev SET_PORT_PROMISC_SHIFT; 728ffe455adSEugenia Emantayev qpn_context->promisc = cpu_to_be32( 729ffe455adSEugenia Emantayev promisc << SET_PORT_PROMISC_SHIFT | 730ffe455adSEugenia Emantayev port_info->base_qpn); 731ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->mcast) >> 732ffe455adSEugenia Emantayev SET_PORT_MC_PROMISC_SHIFT; 733ffe455adSEugenia Emantayev qpn_context->mcast = cpu_to_be32( 734ffe455adSEugenia Emantayev promisc << SET_PORT_MC_PROMISC_SHIFT | 735ffe455adSEugenia Emantayev port_info->base_qpn); 736ffe455adSEugenia Emantayev break; 737ffe455adSEugenia Emantayev case MLX4_SET_PORT_GENERAL: 738ffe455adSEugenia Emantayev gen_context = inbox->buf; 739ffe455adSEugenia Emantayev /* Mtu is configured as the max MTU among all the 740ffe455adSEugenia Emantayev * the functions on the port. */ 741ffe455adSEugenia Emantayev mtu = be16_to_cpu(gen_context->mtu); 742c59fec20SEugenia Emantayev mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] + 743c59fec20SEugenia Emantayev ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); 744ffe455adSEugenia Emantayev prev_mtu = slave_st->mtu[port]; 745ffe455adSEugenia Emantayev slave_st->mtu[port] = mtu; 746ffe455adSEugenia Emantayev if (mtu > master->max_mtu[port]) 747ffe455adSEugenia Emantayev master->max_mtu[port] = mtu; 748ffe455adSEugenia Emantayev if (mtu < prev_mtu && prev_mtu == 749ffe455adSEugenia Emantayev master->max_mtu[port]) { 750ffe455adSEugenia Emantayev slave_st->mtu[port] = mtu; 751ffe455adSEugenia Emantayev master->max_mtu[port] = mtu; 752ffe455adSEugenia Emantayev for (i = 0; i < dev->num_slaves; i++) { 753ffe455adSEugenia Emantayev master->max_mtu[port] = 754ffe455adSEugenia Emantayev max(master->max_mtu[port], 755ffe455adSEugenia Emantayev master->slave_state[i].mtu[port]); 756ffe455adSEugenia Emantayev } 757ffe455adSEugenia Emantayev } 758ffe455adSEugenia Emantayev 759ffe455adSEugenia Emantayev gen_context->mtu = cpu_to_be16(master->max_mtu[port]); 760ffe455adSEugenia Emantayev break; 7619cd59352SJack Morgenstein case MLX4_SET_PORT_GID_TABLE: 762b6ffaeffSJack Morgenstein /* change to MULTIPLE entries: number of guest's gids 763b6ffaeffSJack Morgenstein * need a FOR-loop here over number of gids the guest has. 764b6ffaeffSJack Morgenstein * 1. Check no duplicates in gids passed by slave 765b6ffaeffSJack Morgenstein */ 766449fc488SMatan Barak num_gids = mlx4_get_slave_num_gids(dev, slave, port); 767449fc488SMatan Barak base = mlx4_get_base_gid_ix(dev, slave, port); 768b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 769b6ffaeffSJack Morgenstein for (i = 0; i < num_gids; gid_entry_mbox++, i++) { 770b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 771b6ffaeffSJack Morgenstein sizeof(zgid_entry))) 772b6ffaeffSJack Morgenstein continue; 773b6ffaeffSJack Morgenstein gid_entry_mb1 = gid_entry_mbox + 1; 774b6ffaeffSJack Morgenstein for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) { 775b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw, 776b6ffaeffSJack Morgenstein zgid_entry.raw, sizeof(zgid_entry))) 777b6ffaeffSJack Morgenstein continue; 778b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw, 779b6ffaeffSJack Morgenstein sizeof(gid_entry_mbox->raw))) { 780b6ffaeffSJack Morgenstein /* found duplicate */ 781b6ffaeffSJack Morgenstein return -EINVAL; 782b6ffaeffSJack Morgenstein } 783b6ffaeffSJack Morgenstein } 784b6ffaeffSJack Morgenstein } 785b6ffaeffSJack Morgenstein 786b6ffaeffSJack Morgenstein /* 2. Check that do not have duplicates in OTHER 787b6ffaeffSJack Morgenstein * entries in the port GID table 788b6ffaeffSJack Morgenstein */ 789111c6094SJack Morgenstein 790111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex)); 7919cd59352SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 792b6ffaeffSJack Morgenstein if (i >= base && i < base + num_gids) 793b6ffaeffSJack Morgenstein continue; /* don't compare to slave's current gids */ 794111c6094SJack Morgenstein gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i]; 795b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry))) 796b6ffaeffSJack Morgenstein continue; 797b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 798b6ffaeffSJack Morgenstein for (j = 0; j < num_gids; gid_entry_mbox++, j++) { 799b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 800b6ffaeffSJack Morgenstein sizeof(zgid_entry))) 801b6ffaeffSJack Morgenstein continue; 802b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw, 803b6ffaeffSJack Morgenstein sizeof(gid_entry_tbl->raw))) { 804b6ffaeffSJack Morgenstein /* found duplicate */ 8051a91de28SJoe Perches mlx4_warn(dev, "requested gid entry for slave:%d is a duplicate of gid at index %d\n", 8069cd59352SJack Morgenstein slave, i); 807111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 808b6ffaeffSJack Morgenstein return -EINVAL; 8099cd59352SJack Morgenstein } 8109cd59352SJack Morgenstein } 8119cd59352SJack Morgenstein } 812b6ffaeffSJack Morgenstein 813b6ffaeffSJack Morgenstein /* insert slave GIDs with memcpy, starting at slave's base index */ 814b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 815b6ffaeffSJack Morgenstein for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++) 816111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 817111c6094SJack Morgenstein gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE); 818b6ffaeffSJack Morgenstein 819b6ffaeffSJack Morgenstein /* Now, copy roce port gids table to current mailbox for passing to FW */ 820b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 821b6ffaeffSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 822111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw, 823111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw, 824111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 825b6ffaeffSJack Morgenstein 826111c6094SJack Morgenstein err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 827111c6094SJack Morgenstein MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 828111c6094SJack Morgenstein MLX4_CMD_NATIVE); 829111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 830111c6094SJack Morgenstein return err; 831ffe455adSEugenia Emantayev } 832111c6094SJack Morgenstein 833111c6094SJack Morgenstein return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 834ffe455adSEugenia Emantayev MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 835ffe455adSEugenia Emantayev MLX4_CMD_NATIVE); 836ffe455adSEugenia Emantayev } 837ffe455adSEugenia Emantayev 838ffe455adSEugenia Emantayev /* For IB, we only consider: 839ffe455adSEugenia Emantayev * - The capability mask, which is set to the aggregate of all 840ffe455adSEugenia Emantayev * slave function capabilities 841ffe455adSEugenia Emantayev * - The QKey violatin counter - reset according to each request. 842ffe455adSEugenia Emantayev */ 843ffe455adSEugenia Emantayev 844ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 845ffe455adSEugenia Emantayev reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40; 846ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[2]; 847ffe455adSEugenia Emantayev } else { 848ffe455adSEugenia Emantayev reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1; 849ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[1]; 850ffe455adSEugenia Emantayev } 851ffe455adSEugenia Emantayev 852efcd235dSJack Morgenstein /* slave may not set the IS_SM capability for the port */ 853efcd235dSJack Morgenstein if (slave != mlx4_master_func_num(dev) && 854efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM)) 855efcd235dSJack Morgenstein return -EINVAL; 856efcd235dSJack Morgenstein 857efcd235dSJack Morgenstein /* No DEV_MGMT in multifunc mode */ 858efcd235dSJack Morgenstein if (mlx4_is_mfunc(dev) && 859efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP)) 860efcd235dSJack Morgenstein return -EINVAL; 861efcd235dSJack Morgenstein 862ffe455adSEugenia Emantayev agg_cap_mask = 0; 863ffe455adSEugenia Emantayev slave_cap_mask = 864ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; 865ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask; 866ffe455adSEugenia Emantayev for (i = 0; i < dev->num_slaves; i++) 867ffe455adSEugenia Emantayev agg_cap_mask |= 868ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[i].ib_cap_mask[port]; 869ffe455adSEugenia Emantayev 870ffe455adSEugenia Emantayev /* only clear mailbox for guests. Master may be setting 871ffe455adSEugenia Emantayev * MTU or PKEY table size 872ffe455adSEugenia Emantayev */ 873ffe455adSEugenia Emantayev if (slave != dev->caps.function) 874ffe455adSEugenia Emantayev memset(inbox->buf, 0, 256); 875ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 876edc4a67eSJack Morgenstein *(u8 *) inbox->buf |= !!reset_qkey_viols << 6; 877ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[2] = agg_cap_mask; 878ffe455adSEugenia Emantayev } else { 879edc4a67eSJack Morgenstein ((u8 *) inbox->buf)[3] |= !!reset_qkey_viols; 880ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[1] = agg_cap_mask; 881ffe455adSEugenia Emantayev } 882ffe455adSEugenia Emantayev 883ffe455adSEugenia Emantayev err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT, 884ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 885ffe455adSEugenia Emantayev if (err) 886ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = 887ffe455adSEugenia Emantayev slave_cap_mask; 888ffe455adSEugenia Emantayev return err; 889ffe455adSEugenia Emantayev } 890ffe455adSEugenia Emantayev 891ffe455adSEugenia Emantayev int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, 892ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 893ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 894ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 895ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 896ffe455adSEugenia Emantayev { 897449fc488SMatan Barak int port = mlx4_slave_convert_port( 898449fc488SMatan Barak dev, slave, vhcr->in_modifier & 0xFF); 899449fc488SMatan Barak 900449fc488SMatan Barak if (port < 0) 901449fc488SMatan Barak return -EINVAL; 902449fc488SMatan Barak 903449fc488SMatan Barak vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) | 904449fc488SMatan Barak (port & 0xFF); 905449fc488SMatan Barak 906ffe455adSEugenia Emantayev return mlx4_common_set_port(dev, slave, vhcr->in_modifier, 907ffe455adSEugenia Emantayev vhcr->op_modifier, inbox); 908ffe455adSEugenia Emantayev } 909ffe455adSEugenia Emantayev 910096335b3SOr Gerlitz /* bit locations for set port command with zero op modifier */ 911096335b3SOr Gerlitz enum { 912096335b3SOr Gerlitz MLX4_SET_PORT_VL_CAP = 4, /* bits 7:4 */ 913096335b3SOr Gerlitz MLX4_SET_PORT_MTU_CAP = 12, /* bits 15:12 */ 9146634961cSJack Morgenstein MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20, 915096335b3SOr Gerlitz MLX4_CHANGE_PORT_VL_CAP = 21, 916096335b3SOr Gerlitz MLX4_CHANGE_PORT_MTU_CAP = 22, 917096335b3SOr Gerlitz }; 918096335b3SOr Gerlitz 9196634961cSJack Morgenstein int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz) 9205a2cc190SJeff Kirsher { 9215a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 9226634961cSJack Morgenstein int err, vl_cap, pkey_tbl_flag = 0; 9235a2cc190SJeff Kirsher 9245a2cc190SJeff Kirsher if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) 9255a2cc190SJeff Kirsher return 0; 9265a2cc190SJeff Kirsher 9275a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 9285a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 9295a2cc190SJeff Kirsher return PTR_ERR(mailbox); 9305a2cc190SJeff Kirsher 9315a2cc190SJeff Kirsher ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; 932096335b3SOr Gerlitz 9336634961cSJack Morgenstein if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) { 9346634961cSJack Morgenstein pkey_tbl_flag = 1; 9356634961cSJack Morgenstein ((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz); 9366634961cSJack Morgenstein } 9376634961cSJack Morgenstein 938096335b3SOr Gerlitz /* IB VL CAP enum isn't used by the firmware, just numerical values */ 939096335b3SOr Gerlitz for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) { 940096335b3SOr Gerlitz ((__be32 *) mailbox->buf)[0] = cpu_to_be32( 941096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_MTU_CAP) | 942096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_VL_CAP) | 9436634961cSJack Morgenstein (pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) | 944096335b3SOr Gerlitz (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) | 945096335b3SOr Gerlitz (vl_cap << MLX4_SET_PORT_VL_CAP)); 946a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, port, 947a130b590SIdo Shamay MLX4_SET_PORT_IB_OPCODE, MLX4_CMD_SET_PORT, 948f9baff50SJack Morgenstein MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 949096335b3SOr Gerlitz if (err != -ENOMEM) 950096335b3SOr Gerlitz break; 951096335b3SOr Gerlitz } 9525a2cc190SJeff Kirsher 9535a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 9545a2cc190SJeff Kirsher return err; 9555a2cc190SJeff Kirsher } 956ffe455adSEugenia Emantayev 957cb9ffb76SJoerg Roedel int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, 958ffe455adSEugenia Emantayev u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx) 959ffe455adSEugenia Emantayev { 960ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 961ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *context; 962ffe455adSEugenia Emantayev int err; 963ffe455adSEugenia Emantayev u32 in_mod; 964ffe455adSEugenia Emantayev 965ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 966ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 967ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 968ffe455adSEugenia Emantayev context = mailbox->buf; 969ffe455adSEugenia Emantayev context->flags = SET_PORT_GEN_ALL_VALID; 970ffe455adSEugenia Emantayev context->mtu = cpu_to_be16(mtu); 971ffe455adSEugenia Emantayev context->pptx = (pptx * (!pfctx)) << 7; 972ffe455adSEugenia Emantayev context->pfctx = pfctx; 973ffe455adSEugenia Emantayev context->pprx = (pprx * (!pfcrx)) << 7; 974ffe455adSEugenia Emantayev context->pfcrx = pfcrx; 975ffe455adSEugenia Emantayev 976ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 977a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 978a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 979a130b590SIdo Shamay MLX4_CMD_WRAPPED); 980ffe455adSEugenia Emantayev 981ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 982ffe455adSEugenia Emantayev return err; 983ffe455adSEugenia Emantayev } 984ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_general); 985ffe455adSEugenia Emantayev 986cb9ffb76SJoerg Roedel int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, 987ffe455adSEugenia Emantayev u8 promisc) 988ffe455adSEugenia Emantayev { 989ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 990ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *context; 991ffe455adSEugenia Emantayev int err; 992ffe455adSEugenia Emantayev u32 in_mod; 993ffe455adSEugenia Emantayev u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ? 994ffe455adSEugenia Emantayev MCAST_DIRECT : MCAST_DEFAULT; 995ffe455adSEugenia Emantayev 996c96d97f4SHadar Hen Zion if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) 997ffe455adSEugenia Emantayev return 0; 998ffe455adSEugenia Emantayev 999ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 1000ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 1001ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 1002ffe455adSEugenia Emantayev context = mailbox->buf; 1003ffe455adSEugenia Emantayev context->base_qpn = cpu_to_be32(base_qpn); 1004ffe455adSEugenia Emantayev context->n_mac = dev->caps.log_num_macs; 1005ffe455adSEugenia Emantayev context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | 1006ffe455adSEugenia Emantayev base_qpn); 1007ffe455adSEugenia Emantayev context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | 1008ffe455adSEugenia Emantayev base_qpn); 1009ffe455adSEugenia Emantayev context->intra_no_vlan = 0; 1010ffe455adSEugenia Emantayev context->no_vlan = MLX4_NO_VLAN_IDX; 1011ffe455adSEugenia Emantayev context->intra_vlan_miss = 0; 1012ffe455adSEugenia Emantayev context->vlan_miss = MLX4_VLAN_MISS_IDX; 1013ffe455adSEugenia Emantayev 1014ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port; 1015a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1016a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1017a130b590SIdo Shamay MLX4_CMD_WRAPPED); 1018ffe455adSEugenia Emantayev 1019ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 1020ffe455adSEugenia Emantayev return err; 1021ffe455adSEugenia Emantayev } 1022ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); 1023ffe455adSEugenia Emantayev 10247ffdf726SOr Gerlitz enum { 10257ffdf726SOr Gerlitz VXLAN_ENABLE_MODIFY = 1 << 7, 10267ffdf726SOr Gerlitz VXLAN_STEERING_MODIFY = 1 << 6, 10277ffdf726SOr Gerlitz 10287ffdf726SOr Gerlitz VXLAN_ENABLE = 1 << 7, 10297ffdf726SOr Gerlitz }; 10307ffdf726SOr Gerlitz 10317ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context { 10327ffdf726SOr Gerlitz u32 reserved1; 10337ffdf726SOr Gerlitz u8 modify_flags; 10347ffdf726SOr Gerlitz u8 reserved2; 10357ffdf726SOr Gerlitz u8 enable_flags; 10367ffdf726SOr Gerlitz u8 steering; 10377ffdf726SOr Gerlitz }; 10387ffdf726SOr Gerlitz 10391b136de1SOr Gerlitz int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable) 10407ffdf726SOr Gerlitz { 10417ffdf726SOr Gerlitz int err; 10427ffdf726SOr Gerlitz u32 in_mod; 10437ffdf726SOr Gerlitz struct mlx4_cmd_mailbox *mailbox; 10447ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context *context; 10457ffdf726SOr Gerlitz 10467ffdf726SOr Gerlitz mailbox = mlx4_alloc_cmd_mailbox(dev); 10477ffdf726SOr Gerlitz if (IS_ERR(mailbox)) 10487ffdf726SOr Gerlitz return PTR_ERR(mailbox); 10497ffdf726SOr Gerlitz context = mailbox->buf; 10507ffdf726SOr Gerlitz memset(context, 0, sizeof(*context)); 10517ffdf726SOr Gerlitz 10527ffdf726SOr Gerlitz context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY; 10531b136de1SOr Gerlitz if (enable) 10547ffdf726SOr Gerlitz context->enable_flags = VXLAN_ENABLE; 10557ffdf726SOr Gerlitz context->steering = steering; 10567ffdf726SOr Gerlitz 10577ffdf726SOr Gerlitz in_mod = MLX4_SET_PORT_VXLAN << 8 | port; 1058a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, 1059a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 1060a130b590SIdo Shamay MLX4_CMD_NATIVE); 10617ffdf726SOr Gerlitz 10627ffdf726SOr Gerlitz mlx4_free_cmd_mailbox(dev, mailbox); 10637ffdf726SOr Gerlitz return err; 10647ffdf726SOr Gerlitz } 10657ffdf726SOr Gerlitz EXPORT_SYMBOL(mlx4_SET_PORT_VXLAN); 10667ffdf726SOr Gerlitz 1067ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1068ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1069ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1070ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1071ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1072ffe455adSEugenia Emantayev { 1073ffe455adSEugenia Emantayev int err = 0; 1074ffe455adSEugenia Emantayev 1075ffe455adSEugenia Emantayev return err; 1076ffe455adSEugenia Emantayev } 1077ffe455adSEugenia Emantayev 1078ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, 1079ffe455adSEugenia Emantayev u64 mac, u64 clear, u8 mode) 1080ffe455adSEugenia Emantayev { 1081ffe455adSEugenia Emantayev return mlx4_cmd(dev, (mac | (clear << 63)), port, mode, 1082ffe455adSEugenia Emantayev MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B, 1083ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 1084ffe455adSEugenia Emantayev } 1085ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR); 1086ffe455adSEugenia Emantayev 1087ffe455adSEugenia Emantayev int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1088ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1089ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1090ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1091ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1092ffe455adSEugenia Emantayev { 1093ffe455adSEugenia Emantayev int err = 0; 1094ffe455adSEugenia Emantayev 1095ffe455adSEugenia Emantayev return err; 1096ffe455adSEugenia Emantayev } 1097ffe455adSEugenia Emantayev 1098ffe455adSEugenia Emantayev int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave, 1099ffe455adSEugenia Emantayev u32 in_mod, struct mlx4_cmd_mailbox *outbox) 1100ffe455adSEugenia Emantayev { 1101ffe455adSEugenia Emantayev return mlx4_cmd_box(dev, 0, outbox->dma, in_mod, 0, 1102ffe455adSEugenia Emantayev MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B, 1103ffe455adSEugenia Emantayev MLX4_CMD_NATIVE); 1104ffe455adSEugenia Emantayev } 1105ffe455adSEugenia Emantayev 1106ffe455adSEugenia Emantayev int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, 1107ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1108ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1109ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1110ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1111ffe455adSEugenia Emantayev { 111235fb9afbSEugenia Emantayev if (slave != dev->caps.function) 111335fb9afbSEugenia Emantayev return 0; 1114ffe455adSEugenia Emantayev return mlx4_common_dump_eth_stats(dev, slave, 1115ffe455adSEugenia Emantayev vhcr->in_modifier, outbox); 1116ffe455adSEugenia Emantayev } 111793ece0c1SEugenia Emantayev 11189cd59352SJack Morgenstein int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, 11199cd59352SJack Morgenstein int *slave_id) 11206ee51a4eSJack Morgenstein { 11216ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 11226ee51a4eSJack Morgenstein int i, found_ix = -1; 1123b6ffaeffSJack Morgenstein int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 1124449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 1125449fc488SMatan Barak unsigned num_vfs; 1126449fc488SMatan Barak int slave_gid; 11276ee51a4eSJack Morgenstein 11286ee51a4eSJack Morgenstein if (!mlx4_is_mfunc(dev)) 11296ee51a4eSJack Morgenstein return -EINVAL; 11306ee51a4eSJack Morgenstein 1131449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1132872bf2fbSYishai Hadas num_vfs = bitmap_weight(slaves_pport.slaves, 1133872bf2fbSYishai Hadas dev->persist->num_vfs + 1) - 1; 1134449fc488SMatan Barak 11356ee51a4eSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 1136111c6094SJack Morgenstein if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid, 1137111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE)) { 11386ee51a4eSJack Morgenstein found_ix = i; 11396ee51a4eSJack Morgenstein break; 11406ee51a4eSJack Morgenstein } 11416ee51a4eSJack Morgenstein } 11426ee51a4eSJack Morgenstein 1143b6ffaeffSJack Morgenstein if (found_ix >= 0) { 11440254bc82SMatan Barak /* Calculate a slave_gid which is the slave number in the gid 11450254bc82SMatan Barak * table and not a globally unique slave number. 11460254bc82SMatan Barak */ 1147b6ffaeffSJack Morgenstein if (found_ix < MLX4_ROCE_PF_GIDS) 1148449fc488SMatan Barak slave_gid = 0; 1149449fc488SMatan Barak else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) * 1150449fc488SMatan Barak (vf_gids / num_vfs + 1)) 1151449fc488SMatan Barak slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) / 1152449fc488SMatan Barak (vf_gids / num_vfs + 1)) + 1; 1153b6ffaeffSJack Morgenstein else 1154449fc488SMatan Barak slave_gid = 1155b6ffaeffSJack Morgenstein ((found_ix - MLX4_ROCE_PF_GIDS - 1156449fc488SMatan Barak ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) / 1157449fc488SMatan Barak (vf_gids / num_vfs)) + vf_gids % num_vfs + 1; 1158449fc488SMatan Barak 11590254bc82SMatan Barak /* Calculate the globally unique slave id */ 1160449fc488SMatan Barak if (slave_gid) { 1161449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 1162449fc488SMatan Barak struct mlx4_active_ports actv_ports; 1163449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 1164449fc488SMatan Barak unsigned max_port_p_one; 11650254bc82SMatan Barak int num_vfs_before = 0; 11660254bc82SMatan Barak int candidate_slave_gid; 1167449fc488SMatan Barak 11680254bc82SMatan Barak /* Calculate how many VFs are on the previous port, if exists */ 1169449fc488SMatan Barak for (i = 1; i < port; i++) { 1170449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 11710254bc82SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1172449fc488SMatan Barak slaves_pport_actv = 1173449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv( 1174449fc488SMatan Barak dev, &exclusive_ports); 11750254bc82SMatan Barak num_vfs_before += bitmap_weight( 1176449fc488SMatan Barak slaves_pport_actv.slaves, 1177872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1178449fc488SMatan Barak } 1179449fc488SMatan Barak 11800254bc82SMatan Barak /* candidate_slave_gid isn't necessarily the correct slave, but 11810254bc82SMatan Barak * it has the same number of ports and is assigned to the same 11820254bc82SMatan Barak * ports as the real slave we're looking for. On dual port VF, 11830254bc82SMatan Barak * slave_gid = [single port VFs on port <port>] + 11840254bc82SMatan Barak * [offset of the current slave from the first dual port VF] + 11850254bc82SMatan Barak * 1 (for the PF). 11860254bc82SMatan Barak */ 11870254bc82SMatan Barak candidate_slave_gid = slave_gid + num_vfs_before; 11880254bc82SMatan Barak 11890254bc82SMatan Barak actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid); 1190449fc488SMatan Barak max_port_p_one = find_first_bit( 1191449fc488SMatan Barak actv_ports.ports, dev->caps.num_ports) + 1192449fc488SMatan Barak bitmap_weight(actv_ports.ports, 1193449fc488SMatan Barak dev->caps.num_ports) + 1; 1194449fc488SMatan Barak 11950254bc82SMatan Barak /* Calculate the real slave number */ 1196449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 1197449fc488SMatan Barak if (i == port) 1198449fc488SMatan Barak continue; 1199449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, 1200449fc488SMatan Barak dev->caps.num_ports); 1201449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1202449fc488SMatan Barak slaves_pport_actv = 1203449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv( 1204449fc488SMatan Barak dev, &exclusive_ports); 1205449fc488SMatan Barak slave_gid += bitmap_weight( 1206449fc488SMatan Barak slaves_pport_actv.slaves, 1207872bf2fbSYishai Hadas dev->persist->num_vfs + 1); 1208449fc488SMatan Barak } 1209449fc488SMatan Barak } 1210449fc488SMatan Barak *slave_id = slave_gid; 1211b6ffaeffSJack Morgenstein } 12126ee51a4eSJack Morgenstein 12136ee51a4eSJack Morgenstein return (found_ix >= 0) ? 0 : -EINVAL; 12146ee51a4eSJack Morgenstein } 12156ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid); 12166ee51a4eSJack Morgenstein 12179cd59352SJack Morgenstein int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, 12189cd59352SJack Morgenstein u8 *gid) 12196ee51a4eSJack Morgenstein { 12206ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 12216ee51a4eSJack Morgenstein 12226ee51a4eSJack Morgenstein if (!mlx4_is_master(dev)) 12236ee51a4eSJack Morgenstein return -EINVAL; 12246ee51a4eSJack Morgenstein 1225111c6094SJack Morgenstein memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw, 1226111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 12276ee51a4eSJack Morgenstein return 0; 12286ee51a4eSJack Morgenstein } 12296ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); 123032a173c7SSaeed Mahameed 123132a173c7SSaeed Mahameed /* Cable Module Info */ 123232a173c7SSaeed Mahameed #define MODULE_INFO_MAX_READ 48 123332a173c7SSaeed Mahameed 123432a173c7SSaeed Mahameed #define I2C_ADDR_LOW 0x50 123532a173c7SSaeed Mahameed #define I2C_ADDR_HIGH 0x51 123632a173c7SSaeed Mahameed #define I2C_PAGE_SIZE 256 123732a173c7SSaeed Mahameed 123832a173c7SSaeed Mahameed /* Module Info Data */ 123932a173c7SSaeed Mahameed struct mlx4_cable_info { 124032a173c7SSaeed Mahameed u8 i2c_addr; 124132a173c7SSaeed Mahameed u8 page_num; 124232a173c7SSaeed Mahameed __be16 dev_mem_address; 124332a173c7SSaeed Mahameed __be16 reserved1; 124432a173c7SSaeed Mahameed __be16 size; 124532a173c7SSaeed Mahameed __be32 reserved2[2]; 124632a173c7SSaeed Mahameed u8 data[MODULE_INFO_MAX_READ]; 124732a173c7SSaeed Mahameed }; 124832a173c7SSaeed Mahameed 124932a173c7SSaeed Mahameed enum cable_info_err { 125032a173c7SSaeed Mahameed CABLE_INF_INV_PORT = 0x1, 125132a173c7SSaeed Mahameed CABLE_INF_OP_NOSUP = 0x2, 125232a173c7SSaeed Mahameed CABLE_INF_NOT_CONN = 0x3, 125332a173c7SSaeed Mahameed CABLE_INF_NO_EEPRM = 0x4, 125432a173c7SSaeed Mahameed CABLE_INF_PAGE_ERR = 0x5, 125532a173c7SSaeed Mahameed CABLE_INF_INV_ADDR = 0x6, 125632a173c7SSaeed Mahameed CABLE_INF_I2C_ADDR = 0x7, 125732a173c7SSaeed Mahameed CABLE_INF_QSFP_VIO = 0x8, 125832a173c7SSaeed Mahameed CABLE_INF_I2C_BUSY = 0x9, 125932a173c7SSaeed Mahameed }; 126032a173c7SSaeed Mahameed 126132a173c7SSaeed Mahameed #define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF) 126232a173c7SSaeed Mahameed 126332a173c7SSaeed Mahameed static inline const char *cable_info_mad_err_str(u16 mad_status) 126432a173c7SSaeed Mahameed { 126532a173c7SSaeed Mahameed u8 err = MAD_STATUS_2_CABLE_ERR(mad_status); 126632a173c7SSaeed Mahameed 126732a173c7SSaeed Mahameed switch (err) { 126832a173c7SSaeed Mahameed case CABLE_INF_INV_PORT: 126932a173c7SSaeed Mahameed return "invalid port selected"; 127032a173c7SSaeed Mahameed case CABLE_INF_OP_NOSUP: 127132a173c7SSaeed Mahameed return "operation not supported for this port (the port is of type CX4 or internal)"; 127232a173c7SSaeed Mahameed case CABLE_INF_NOT_CONN: 127332a173c7SSaeed Mahameed return "cable is not connected"; 127432a173c7SSaeed Mahameed case CABLE_INF_NO_EEPRM: 127532a173c7SSaeed Mahameed return "the connected cable has no EPROM (passive copper cable)"; 127632a173c7SSaeed Mahameed case CABLE_INF_PAGE_ERR: 127732a173c7SSaeed Mahameed return "page number is greater than 15"; 127832a173c7SSaeed Mahameed case CABLE_INF_INV_ADDR: 127932a173c7SSaeed Mahameed return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)"; 128032a173c7SSaeed Mahameed case CABLE_INF_I2C_ADDR: 128132a173c7SSaeed Mahameed return "invalid I2C slave address"; 128232a173c7SSaeed Mahameed case CABLE_INF_QSFP_VIO: 128332a173c7SSaeed Mahameed return "at least one cable violates the QSFP specification and ignores the modsel signal"; 128432a173c7SSaeed Mahameed case CABLE_INF_I2C_BUSY: 128532a173c7SSaeed Mahameed return "I2C bus is constantly busy"; 128632a173c7SSaeed Mahameed } 128732a173c7SSaeed Mahameed return "Unknown Error"; 128832a173c7SSaeed Mahameed } 128932a173c7SSaeed Mahameed 129032a173c7SSaeed Mahameed /** 129132a173c7SSaeed Mahameed * mlx4_get_module_info - Read cable module eeprom data 129232a173c7SSaeed Mahameed * @dev: mlx4_dev. 129332a173c7SSaeed Mahameed * @port: port number. 129432a173c7SSaeed Mahameed * @offset: byte offset in eeprom to start reading data from. 129532a173c7SSaeed Mahameed * @size: num of bytes to read. 129632a173c7SSaeed Mahameed * @data: output buffer to put the requested data into. 129732a173c7SSaeed Mahameed * 129832a173c7SSaeed Mahameed * Reads cable module eeprom data, puts the outcome data into 129932a173c7SSaeed Mahameed * data pointer paramer. 130032a173c7SSaeed Mahameed * Returns num of read bytes on success or a negative error 130132a173c7SSaeed Mahameed * code. 130232a173c7SSaeed Mahameed */ 130332a173c7SSaeed Mahameed int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, 130432a173c7SSaeed Mahameed u16 offset, u16 size, u8 *data) 130532a173c7SSaeed Mahameed { 130632a173c7SSaeed Mahameed struct mlx4_cmd_mailbox *inbox, *outbox; 130732a173c7SSaeed Mahameed struct mlx4_mad_ifc *inmad, *outmad; 130832a173c7SSaeed Mahameed struct mlx4_cable_info *cable_info; 130932a173c7SSaeed Mahameed u16 i2c_addr; 131032a173c7SSaeed Mahameed int ret; 131132a173c7SSaeed Mahameed 131232a173c7SSaeed Mahameed if (size > MODULE_INFO_MAX_READ) 131332a173c7SSaeed Mahameed size = MODULE_INFO_MAX_READ; 131432a173c7SSaeed Mahameed 131532a173c7SSaeed Mahameed inbox = mlx4_alloc_cmd_mailbox(dev); 131632a173c7SSaeed Mahameed if (IS_ERR(inbox)) 131732a173c7SSaeed Mahameed return PTR_ERR(inbox); 131832a173c7SSaeed Mahameed 131932a173c7SSaeed Mahameed outbox = mlx4_alloc_cmd_mailbox(dev); 132032a173c7SSaeed Mahameed if (IS_ERR(outbox)) { 132132a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, inbox); 132232a173c7SSaeed Mahameed return PTR_ERR(outbox); 132332a173c7SSaeed Mahameed } 132432a173c7SSaeed Mahameed 132532a173c7SSaeed Mahameed inmad = (struct mlx4_mad_ifc *)(inbox->buf); 132632a173c7SSaeed Mahameed outmad = (struct mlx4_mad_ifc *)(outbox->buf); 132732a173c7SSaeed Mahameed 132832a173c7SSaeed Mahameed inmad->method = 0x1; /* Get */ 132932a173c7SSaeed Mahameed inmad->class_version = 0x1; 133032a173c7SSaeed Mahameed inmad->mgmt_class = 0x1; 133132a173c7SSaeed Mahameed inmad->base_version = 0x1; 133232a173c7SSaeed Mahameed inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */ 133332a173c7SSaeed Mahameed 133432a173c7SSaeed Mahameed if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE) 133532a173c7SSaeed Mahameed /* Cross pages reads are not allowed 133632a173c7SSaeed Mahameed * read until offset 256 in low page 133732a173c7SSaeed Mahameed */ 133832a173c7SSaeed Mahameed size -= offset + size - I2C_PAGE_SIZE; 133932a173c7SSaeed Mahameed 134032a173c7SSaeed Mahameed i2c_addr = I2C_ADDR_LOW; 134132a173c7SSaeed Mahameed if (offset >= I2C_PAGE_SIZE) { 134232a173c7SSaeed Mahameed /* Reset offset to high page */ 134332a173c7SSaeed Mahameed i2c_addr = I2C_ADDR_HIGH; 134432a173c7SSaeed Mahameed offset -= I2C_PAGE_SIZE; 134532a173c7SSaeed Mahameed } 134632a173c7SSaeed Mahameed 134732a173c7SSaeed Mahameed cable_info = (struct mlx4_cable_info *)inmad->data; 134832a173c7SSaeed Mahameed cable_info->dev_mem_address = cpu_to_be16(offset); 134932a173c7SSaeed Mahameed cable_info->page_num = 0; 135032a173c7SSaeed Mahameed cable_info->i2c_addr = i2c_addr; 135132a173c7SSaeed Mahameed cable_info->size = cpu_to_be16(size); 135232a173c7SSaeed Mahameed 135332a173c7SSaeed Mahameed ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, 135432a173c7SSaeed Mahameed MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 135532a173c7SSaeed Mahameed MLX4_CMD_NATIVE); 135632a173c7SSaeed Mahameed if (ret) 135732a173c7SSaeed Mahameed goto out; 135832a173c7SSaeed Mahameed 135932a173c7SSaeed Mahameed if (be16_to_cpu(outmad->status)) { 136032a173c7SSaeed Mahameed /* Mad returned with bad status */ 136132a173c7SSaeed Mahameed ret = be16_to_cpu(outmad->status); 136232a173c7SSaeed Mahameed mlx4_warn(dev, 136332a173c7SSaeed 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", 136432a173c7SSaeed Mahameed 0xFF60, port, i2c_addr, offset, size, 136532a173c7SSaeed Mahameed ret, cable_info_mad_err_str(ret)); 136632a173c7SSaeed Mahameed 136732a173c7SSaeed Mahameed if (i2c_addr == I2C_ADDR_HIGH && 136832a173c7SSaeed Mahameed MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR) 136932a173c7SSaeed Mahameed /* Some SFP cables do not support i2c slave 137032a173c7SSaeed Mahameed * address 0x51 (high page), abort silently. 137132a173c7SSaeed Mahameed */ 137232a173c7SSaeed Mahameed ret = 0; 137332a173c7SSaeed Mahameed else 137432a173c7SSaeed Mahameed ret = -ret; 137532a173c7SSaeed Mahameed goto out; 137632a173c7SSaeed Mahameed } 137732a173c7SSaeed Mahameed cable_info = (struct mlx4_cable_info *)outmad->data; 137832a173c7SSaeed Mahameed memcpy(data, cable_info->data, size); 137932a173c7SSaeed Mahameed ret = size; 138032a173c7SSaeed Mahameed out: 138132a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, inbox); 138232a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, outbox); 138332a173c7SSaeed Mahameed return ret; 138432a173c7SSaeed Mahameed } 138532a173c7SSaeed Mahameed EXPORT_SYMBOL(mlx4_get_module_info); 1386