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" 415a2cc190SJeff Kirsher 425a2cc190SJeff Kirsher #define MLX4_MAC_VALID (1ull << 63) 435a2cc190SJeff Kirsher 445a2cc190SJeff Kirsher #define MLX4_VLAN_VALID (1u << 31) 455a2cc190SJeff Kirsher #define MLX4_VLAN_MASK 0xfff 465a2cc190SJeff Kirsher 4793ece0c1SEugenia Emantayev #define MLX4_STATS_TRAFFIC_COUNTERS_MASK 0xfULL 4893ece0c1SEugenia Emantayev #define MLX4_STATS_TRAFFIC_DROPS_MASK 0xc0ULL 4993ece0c1SEugenia Emantayev #define MLX4_STATS_ERROR_COUNTERS_MASK 0x1ffc30ULL 5093ece0c1SEugenia Emantayev #define MLX4_STATS_PORT_COUNTERS_MASK 0x1fe00000ULL 5193ece0c1SEugenia Emantayev 525a2cc190SJeff Kirsher void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table) 535a2cc190SJeff Kirsher { 545a2cc190SJeff Kirsher int i; 555a2cc190SJeff Kirsher 565a2cc190SJeff Kirsher mutex_init(&table->mutex); 575a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 585a2cc190SJeff Kirsher table->entries[i] = 0; 595a2cc190SJeff Kirsher table->refs[i] = 0; 605a2cc190SJeff Kirsher } 615a2cc190SJeff Kirsher table->max = 1 << dev->caps.log_num_macs; 625a2cc190SJeff Kirsher table->total = 0; 635a2cc190SJeff Kirsher } 645a2cc190SJeff Kirsher 655a2cc190SJeff Kirsher void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table) 665a2cc190SJeff Kirsher { 675a2cc190SJeff Kirsher int i; 685a2cc190SJeff Kirsher 695a2cc190SJeff Kirsher mutex_init(&table->mutex); 705a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { 715a2cc190SJeff Kirsher table->entries[i] = 0; 725a2cc190SJeff Kirsher table->refs[i] = 0; 735a2cc190SJeff Kirsher } 74e72ebf5aSYevgeny Petrilin table->max = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR; 755a2cc190SJeff Kirsher table->total = 0; 765a2cc190SJeff Kirsher } 775a2cc190SJeff Kirsher 78111c6094SJack Morgenstein void mlx4_init_roce_gid_table(struct mlx4_dev *dev, 79111c6094SJack Morgenstein struct mlx4_roce_gid_table *table) 80111c6094SJack Morgenstein { 81111c6094SJack Morgenstein int i; 82111c6094SJack Morgenstein 83111c6094SJack Morgenstein mutex_init(&table->mutex); 84111c6094SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) 85111c6094SJack Morgenstein memset(table->roce_gids[i].raw, 0, MLX4_ROCE_GID_ENTRY_SIZE); 86111c6094SJack Morgenstein } 87111c6094SJack Morgenstein 885a2cc190SJeff Kirsher static int validate_index(struct mlx4_dev *dev, 895a2cc190SJeff Kirsher struct mlx4_mac_table *table, int index) 905a2cc190SJeff Kirsher { 915a2cc190SJeff Kirsher int err = 0; 925a2cc190SJeff Kirsher 935a2cc190SJeff Kirsher if (index < 0 || index >= table->max || !table->entries[index]) { 945a2cc190SJeff Kirsher mlx4_warn(dev, "No valid Mac entry for the given index\n"); 955a2cc190SJeff Kirsher err = -EINVAL; 965a2cc190SJeff Kirsher } 975a2cc190SJeff Kirsher return err; 985a2cc190SJeff Kirsher } 995a2cc190SJeff Kirsher 1005a2cc190SJeff Kirsher static int find_index(struct mlx4_dev *dev, 1015a2cc190SJeff Kirsher struct mlx4_mac_table *table, u64 mac) 1025a2cc190SJeff Kirsher { 1035a2cc190SJeff Kirsher int i; 104ffe455adSEugenia Emantayev 1055a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 106ffe455adSEugenia Emantayev if ((mac & MLX4_MAC_MASK) == 107ffe455adSEugenia Emantayev (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) 1085a2cc190SJeff Kirsher return i; 1095a2cc190SJeff Kirsher } 1105a2cc190SJeff Kirsher /* Mac not found */ 1115a2cc190SJeff Kirsher return -EINVAL; 1125a2cc190SJeff Kirsher } 1135a2cc190SJeff Kirsher 114ffe455adSEugenia Emantayev static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, 115ffe455adSEugenia Emantayev __be64 *entries) 116ffe455adSEugenia Emantayev { 117ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 118ffe455adSEugenia Emantayev u32 in_mod; 119ffe455adSEugenia Emantayev int err; 120ffe455adSEugenia Emantayev 121ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 122ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 123ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 124ffe455adSEugenia Emantayev 125ffe455adSEugenia Emantayev memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); 126ffe455adSEugenia Emantayev 127ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; 128ffe455adSEugenia Emantayev 129ffe455adSEugenia Emantayev err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 130ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 131ffe455adSEugenia Emantayev 132ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 133ffe455adSEugenia Emantayev return err; 134ffe455adSEugenia Emantayev } 135ffe455adSEugenia Emantayev 136297e0dadSMoni Shoua int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx) 137297e0dadSMoni Shoua { 138297e0dadSMoni Shoua struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 139297e0dadSMoni Shoua struct mlx4_mac_table *table = &info->mac_table; 140297e0dadSMoni Shoua int i; 141297e0dadSMoni Shoua 142297e0dadSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 143297e0dadSMoni Shoua if (!table->refs[i]) 144297e0dadSMoni Shoua continue; 145297e0dadSMoni Shoua 146297e0dadSMoni Shoua if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 147297e0dadSMoni Shoua *idx = i; 148297e0dadSMoni Shoua return 0; 149297e0dadSMoni Shoua } 150297e0dadSMoni Shoua } 151297e0dadSMoni Shoua 152297e0dadSMoni Shoua return -ENOENT; 153297e0dadSMoni Shoua } 154297e0dadSMoni Shoua EXPORT_SYMBOL_GPL(mlx4_find_cached_mac); 155297e0dadSMoni Shoua 156ffe455adSEugenia Emantayev int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 157ffe455adSEugenia Emantayev { 158ffe455adSEugenia Emantayev struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 159ffe455adSEugenia Emantayev struct mlx4_mac_table *table = &info->mac_table; 160ffe455adSEugenia Emantayev int i, err = 0; 161ffe455adSEugenia Emantayev int free = -1; 162ffe455adSEugenia Emantayev 163ffe455adSEugenia Emantayev mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d\n", 164ffe455adSEugenia Emantayev (unsigned long long) mac, port); 165ffe455adSEugenia Emantayev 166ffe455adSEugenia Emantayev mutex_lock(&table->mutex); 167ffe455adSEugenia Emantayev for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 168ffe455adSEugenia Emantayev if (free < 0 && !table->entries[i]) { 169ffe455adSEugenia Emantayev free = i; 170ffe455adSEugenia Emantayev continue; 171ffe455adSEugenia Emantayev } 172ffe455adSEugenia Emantayev 173ffe455adSEugenia Emantayev if (mac == (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 { 247ffe455adSEugenia Emantayev struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 248ffe455adSEugenia Emantayev struct mlx4_mac_table *table = &info->mac_table; 249ffe455adSEugenia Emantayev int index; 250ffe455adSEugenia Emantayev 2515a2cc190SJeff Kirsher mutex_lock(&table->mutex); 2526ce71acdSRony Efraim index = find_index(dev, table, mac); 2535a2cc190SJeff Kirsher 2545a2cc190SJeff Kirsher if (validate_index(dev, table, index)) 2555a2cc190SJeff Kirsher goto out; 2566ce71acdSRony Efraim if (--table->refs[index]) { 2571a91de28SJoe Perches mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n", 2581a91de28SJoe Perches index); 2596ce71acdSRony Efraim goto out; 2606ce71acdSRony Efraim } 2615a2cc190SJeff Kirsher 2625a2cc190SJeff Kirsher table->entries[index] = 0; 2635a2cc190SJeff Kirsher mlx4_set_port_mac_table(dev, port, table->entries); 2645a2cc190SJeff Kirsher --table->total; 2655a2cc190SJeff Kirsher out: 2665a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 2675a2cc190SJeff Kirsher } 268ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_unregister_mac); 269ffe455adSEugenia Emantayev 270ffe455adSEugenia Emantayev void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 271ffe455adSEugenia Emantayev { 272e7dbeba8SJack Morgenstein u64 out_param = 0; 273ffe455adSEugenia Emantayev 274ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 275acddd5ddSJack Morgenstein if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 276acddd5ddSJack Morgenstein (void) mlx4_cmd_imm(dev, mac, &out_param, 277acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_MAC, 278acddd5ddSJack Morgenstein RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 279acddd5ddSJack Morgenstein MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 280acddd5ddSJack Morgenstein } else { 281acddd5ddSJack Morgenstein /* use old unregister mac format */ 282ffe455adSEugenia Emantayev set_param_l(&out_param, port); 283162344edSOr Gerlitz (void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 284ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 285ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 286acddd5ddSJack Morgenstein } 287ffe455adSEugenia Emantayev return; 288ffe455adSEugenia Emantayev } 289ffe455adSEugenia Emantayev __mlx4_unregister_mac(dev, port, mac); 290ffe455adSEugenia Emantayev return; 291ffe455adSEugenia Emantayev } 2925a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_mac); 2935a2cc190SJeff Kirsher 29416a10ffdSYan Burman int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac) 2955a2cc190SJeff Kirsher { 2965a2cc190SJeff Kirsher struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 2975a2cc190SJeff Kirsher struct mlx4_mac_table *table = &info->mac_table; 298ffe455adSEugenia Emantayev int index = qpn - info->base_qpn; 299ffe455adSEugenia Emantayev int err = 0; 3005a2cc190SJeff Kirsher 301ffe455adSEugenia Emantayev /* CX1 doesn't support multi-functions */ 3025a2cc190SJeff Kirsher mutex_lock(&table->mutex); 3035a2cc190SJeff Kirsher 3045a2cc190SJeff Kirsher err = validate_index(dev, table, index); 3055a2cc190SJeff Kirsher if (err) 3065a2cc190SJeff Kirsher goto out; 3075a2cc190SJeff Kirsher 3085a2cc190SJeff Kirsher table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); 3095a2cc190SJeff Kirsher 3105a2cc190SJeff Kirsher err = mlx4_set_port_mac_table(dev, port, table->entries); 3115a2cc190SJeff Kirsher if (unlikely(err)) { 312ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 313ffe455adSEugenia Emantayev (unsigned long long) new_mac); 3145a2cc190SJeff Kirsher table->entries[index] = 0; 3155a2cc190SJeff Kirsher } 3165a2cc190SJeff Kirsher out: 3175a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 3185a2cc190SJeff Kirsher return err; 3195a2cc190SJeff Kirsher } 32016a10ffdSYan Burman EXPORT_SYMBOL_GPL(__mlx4_replace_mac); 321ffe455adSEugenia Emantayev 3225a2cc190SJeff Kirsher static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, 3235a2cc190SJeff Kirsher __be32 *entries) 3245a2cc190SJeff Kirsher { 3255a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 3265a2cc190SJeff Kirsher u32 in_mod; 3275a2cc190SJeff Kirsher int err; 3285a2cc190SJeff Kirsher 3295a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 3305a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 3315a2cc190SJeff Kirsher return PTR_ERR(mailbox); 3325a2cc190SJeff Kirsher 3335a2cc190SJeff Kirsher memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); 3345a2cc190SJeff Kirsher in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; 3355a2cc190SJeff Kirsher err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 336162226a1SJack Morgenstein MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 3375a2cc190SJeff Kirsher 3385a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 3395a2cc190SJeff Kirsher 3405a2cc190SJeff Kirsher return err; 3415a2cc190SJeff Kirsher } 3425a2cc190SJeff Kirsher 3435a2cc190SJeff Kirsher int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx) 3445a2cc190SJeff Kirsher { 3455a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 3465a2cc190SJeff Kirsher int i; 3475a2cc190SJeff Kirsher 3485a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) { 3495a2cc190SJeff Kirsher if (table->refs[i] && 3505a2cc190SJeff Kirsher (vid == (MLX4_VLAN_MASK & 3515a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 3525a2cc190SJeff Kirsher /* VLAN already registered, increase reference count */ 3535a2cc190SJeff Kirsher *idx = i; 3545a2cc190SJeff Kirsher return 0; 3555a2cc190SJeff Kirsher } 3565a2cc190SJeff Kirsher } 3575a2cc190SJeff Kirsher 3585a2cc190SJeff Kirsher return -ENOENT; 3595a2cc190SJeff Kirsher } 3605a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan); 3615a2cc190SJeff Kirsher 3623f7fb021SRony Efraim int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, 363ffe455adSEugenia Emantayev int *index) 3645a2cc190SJeff Kirsher { 3655a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 3665a2cc190SJeff Kirsher int i, err = 0; 3675a2cc190SJeff Kirsher int free = -1; 3685a2cc190SJeff Kirsher 3695a2cc190SJeff Kirsher mutex_lock(&table->mutex); 370e72ebf5aSYevgeny Petrilin 371e72ebf5aSYevgeny Petrilin if (table->total == table->max) { 372e72ebf5aSYevgeny Petrilin /* No free vlan entries */ 373e72ebf5aSYevgeny Petrilin err = -ENOSPC; 374e72ebf5aSYevgeny Petrilin goto out; 375e72ebf5aSYevgeny Petrilin } 376e72ebf5aSYevgeny Petrilin 3775a2cc190SJeff Kirsher for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 3785a2cc190SJeff Kirsher if (free < 0 && (table->refs[i] == 0)) { 3795a2cc190SJeff Kirsher free = i; 3805a2cc190SJeff Kirsher continue; 3815a2cc190SJeff Kirsher } 3825a2cc190SJeff Kirsher 3835a2cc190SJeff Kirsher if (table->refs[i] && 3845a2cc190SJeff Kirsher (vlan == (MLX4_VLAN_MASK & 3855a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 3865a2cc190SJeff Kirsher /* Vlan already registered, increase references count */ 3875a2cc190SJeff Kirsher *index = i; 3885a2cc190SJeff Kirsher ++table->refs[i]; 3895a2cc190SJeff Kirsher goto out; 3905a2cc190SJeff Kirsher } 3915a2cc190SJeff Kirsher } 3925a2cc190SJeff Kirsher 3935a2cc190SJeff Kirsher if (free < 0) { 3945a2cc190SJeff Kirsher err = -ENOMEM; 3955a2cc190SJeff Kirsher goto out; 3965a2cc190SJeff Kirsher } 3975a2cc190SJeff Kirsher 398ffe455adSEugenia Emantayev /* Register new VLAN */ 3995a2cc190SJeff Kirsher table->refs[free] = 1; 4005a2cc190SJeff Kirsher table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 4015a2cc190SJeff Kirsher 4025a2cc190SJeff Kirsher err = mlx4_set_port_vlan_table(dev, port, table->entries); 4035a2cc190SJeff Kirsher if (unlikely(err)) { 4045a2cc190SJeff Kirsher mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); 4055a2cc190SJeff Kirsher table->refs[free] = 0; 4065a2cc190SJeff Kirsher table->entries[free] = 0; 4075a2cc190SJeff Kirsher goto out; 4085a2cc190SJeff Kirsher } 4095a2cc190SJeff Kirsher 4105a2cc190SJeff Kirsher *index = free; 4115a2cc190SJeff Kirsher ++table->total; 4125a2cc190SJeff Kirsher out: 4135a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 4145a2cc190SJeff Kirsher return err; 4155a2cc190SJeff Kirsher } 416ffe455adSEugenia Emantayev 417ffe455adSEugenia Emantayev int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) 418ffe455adSEugenia Emantayev { 419e7dbeba8SJack Morgenstein u64 out_param = 0; 420ffe455adSEugenia Emantayev int err; 421ffe455adSEugenia Emantayev 422162226a1SJack Morgenstein if (vlan > 4095) 423162226a1SJack Morgenstein return -EINVAL; 424162226a1SJack Morgenstein 425ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 426acddd5ddSJack Morgenstein err = mlx4_cmd_imm(dev, vlan, &out_param, 427acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN, 428ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 429ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 430ffe455adSEugenia Emantayev if (!err) 431ffe455adSEugenia Emantayev *index = get_param_l(&out_param); 432ffe455adSEugenia Emantayev 433ffe455adSEugenia Emantayev return err; 434ffe455adSEugenia Emantayev } 435ffe455adSEugenia Emantayev return __mlx4_register_vlan(dev, port, vlan, index); 436ffe455adSEugenia Emantayev } 4375a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_register_vlan); 4385a2cc190SJeff Kirsher 4392009d005SJack Morgenstein void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 4405a2cc190SJeff Kirsher { 4415a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 4422009d005SJack Morgenstein int index; 4432009d005SJack Morgenstein 4442009d005SJack Morgenstein mutex_lock(&table->mutex); 4452009d005SJack Morgenstein if (mlx4_find_cached_vlan(dev, port, vlan, &index)) { 4462009d005SJack Morgenstein mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan); 4472009d005SJack Morgenstein goto out; 4482009d005SJack Morgenstein } 4495a2cc190SJeff Kirsher 4505a2cc190SJeff Kirsher if (index < MLX4_VLAN_REGULAR) { 4515a2cc190SJeff Kirsher mlx4_warn(dev, "Trying to free special vlan index %d\n", index); 4525a2cc190SJeff Kirsher goto out; 4535a2cc190SJeff Kirsher } 4542009d005SJack Morgenstein 4555a2cc190SJeff Kirsher if (--table->refs[index]) { 4561a91de28SJoe Perches mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n", 4571a91de28SJoe Perches table->refs[index], index); 4585a2cc190SJeff Kirsher goto out; 4595a2cc190SJeff Kirsher } 4605a2cc190SJeff Kirsher table->entries[index] = 0; 4615a2cc190SJeff Kirsher mlx4_set_port_vlan_table(dev, port, table->entries); 4625a2cc190SJeff Kirsher --table->total; 4635a2cc190SJeff Kirsher out: 4645a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 4655a2cc190SJeff Kirsher } 466ffe455adSEugenia Emantayev 4672009d005SJack Morgenstein void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 468ffe455adSEugenia Emantayev { 469162226a1SJack Morgenstein u64 out_param = 0; 470ffe455adSEugenia Emantayev 471ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 4722009d005SJack Morgenstein (void) mlx4_cmd_imm(dev, vlan, &out_param, 473acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN, 474162226a1SJack Morgenstein RES_OP_RESERVE_AND_MAP, 475ffe455adSEugenia Emantayev MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, 476ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 477ffe455adSEugenia Emantayev return; 478ffe455adSEugenia Emantayev } 4792009d005SJack Morgenstein __mlx4_unregister_vlan(dev, port, vlan); 480ffe455adSEugenia Emantayev } 4815a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_vlan); 4825a2cc190SJeff Kirsher 4835a2cc190SJeff Kirsher int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) 4845a2cc190SJeff Kirsher { 4855a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *inmailbox, *outmailbox; 4865a2cc190SJeff Kirsher u8 *inbuf, *outbuf; 4875a2cc190SJeff Kirsher int err; 4885a2cc190SJeff Kirsher 4895a2cc190SJeff Kirsher inmailbox = mlx4_alloc_cmd_mailbox(dev); 4905a2cc190SJeff Kirsher if (IS_ERR(inmailbox)) 4915a2cc190SJeff Kirsher return PTR_ERR(inmailbox); 4925a2cc190SJeff Kirsher 4935a2cc190SJeff Kirsher outmailbox = mlx4_alloc_cmd_mailbox(dev); 4945a2cc190SJeff Kirsher if (IS_ERR(outmailbox)) { 4955a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 4965a2cc190SJeff Kirsher return PTR_ERR(outmailbox); 4975a2cc190SJeff Kirsher } 4985a2cc190SJeff Kirsher 4995a2cc190SJeff Kirsher inbuf = inmailbox->buf; 5005a2cc190SJeff Kirsher outbuf = outmailbox->buf; 5015a2cc190SJeff Kirsher inbuf[0] = 1; 5025a2cc190SJeff Kirsher inbuf[1] = 1; 5035a2cc190SJeff Kirsher inbuf[2] = 1; 5045a2cc190SJeff Kirsher inbuf[3] = 1; 5055a2cc190SJeff Kirsher *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015); 5065a2cc190SJeff Kirsher *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); 5075a2cc190SJeff Kirsher 5085a2cc190SJeff Kirsher err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, 509f9baff50SJack Morgenstein MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 510f9baff50SJack Morgenstein MLX4_CMD_NATIVE); 5115a2cc190SJeff Kirsher if (!err) 5125a2cc190SJeff Kirsher *caps = *(__be32 *) (outbuf + 84); 5135a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 5145a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, outmailbox); 5155a2cc190SJeff Kirsher return err; 5165a2cc190SJeff Kirsher } 5179cd59352SJack Morgenstein static struct mlx4_roce_gid_entry zgid_entry; 5185a2cc190SJeff Kirsher 519449fc488SMatan Barak int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port) 520b6ffaeffSJack Morgenstein { 521449fc488SMatan Barak int vfs; 522449fc488SMatan Barak int slave_gid = slave; 523449fc488SMatan Barak unsigned i; 524449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 525449fc488SMatan Barak struct mlx4_active_ports actv_ports; 526449fc488SMatan Barak unsigned max_port_p_one; 527449fc488SMatan Barak 528b6ffaeffSJack Morgenstein if (slave == 0) 529b6ffaeffSJack Morgenstein return MLX4_ROCE_PF_GIDS; 530449fc488SMatan Barak 531449fc488SMatan Barak /* Slave is a VF */ 532449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 533449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave); 534449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 535449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 536449fc488SMatan Barak 537449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 538449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 539449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 540449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 541449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 542449fc488SMatan Barak if (i == port) 543449fc488SMatan Barak continue; 544449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 545449fc488SMatan Barak dev, &exclusive_ports); 546449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 547449fc488SMatan Barak dev->num_vfs + 1); 548449fc488SMatan Barak } 549449fc488SMatan Barak vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1; 550449fc488SMatan Barak if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs)) 551449fc488SMatan Barak return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1; 552449fc488SMatan Barak return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs; 553b6ffaeffSJack Morgenstein } 554b6ffaeffSJack Morgenstein 555449fc488SMatan Barak int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port) 556b6ffaeffSJack Morgenstein { 557b6ffaeffSJack Morgenstein int gids; 558449fc488SMatan Barak unsigned i; 559449fc488SMatan Barak int slave_gid = slave; 560b6ffaeffSJack Morgenstein int vfs; 561b6ffaeffSJack Morgenstein 562449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 563449fc488SMatan Barak struct mlx4_active_ports actv_ports; 564449fc488SMatan Barak unsigned max_port_p_one; 565b6ffaeffSJack Morgenstein 566b6ffaeffSJack Morgenstein if (slave == 0) 567b6ffaeffSJack Morgenstein return 0; 568b6ffaeffSJack Morgenstein 569449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 570449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave); 571449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 572449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 573449fc488SMatan Barak 574449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 575449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 576449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 577449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 578449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 579449fc488SMatan Barak if (i == port) 580449fc488SMatan Barak continue; 581449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 582449fc488SMatan Barak dev, &exclusive_ports); 583449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 584449fc488SMatan Barak dev->num_vfs + 1); 585b6ffaeffSJack Morgenstein } 586449fc488SMatan Barak gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 587449fc488SMatan Barak vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1; 588449fc488SMatan Barak if (slave_gid <= gids % vfs) 589449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1); 590449fc488SMatan Barak 591449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + (gids % vfs) + 592449fc488SMatan Barak ((gids / vfs) * (slave_gid - 1)); 593449fc488SMatan Barak } 594449fc488SMatan Barak EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix); 595b6ffaeffSJack Morgenstein 596111c6094SJack Morgenstein static int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave, 597111c6094SJack Morgenstein int port, struct mlx4_cmd_mailbox *mailbox) 598111c6094SJack Morgenstein { 599111c6094SJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_mbox; 600111c6094SJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 601111c6094SJack Morgenstein int num_gids, base, offset; 602111c6094SJack Morgenstein int i, err; 603111c6094SJack Morgenstein 604111c6094SJack Morgenstein num_gids = mlx4_get_slave_num_gids(dev, slave, port); 605111c6094SJack Morgenstein base = mlx4_get_base_gid_ix(dev, slave, port); 606111c6094SJack Morgenstein 607111c6094SJack Morgenstein memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE); 608111c6094SJack Morgenstein 609111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex)); 610111c6094SJack Morgenstein /* Zero-out gids belonging to that slave in the port GID table */ 611111c6094SJack Morgenstein for (i = 0, offset = base; i < num_gids; offset++, i++) 612111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 613111c6094SJack Morgenstein zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE); 614111c6094SJack Morgenstein 615111c6094SJack Morgenstein /* Now, copy roce port gids table to mailbox for passing to FW */ 616111c6094SJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf; 617111c6094SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 618111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw, 619111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw, 620111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 621111c6094SJack Morgenstein 622111c6094SJack Morgenstein err = mlx4_cmd(dev, mailbox->dma, 623111c6094SJack Morgenstein ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8), 1, 624111c6094SJack Morgenstein MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 625111c6094SJack Morgenstein MLX4_CMD_NATIVE); 626111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 627111c6094SJack Morgenstein return err; 628111c6094SJack Morgenstein } 629111c6094SJack Morgenstein 630111c6094SJack Morgenstein 631111c6094SJack Morgenstein void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave) 632111c6094SJack Morgenstein { 633111c6094SJack Morgenstein struct mlx4_active_ports actv_ports; 634111c6094SJack Morgenstein struct mlx4_cmd_mailbox *mailbox; 635111c6094SJack Morgenstein int num_eth_ports, err; 636111c6094SJack Morgenstein int i; 637111c6094SJack Morgenstein 638111c6094SJack Morgenstein if (slave < 0 || slave > dev->num_vfs) 639111c6094SJack Morgenstein return; 640111c6094SJack Morgenstein 641111c6094SJack Morgenstein actv_ports = mlx4_get_active_ports(dev, slave); 642111c6094SJack Morgenstein 643111c6094SJack Morgenstein for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) { 644111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) { 645111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 646111c6094SJack Morgenstein continue; 647111c6094SJack Morgenstein num_eth_ports++; 648111c6094SJack Morgenstein } 649111c6094SJack Morgenstein } 650111c6094SJack Morgenstein 651111c6094SJack Morgenstein if (!num_eth_ports) 652111c6094SJack Morgenstein return; 653111c6094SJack Morgenstein 654111c6094SJack Morgenstein /* have ETH ports. Alloc mailbox for SET_PORT command */ 655111c6094SJack Morgenstein mailbox = mlx4_alloc_cmd_mailbox(dev); 656111c6094SJack Morgenstein if (IS_ERR(mailbox)) 657111c6094SJack Morgenstein return; 658111c6094SJack Morgenstein 659111c6094SJack Morgenstein for (i = 0; i < dev->caps.num_ports; i++) { 660111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) { 661111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 662111c6094SJack Morgenstein continue; 663111c6094SJack Morgenstein err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox); 664111c6094SJack Morgenstein if (err) 665111c6094SJack Morgenstein mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n", 666111c6094SJack Morgenstein slave, i + 1, err); 667111c6094SJack Morgenstein } 668111c6094SJack Morgenstein } 669111c6094SJack Morgenstein 670111c6094SJack Morgenstein mlx4_free_cmd_mailbox(dev, mailbox); 671111c6094SJack Morgenstein return; 672111c6094SJack Morgenstein } 673111c6094SJack Morgenstein 674ffe455adSEugenia Emantayev static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, 675ffe455adSEugenia Emantayev u8 op_mod, struct mlx4_cmd_mailbox *inbox) 676ffe455adSEugenia Emantayev { 677ffe455adSEugenia Emantayev struct mlx4_priv *priv = mlx4_priv(dev); 678ffe455adSEugenia Emantayev struct mlx4_port_info *port_info; 679ffe455adSEugenia Emantayev struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; 680ffe455adSEugenia Emantayev struct mlx4_slave_state *slave_st = &master->slave_state[slave]; 681ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *qpn_context; 682ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *gen_context; 683b6ffaeffSJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1; 684ffe455adSEugenia Emantayev int reset_qkey_viols; 685ffe455adSEugenia Emantayev int port; 686ffe455adSEugenia Emantayev int is_eth; 687b6ffaeffSJack Morgenstein int num_gids; 688b6ffaeffSJack Morgenstein int base; 689ffe455adSEugenia Emantayev u32 in_modifier; 690ffe455adSEugenia Emantayev u32 promisc; 691ffe455adSEugenia Emantayev u16 mtu, prev_mtu; 692ffe455adSEugenia Emantayev int err; 693b6ffaeffSJack Morgenstein int i, j; 694b6ffaeffSJack Morgenstein int offset; 695ffe455adSEugenia Emantayev __be32 agg_cap_mask; 696ffe455adSEugenia Emantayev __be32 slave_cap_mask; 697ffe455adSEugenia Emantayev __be32 new_cap_mask; 698ffe455adSEugenia Emantayev 699ffe455adSEugenia Emantayev port = in_mod & 0xff; 700ffe455adSEugenia Emantayev in_modifier = in_mod >> 8; 701ffe455adSEugenia Emantayev is_eth = op_mod; 702ffe455adSEugenia Emantayev port_info = &priv->port[port]; 703ffe455adSEugenia Emantayev 704ffe455adSEugenia Emantayev /* Slaves cannot perform SET_PORT operations except changing MTU */ 705ffe455adSEugenia Emantayev if (is_eth) { 706ffe455adSEugenia Emantayev if (slave != dev->caps.function && 7079cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GENERAL && 7089cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GID_TABLE) { 709ffe455adSEugenia Emantayev mlx4_warn(dev, "denying SET_PORT for slave:%d\n", 710ffe455adSEugenia Emantayev slave); 711ffe455adSEugenia Emantayev return -EINVAL; 712ffe455adSEugenia Emantayev } 713ffe455adSEugenia Emantayev switch (in_modifier) { 714ffe455adSEugenia Emantayev case MLX4_SET_PORT_RQP_CALC: 715ffe455adSEugenia Emantayev qpn_context = inbox->buf; 716ffe455adSEugenia Emantayev qpn_context->base_qpn = 717ffe455adSEugenia Emantayev cpu_to_be32(port_info->base_qpn); 718ffe455adSEugenia Emantayev qpn_context->n_mac = 0x7; 719ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->promisc) >> 720ffe455adSEugenia Emantayev SET_PORT_PROMISC_SHIFT; 721ffe455adSEugenia Emantayev qpn_context->promisc = cpu_to_be32( 722ffe455adSEugenia Emantayev promisc << SET_PORT_PROMISC_SHIFT | 723ffe455adSEugenia Emantayev port_info->base_qpn); 724ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->mcast) >> 725ffe455adSEugenia Emantayev SET_PORT_MC_PROMISC_SHIFT; 726ffe455adSEugenia Emantayev qpn_context->mcast = cpu_to_be32( 727ffe455adSEugenia Emantayev promisc << SET_PORT_MC_PROMISC_SHIFT | 728ffe455adSEugenia Emantayev port_info->base_qpn); 729ffe455adSEugenia Emantayev break; 730ffe455adSEugenia Emantayev case MLX4_SET_PORT_GENERAL: 731ffe455adSEugenia Emantayev gen_context = inbox->buf; 732ffe455adSEugenia Emantayev /* Mtu is configured as the max MTU among all the 733ffe455adSEugenia Emantayev * the functions on the port. */ 734ffe455adSEugenia Emantayev mtu = be16_to_cpu(gen_context->mtu); 735c59fec20SEugenia Emantayev mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] + 736c59fec20SEugenia Emantayev ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); 737ffe455adSEugenia Emantayev prev_mtu = slave_st->mtu[port]; 738ffe455adSEugenia Emantayev slave_st->mtu[port] = mtu; 739ffe455adSEugenia Emantayev if (mtu > master->max_mtu[port]) 740ffe455adSEugenia Emantayev master->max_mtu[port] = mtu; 741ffe455adSEugenia Emantayev if (mtu < prev_mtu && prev_mtu == 742ffe455adSEugenia Emantayev master->max_mtu[port]) { 743ffe455adSEugenia Emantayev slave_st->mtu[port] = mtu; 744ffe455adSEugenia Emantayev master->max_mtu[port] = mtu; 745ffe455adSEugenia Emantayev for (i = 0; i < dev->num_slaves; i++) { 746ffe455adSEugenia Emantayev master->max_mtu[port] = 747ffe455adSEugenia Emantayev max(master->max_mtu[port], 748ffe455adSEugenia Emantayev master->slave_state[i].mtu[port]); 749ffe455adSEugenia Emantayev } 750ffe455adSEugenia Emantayev } 751ffe455adSEugenia Emantayev 752ffe455adSEugenia Emantayev gen_context->mtu = cpu_to_be16(master->max_mtu[port]); 753ffe455adSEugenia Emantayev break; 7549cd59352SJack Morgenstein case MLX4_SET_PORT_GID_TABLE: 755b6ffaeffSJack Morgenstein /* change to MULTIPLE entries: number of guest's gids 756b6ffaeffSJack Morgenstein * need a FOR-loop here over number of gids the guest has. 757b6ffaeffSJack Morgenstein * 1. Check no duplicates in gids passed by slave 758b6ffaeffSJack Morgenstein */ 759449fc488SMatan Barak num_gids = mlx4_get_slave_num_gids(dev, slave, port); 760449fc488SMatan Barak base = mlx4_get_base_gid_ix(dev, slave, port); 761b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 762b6ffaeffSJack Morgenstein for (i = 0; i < num_gids; gid_entry_mbox++, i++) { 763b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 764b6ffaeffSJack Morgenstein sizeof(zgid_entry))) 765b6ffaeffSJack Morgenstein continue; 766b6ffaeffSJack Morgenstein gid_entry_mb1 = gid_entry_mbox + 1; 767b6ffaeffSJack Morgenstein for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) { 768b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw, 769b6ffaeffSJack Morgenstein zgid_entry.raw, sizeof(zgid_entry))) 770b6ffaeffSJack Morgenstein continue; 771b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw, 772b6ffaeffSJack Morgenstein sizeof(gid_entry_mbox->raw))) { 773b6ffaeffSJack Morgenstein /* found duplicate */ 774b6ffaeffSJack Morgenstein return -EINVAL; 775b6ffaeffSJack Morgenstein } 776b6ffaeffSJack Morgenstein } 777b6ffaeffSJack Morgenstein } 778b6ffaeffSJack Morgenstein 779b6ffaeffSJack Morgenstein /* 2. Check that do not have duplicates in OTHER 780b6ffaeffSJack Morgenstein * entries in the port GID table 781b6ffaeffSJack Morgenstein */ 782111c6094SJack Morgenstein 783111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex)); 7849cd59352SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 785b6ffaeffSJack Morgenstein if (i >= base && i < base + num_gids) 786b6ffaeffSJack Morgenstein continue; /* don't compare to slave's current gids */ 787111c6094SJack Morgenstein gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i]; 788b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry))) 789b6ffaeffSJack Morgenstein continue; 790b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 791b6ffaeffSJack Morgenstein for (j = 0; j < num_gids; gid_entry_mbox++, j++) { 792b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 793b6ffaeffSJack Morgenstein sizeof(zgid_entry))) 794b6ffaeffSJack Morgenstein continue; 795b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw, 796b6ffaeffSJack Morgenstein sizeof(gid_entry_tbl->raw))) { 797b6ffaeffSJack Morgenstein /* found duplicate */ 7981a91de28SJoe Perches mlx4_warn(dev, "requested gid entry for slave:%d is a duplicate of gid at index %d\n", 7999cd59352SJack Morgenstein slave, i); 800111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 801b6ffaeffSJack Morgenstein return -EINVAL; 8029cd59352SJack Morgenstein } 8039cd59352SJack Morgenstein } 8049cd59352SJack Morgenstein } 805b6ffaeffSJack Morgenstein 806b6ffaeffSJack Morgenstein /* insert slave GIDs with memcpy, starting at slave's base index */ 807b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 808b6ffaeffSJack Morgenstein for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++) 809111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 810111c6094SJack Morgenstein gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE); 811b6ffaeffSJack Morgenstein 812b6ffaeffSJack Morgenstein /* Now, copy roce port gids table to current mailbox for passing to FW */ 813b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 814b6ffaeffSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 815111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw, 816111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw, 817111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 818b6ffaeffSJack Morgenstein 819111c6094SJack Morgenstein err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 820111c6094SJack Morgenstein MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 821111c6094SJack Morgenstein MLX4_CMD_NATIVE); 822111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 823111c6094SJack Morgenstein return err; 824ffe455adSEugenia Emantayev } 825111c6094SJack Morgenstein 826111c6094SJack Morgenstein return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 827ffe455adSEugenia Emantayev MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 828ffe455adSEugenia Emantayev MLX4_CMD_NATIVE); 829ffe455adSEugenia Emantayev } 830ffe455adSEugenia Emantayev 831ffe455adSEugenia Emantayev /* For IB, we only consider: 832ffe455adSEugenia Emantayev * - The capability mask, which is set to the aggregate of all 833ffe455adSEugenia Emantayev * slave function capabilities 834ffe455adSEugenia Emantayev * - The QKey violatin counter - reset according to each request. 835ffe455adSEugenia Emantayev */ 836ffe455adSEugenia Emantayev 837ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 838ffe455adSEugenia Emantayev reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40; 839ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[2]; 840ffe455adSEugenia Emantayev } else { 841ffe455adSEugenia Emantayev reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1; 842ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[1]; 843ffe455adSEugenia Emantayev } 844ffe455adSEugenia Emantayev 845efcd235dSJack Morgenstein /* slave may not set the IS_SM capability for the port */ 846efcd235dSJack Morgenstein if (slave != mlx4_master_func_num(dev) && 847efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM)) 848efcd235dSJack Morgenstein return -EINVAL; 849efcd235dSJack Morgenstein 850efcd235dSJack Morgenstein /* No DEV_MGMT in multifunc mode */ 851efcd235dSJack Morgenstein if (mlx4_is_mfunc(dev) && 852efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP)) 853efcd235dSJack Morgenstein return -EINVAL; 854efcd235dSJack Morgenstein 855ffe455adSEugenia Emantayev agg_cap_mask = 0; 856ffe455adSEugenia Emantayev slave_cap_mask = 857ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; 858ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask; 859ffe455adSEugenia Emantayev for (i = 0; i < dev->num_slaves; i++) 860ffe455adSEugenia Emantayev agg_cap_mask |= 861ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[i].ib_cap_mask[port]; 862ffe455adSEugenia Emantayev 863ffe455adSEugenia Emantayev /* only clear mailbox for guests. Master may be setting 864ffe455adSEugenia Emantayev * MTU or PKEY table size 865ffe455adSEugenia Emantayev */ 866ffe455adSEugenia Emantayev if (slave != dev->caps.function) 867ffe455adSEugenia Emantayev memset(inbox->buf, 0, 256); 868ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 869edc4a67eSJack Morgenstein *(u8 *) inbox->buf |= !!reset_qkey_viols << 6; 870ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[2] = agg_cap_mask; 871ffe455adSEugenia Emantayev } else { 872edc4a67eSJack Morgenstein ((u8 *) inbox->buf)[3] |= !!reset_qkey_viols; 873ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[1] = agg_cap_mask; 874ffe455adSEugenia Emantayev } 875ffe455adSEugenia Emantayev 876ffe455adSEugenia Emantayev err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT, 877ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 878ffe455adSEugenia Emantayev if (err) 879ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = 880ffe455adSEugenia Emantayev slave_cap_mask; 881ffe455adSEugenia Emantayev return err; 882ffe455adSEugenia Emantayev } 883ffe455adSEugenia Emantayev 884ffe455adSEugenia Emantayev int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, 885ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 886ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 887ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 888ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 889ffe455adSEugenia Emantayev { 890449fc488SMatan Barak int port = mlx4_slave_convert_port( 891449fc488SMatan Barak dev, slave, vhcr->in_modifier & 0xFF); 892449fc488SMatan Barak 893449fc488SMatan Barak if (port < 0) 894449fc488SMatan Barak return -EINVAL; 895449fc488SMatan Barak 896449fc488SMatan Barak vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) | 897449fc488SMatan Barak (port & 0xFF); 898449fc488SMatan Barak 899ffe455adSEugenia Emantayev return mlx4_common_set_port(dev, slave, vhcr->in_modifier, 900ffe455adSEugenia Emantayev vhcr->op_modifier, inbox); 901ffe455adSEugenia Emantayev } 902ffe455adSEugenia Emantayev 903096335b3SOr Gerlitz /* bit locations for set port command with zero op modifier */ 904096335b3SOr Gerlitz enum { 905096335b3SOr Gerlitz MLX4_SET_PORT_VL_CAP = 4, /* bits 7:4 */ 906096335b3SOr Gerlitz MLX4_SET_PORT_MTU_CAP = 12, /* bits 15:12 */ 9076634961cSJack Morgenstein MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20, 908096335b3SOr Gerlitz MLX4_CHANGE_PORT_VL_CAP = 21, 909096335b3SOr Gerlitz MLX4_CHANGE_PORT_MTU_CAP = 22, 910096335b3SOr Gerlitz }; 911096335b3SOr Gerlitz 9126634961cSJack Morgenstein int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz) 9135a2cc190SJeff Kirsher { 9145a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 9156634961cSJack Morgenstein int err, vl_cap, pkey_tbl_flag = 0; 9165a2cc190SJeff Kirsher 9175a2cc190SJeff Kirsher if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) 9185a2cc190SJeff Kirsher return 0; 9195a2cc190SJeff Kirsher 9205a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 9215a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 9225a2cc190SJeff Kirsher return PTR_ERR(mailbox); 9235a2cc190SJeff Kirsher 9245a2cc190SJeff Kirsher ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; 925096335b3SOr Gerlitz 9266634961cSJack Morgenstein if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) { 9276634961cSJack Morgenstein pkey_tbl_flag = 1; 9286634961cSJack Morgenstein ((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz); 9296634961cSJack Morgenstein } 9306634961cSJack Morgenstein 931096335b3SOr Gerlitz /* IB VL CAP enum isn't used by the firmware, just numerical values */ 932096335b3SOr Gerlitz for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) { 933096335b3SOr Gerlitz ((__be32 *) mailbox->buf)[0] = cpu_to_be32( 934096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_MTU_CAP) | 935096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_VL_CAP) | 9366634961cSJack Morgenstein (pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) | 937096335b3SOr Gerlitz (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) | 938096335b3SOr Gerlitz (vl_cap << MLX4_SET_PORT_VL_CAP)); 9395a2cc190SJeff Kirsher err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT, 940f9baff50SJack Morgenstein MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 941096335b3SOr Gerlitz if (err != -ENOMEM) 942096335b3SOr Gerlitz break; 943096335b3SOr Gerlitz } 9445a2cc190SJeff Kirsher 9455a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 9465a2cc190SJeff Kirsher return err; 9475a2cc190SJeff Kirsher } 948ffe455adSEugenia Emantayev 949cb9ffb76SJoerg Roedel int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, 950ffe455adSEugenia Emantayev u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx) 951ffe455adSEugenia Emantayev { 952ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 953ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *context; 954ffe455adSEugenia Emantayev int err; 955ffe455adSEugenia Emantayev u32 in_mod; 956ffe455adSEugenia Emantayev 957ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 958ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 959ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 960ffe455adSEugenia Emantayev context = mailbox->buf; 961ffe455adSEugenia Emantayev context->flags = SET_PORT_GEN_ALL_VALID; 962ffe455adSEugenia Emantayev context->mtu = cpu_to_be16(mtu); 963ffe455adSEugenia Emantayev context->pptx = (pptx * (!pfctx)) << 7; 964ffe455adSEugenia Emantayev context->pfctx = pfctx; 965ffe455adSEugenia Emantayev context->pprx = (pprx * (!pfcrx)) << 7; 966ffe455adSEugenia Emantayev context->pfcrx = pfcrx; 967ffe455adSEugenia Emantayev 968ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 969ffe455adSEugenia Emantayev err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 970ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 971ffe455adSEugenia Emantayev 972ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 973ffe455adSEugenia Emantayev return err; 974ffe455adSEugenia Emantayev } 975ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_general); 976ffe455adSEugenia Emantayev 977cb9ffb76SJoerg Roedel int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, 978ffe455adSEugenia Emantayev u8 promisc) 979ffe455adSEugenia Emantayev { 980ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 981ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *context; 982ffe455adSEugenia Emantayev int err; 983ffe455adSEugenia Emantayev u32 in_mod; 984ffe455adSEugenia Emantayev u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ? 985ffe455adSEugenia Emantayev MCAST_DIRECT : MCAST_DEFAULT; 986ffe455adSEugenia Emantayev 987c96d97f4SHadar Hen Zion if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) 988ffe455adSEugenia Emantayev return 0; 989ffe455adSEugenia Emantayev 990ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 991ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 992ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 993ffe455adSEugenia Emantayev context = mailbox->buf; 994ffe455adSEugenia Emantayev context->base_qpn = cpu_to_be32(base_qpn); 995ffe455adSEugenia Emantayev context->n_mac = dev->caps.log_num_macs; 996ffe455adSEugenia Emantayev context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | 997ffe455adSEugenia Emantayev base_qpn); 998ffe455adSEugenia Emantayev context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | 999ffe455adSEugenia Emantayev base_qpn); 1000ffe455adSEugenia Emantayev context->intra_no_vlan = 0; 1001ffe455adSEugenia Emantayev context->no_vlan = MLX4_NO_VLAN_IDX; 1002ffe455adSEugenia Emantayev context->intra_vlan_miss = 0; 1003ffe455adSEugenia Emantayev context->vlan_miss = MLX4_VLAN_MISS_IDX; 1004ffe455adSEugenia Emantayev 1005ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port; 1006ffe455adSEugenia Emantayev err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 1007ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 1008ffe455adSEugenia Emantayev 1009ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 1010ffe455adSEugenia Emantayev return err; 1011ffe455adSEugenia Emantayev } 1012ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); 1013ffe455adSEugenia Emantayev 1014e5395e92SAmir Vadai int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc) 1015e5395e92SAmir Vadai { 1016e5395e92SAmir Vadai struct mlx4_cmd_mailbox *mailbox; 1017e5395e92SAmir Vadai struct mlx4_set_port_prio2tc_context *context; 1018e5395e92SAmir Vadai int err; 1019e5395e92SAmir Vadai u32 in_mod; 1020e5395e92SAmir Vadai int i; 1021e5395e92SAmir Vadai 1022e5395e92SAmir Vadai mailbox = mlx4_alloc_cmd_mailbox(dev); 1023e5395e92SAmir Vadai if (IS_ERR(mailbox)) 1024e5395e92SAmir Vadai return PTR_ERR(mailbox); 1025e5395e92SAmir Vadai context = mailbox->buf; 1026e5395e92SAmir Vadai for (i = 0; i < MLX4_NUM_UP; i += 2) 1027e5395e92SAmir Vadai context->prio2tc[i >> 1] = prio2tc[i] << 4 | prio2tc[i + 1]; 1028e5395e92SAmir Vadai 1029e5395e92SAmir Vadai in_mod = MLX4_SET_PORT_PRIO2TC << 8 | port; 1030e5395e92SAmir Vadai err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 1031e5395e92SAmir Vadai MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1032e5395e92SAmir Vadai 1033e5395e92SAmir Vadai mlx4_free_cmd_mailbox(dev, mailbox); 1034e5395e92SAmir Vadai return err; 1035e5395e92SAmir Vadai } 1036e5395e92SAmir Vadai EXPORT_SYMBOL(mlx4_SET_PORT_PRIO2TC); 1037e5395e92SAmir Vadai 1038e5395e92SAmir Vadai int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, 1039e5395e92SAmir Vadai u8 *pg, u16 *ratelimit) 1040e5395e92SAmir Vadai { 1041e5395e92SAmir Vadai struct mlx4_cmd_mailbox *mailbox; 1042e5395e92SAmir Vadai struct mlx4_set_port_scheduler_context *context; 1043e5395e92SAmir Vadai int err; 1044e5395e92SAmir Vadai u32 in_mod; 1045e5395e92SAmir Vadai int i; 1046e5395e92SAmir Vadai 1047e5395e92SAmir Vadai mailbox = mlx4_alloc_cmd_mailbox(dev); 1048e5395e92SAmir Vadai if (IS_ERR(mailbox)) 1049e5395e92SAmir Vadai return PTR_ERR(mailbox); 1050e5395e92SAmir Vadai context = mailbox->buf; 1051e5395e92SAmir Vadai 1052e5395e92SAmir Vadai for (i = 0; i < MLX4_NUM_TC; i++) { 1053e5395e92SAmir Vadai struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i]; 1054523ece88SEugenia Emantayev u16 r; 1055523ece88SEugenia Emantayev 1056523ece88SEugenia Emantayev if (ratelimit && ratelimit[i]) { 1057523ece88SEugenia Emantayev if (ratelimit[i] <= MLX4_MAX_100M_UNITS_VAL) { 1058523ece88SEugenia Emantayev r = ratelimit[i]; 1059523ece88SEugenia Emantayev tc->max_bw_units = 1060523ece88SEugenia Emantayev htons(MLX4_RATELIMIT_100M_UNITS); 1061523ece88SEugenia Emantayev } else { 1062523ece88SEugenia Emantayev r = ratelimit[i]/10; 1063523ece88SEugenia Emantayev tc->max_bw_units = 1064523ece88SEugenia Emantayev htons(MLX4_RATELIMIT_1G_UNITS); 1065523ece88SEugenia Emantayev } 1066523ece88SEugenia Emantayev tc->max_bw_value = htons(r); 1067523ece88SEugenia Emantayev } else { 1068523ece88SEugenia Emantayev tc->max_bw_value = htons(MLX4_RATELIMIT_DEFAULT); 1069523ece88SEugenia Emantayev tc->max_bw_units = htons(MLX4_RATELIMIT_1G_UNITS); 1070523ece88SEugenia Emantayev } 1071e5395e92SAmir Vadai 1072e5395e92SAmir Vadai tc->pg = htons(pg[i]); 1073e5395e92SAmir Vadai tc->bw_precentage = htons(tc_tx_bw[i]); 1074e5395e92SAmir Vadai } 1075e5395e92SAmir Vadai 1076e5395e92SAmir Vadai in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port; 1077e5395e92SAmir Vadai err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 1078e5395e92SAmir Vadai MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1079e5395e92SAmir Vadai 1080e5395e92SAmir Vadai mlx4_free_cmd_mailbox(dev, mailbox); 1081e5395e92SAmir Vadai return err; 1082e5395e92SAmir Vadai } 1083e5395e92SAmir Vadai EXPORT_SYMBOL(mlx4_SET_PORT_SCHEDULER); 1084e5395e92SAmir Vadai 10857ffdf726SOr Gerlitz enum { 10867ffdf726SOr Gerlitz VXLAN_ENABLE_MODIFY = 1 << 7, 10877ffdf726SOr Gerlitz VXLAN_STEERING_MODIFY = 1 << 6, 10887ffdf726SOr Gerlitz 10897ffdf726SOr Gerlitz VXLAN_ENABLE = 1 << 7, 10907ffdf726SOr Gerlitz }; 10917ffdf726SOr Gerlitz 10927ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context { 10937ffdf726SOr Gerlitz u32 reserved1; 10947ffdf726SOr Gerlitz u8 modify_flags; 10957ffdf726SOr Gerlitz u8 reserved2; 10967ffdf726SOr Gerlitz u8 enable_flags; 10977ffdf726SOr Gerlitz u8 steering; 10987ffdf726SOr Gerlitz }; 10997ffdf726SOr Gerlitz 11001b136de1SOr Gerlitz int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable) 11017ffdf726SOr Gerlitz { 11027ffdf726SOr Gerlitz int err; 11037ffdf726SOr Gerlitz u32 in_mod; 11047ffdf726SOr Gerlitz struct mlx4_cmd_mailbox *mailbox; 11057ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context *context; 11067ffdf726SOr Gerlitz 11077ffdf726SOr Gerlitz mailbox = mlx4_alloc_cmd_mailbox(dev); 11087ffdf726SOr Gerlitz if (IS_ERR(mailbox)) 11097ffdf726SOr Gerlitz return PTR_ERR(mailbox); 11107ffdf726SOr Gerlitz context = mailbox->buf; 11117ffdf726SOr Gerlitz memset(context, 0, sizeof(*context)); 11127ffdf726SOr Gerlitz 11137ffdf726SOr Gerlitz context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY; 11141b136de1SOr Gerlitz if (enable) 11157ffdf726SOr Gerlitz context->enable_flags = VXLAN_ENABLE; 11167ffdf726SOr Gerlitz context->steering = steering; 11177ffdf726SOr Gerlitz 11187ffdf726SOr Gerlitz in_mod = MLX4_SET_PORT_VXLAN << 8 | port; 11197ffdf726SOr Gerlitz err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 11207ffdf726SOr Gerlitz MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 11217ffdf726SOr Gerlitz 11227ffdf726SOr Gerlitz mlx4_free_cmd_mailbox(dev, mailbox); 11237ffdf726SOr Gerlitz return err; 11247ffdf726SOr Gerlitz } 11257ffdf726SOr Gerlitz EXPORT_SYMBOL(mlx4_SET_PORT_VXLAN); 11267ffdf726SOr Gerlitz 1127ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1128ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1129ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1130ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1131ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1132ffe455adSEugenia Emantayev { 1133ffe455adSEugenia Emantayev int err = 0; 1134ffe455adSEugenia Emantayev 1135ffe455adSEugenia Emantayev return err; 1136ffe455adSEugenia Emantayev } 1137ffe455adSEugenia Emantayev 1138ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, 1139ffe455adSEugenia Emantayev u64 mac, u64 clear, u8 mode) 1140ffe455adSEugenia Emantayev { 1141ffe455adSEugenia Emantayev return mlx4_cmd(dev, (mac | (clear << 63)), port, mode, 1142ffe455adSEugenia Emantayev MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B, 1143ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 1144ffe455adSEugenia Emantayev } 1145ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR); 1146ffe455adSEugenia Emantayev 1147ffe455adSEugenia Emantayev int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1148ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1149ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1150ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1151ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1152ffe455adSEugenia Emantayev { 1153ffe455adSEugenia Emantayev int err = 0; 1154ffe455adSEugenia Emantayev 1155ffe455adSEugenia Emantayev return err; 1156ffe455adSEugenia Emantayev } 1157ffe455adSEugenia Emantayev 1158ffe455adSEugenia Emantayev int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave, 1159ffe455adSEugenia Emantayev u32 in_mod, struct mlx4_cmd_mailbox *outbox) 1160ffe455adSEugenia Emantayev { 1161ffe455adSEugenia Emantayev return mlx4_cmd_box(dev, 0, outbox->dma, in_mod, 0, 1162ffe455adSEugenia Emantayev MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B, 1163ffe455adSEugenia Emantayev MLX4_CMD_NATIVE); 1164ffe455adSEugenia Emantayev } 1165ffe455adSEugenia Emantayev 1166ffe455adSEugenia Emantayev int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, 1167ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1168ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1169ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1170ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1171ffe455adSEugenia Emantayev { 117235fb9afbSEugenia Emantayev if (slave != dev->caps.function) 117335fb9afbSEugenia Emantayev return 0; 1174ffe455adSEugenia Emantayev return mlx4_common_dump_eth_stats(dev, slave, 1175ffe455adSEugenia Emantayev vhcr->in_modifier, outbox); 1176ffe455adSEugenia Emantayev } 117793ece0c1SEugenia Emantayev 117893ece0c1SEugenia Emantayev void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap) 117993ece0c1SEugenia Emantayev { 118093ece0c1SEugenia Emantayev if (!mlx4_is_mfunc(dev)) { 118193ece0c1SEugenia Emantayev *stats_bitmap = 0; 118293ece0c1SEugenia Emantayev return; 118393ece0c1SEugenia Emantayev } 118493ece0c1SEugenia Emantayev 118593ece0c1SEugenia Emantayev *stats_bitmap = (MLX4_STATS_TRAFFIC_COUNTERS_MASK | 118693ece0c1SEugenia Emantayev MLX4_STATS_TRAFFIC_DROPS_MASK | 118793ece0c1SEugenia Emantayev MLX4_STATS_PORT_COUNTERS_MASK); 118893ece0c1SEugenia Emantayev 118993ece0c1SEugenia Emantayev if (mlx4_is_master(dev)) 119093ece0c1SEugenia Emantayev *stats_bitmap |= MLX4_STATS_ERROR_COUNTERS_MASK; 119193ece0c1SEugenia Emantayev } 119293ece0c1SEugenia Emantayev EXPORT_SYMBOL(mlx4_set_stats_bitmap); 11936ee51a4eSJack Morgenstein 11949cd59352SJack Morgenstein int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, 11959cd59352SJack Morgenstein int *slave_id) 11966ee51a4eSJack Morgenstein { 11976ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 11986ee51a4eSJack Morgenstein int i, found_ix = -1; 1199b6ffaeffSJack Morgenstein int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 1200449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 1201449fc488SMatan Barak unsigned num_vfs; 1202449fc488SMatan Barak int slave_gid; 12036ee51a4eSJack Morgenstein 12046ee51a4eSJack Morgenstein if (!mlx4_is_mfunc(dev)) 12056ee51a4eSJack Morgenstein return -EINVAL; 12066ee51a4eSJack Morgenstein 1207449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1208449fc488SMatan Barak num_vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1; 1209449fc488SMatan Barak 12106ee51a4eSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 1211111c6094SJack Morgenstein if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid, 1212111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE)) { 12136ee51a4eSJack Morgenstein found_ix = i; 12146ee51a4eSJack Morgenstein break; 12156ee51a4eSJack Morgenstein } 12166ee51a4eSJack Morgenstein } 12176ee51a4eSJack Morgenstein 1218b6ffaeffSJack Morgenstein if (found_ix >= 0) { 12190254bc82SMatan Barak /* Calculate a slave_gid which is the slave number in the gid 12200254bc82SMatan Barak * table and not a globally unique slave number. 12210254bc82SMatan Barak */ 1222b6ffaeffSJack Morgenstein if (found_ix < MLX4_ROCE_PF_GIDS) 1223449fc488SMatan Barak slave_gid = 0; 1224449fc488SMatan Barak else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) * 1225449fc488SMatan Barak (vf_gids / num_vfs + 1)) 1226449fc488SMatan Barak slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) / 1227449fc488SMatan Barak (vf_gids / num_vfs + 1)) + 1; 1228b6ffaeffSJack Morgenstein else 1229449fc488SMatan Barak slave_gid = 1230b6ffaeffSJack Morgenstein ((found_ix - MLX4_ROCE_PF_GIDS - 1231449fc488SMatan Barak ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) / 1232449fc488SMatan Barak (vf_gids / num_vfs)) + vf_gids % num_vfs + 1; 1233449fc488SMatan Barak 12340254bc82SMatan Barak /* Calculate the globally unique slave id */ 1235449fc488SMatan Barak if (slave_gid) { 1236449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 1237449fc488SMatan Barak struct mlx4_active_ports actv_ports; 1238449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 1239449fc488SMatan Barak unsigned max_port_p_one; 12400254bc82SMatan Barak int num_vfs_before = 0; 12410254bc82SMatan Barak int candidate_slave_gid; 1242449fc488SMatan Barak 12430254bc82SMatan Barak /* Calculate how many VFs are on the previous port, if exists */ 1244449fc488SMatan Barak for (i = 1; i < port; i++) { 1245449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 12460254bc82SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1247449fc488SMatan Barak slaves_pport_actv = 1248449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv( 1249449fc488SMatan Barak dev, &exclusive_ports); 12500254bc82SMatan Barak num_vfs_before += bitmap_weight( 1251449fc488SMatan Barak slaves_pport_actv.slaves, 1252449fc488SMatan Barak dev->num_vfs + 1); 1253449fc488SMatan Barak } 1254449fc488SMatan Barak 12550254bc82SMatan Barak /* candidate_slave_gid isn't necessarily the correct slave, but 12560254bc82SMatan Barak * it has the same number of ports and is assigned to the same 12570254bc82SMatan Barak * ports as the real slave we're looking for. On dual port VF, 12580254bc82SMatan Barak * slave_gid = [single port VFs on port <port>] + 12590254bc82SMatan Barak * [offset of the current slave from the first dual port VF] + 12600254bc82SMatan Barak * 1 (for the PF). 12610254bc82SMatan Barak */ 12620254bc82SMatan Barak candidate_slave_gid = slave_gid + num_vfs_before; 12630254bc82SMatan Barak 12640254bc82SMatan Barak actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid); 1265449fc488SMatan Barak max_port_p_one = find_first_bit( 1266449fc488SMatan Barak actv_ports.ports, dev->caps.num_ports) + 1267449fc488SMatan Barak bitmap_weight(actv_ports.ports, 1268449fc488SMatan Barak dev->caps.num_ports) + 1; 1269449fc488SMatan Barak 12700254bc82SMatan Barak /* Calculate the real slave number */ 1271449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 1272449fc488SMatan Barak if (i == port) 1273449fc488SMatan Barak continue; 1274449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, 1275449fc488SMatan Barak dev->caps.num_ports); 1276449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1277449fc488SMatan Barak slaves_pport_actv = 1278449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv( 1279449fc488SMatan Barak dev, &exclusive_ports); 1280449fc488SMatan Barak slave_gid += bitmap_weight( 1281449fc488SMatan Barak slaves_pport_actv.slaves, 1282449fc488SMatan Barak dev->num_vfs + 1); 1283449fc488SMatan Barak } 1284449fc488SMatan Barak } 1285449fc488SMatan Barak *slave_id = slave_gid; 1286b6ffaeffSJack Morgenstein } 12876ee51a4eSJack Morgenstein 12886ee51a4eSJack Morgenstein return (found_ix >= 0) ? 0 : -EINVAL; 12896ee51a4eSJack Morgenstein } 12906ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid); 12916ee51a4eSJack Morgenstein 12929cd59352SJack Morgenstein int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, 12939cd59352SJack Morgenstein u8 *gid) 12946ee51a4eSJack Morgenstein { 12956ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 12966ee51a4eSJack Morgenstein 12976ee51a4eSJack Morgenstein if (!mlx4_is_master(dev)) 12986ee51a4eSJack Morgenstein return -EINVAL; 12996ee51a4eSJack Morgenstein 1300111c6094SJack Morgenstein memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw, 1301111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 13026ee51a4eSJack Morgenstein return 0; 13036ee51a4eSJack Morgenstein } 13046ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); 1305