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++) { 106f4fd40b2SJack Morgenstein if (table->refs[i] && 107f4fd40b2SJack Morgenstein (MLX4_MAC_MASK & mac) == 108ffe455adSEugenia Emantayev (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) 1095a2cc190SJeff Kirsher return i; 1105a2cc190SJeff Kirsher } 1115a2cc190SJeff Kirsher /* Mac not found */ 1125a2cc190SJeff Kirsher return -EINVAL; 1135a2cc190SJeff Kirsher } 1145a2cc190SJeff Kirsher 115ffe455adSEugenia Emantayev static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, 116ffe455adSEugenia Emantayev __be64 *entries) 117ffe455adSEugenia Emantayev { 118ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 119ffe455adSEugenia Emantayev u32 in_mod; 120ffe455adSEugenia Emantayev int err; 121ffe455adSEugenia Emantayev 122ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 123ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 124ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 125ffe455adSEugenia Emantayev 126ffe455adSEugenia Emantayev memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); 127ffe455adSEugenia Emantayev 128ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; 129ffe455adSEugenia Emantayev 130ffe455adSEugenia Emantayev err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 131ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 132ffe455adSEugenia Emantayev 133ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 134ffe455adSEugenia Emantayev return err; 135ffe455adSEugenia Emantayev } 136ffe455adSEugenia Emantayev 137297e0dadSMoni Shoua int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx) 138297e0dadSMoni Shoua { 139297e0dadSMoni Shoua struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 140297e0dadSMoni Shoua struct mlx4_mac_table *table = &info->mac_table; 141297e0dadSMoni Shoua int i; 142297e0dadSMoni Shoua 143297e0dadSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 144297e0dadSMoni Shoua if (!table->refs[i]) 145297e0dadSMoni Shoua continue; 146297e0dadSMoni Shoua 147297e0dadSMoni Shoua if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 148297e0dadSMoni Shoua *idx = i; 149297e0dadSMoni Shoua return 0; 150297e0dadSMoni Shoua } 151297e0dadSMoni Shoua } 152297e0dadSMoni Shoua 153297e0dadSMoni Shoua return -ENOENT; 154297e0dadSMoni Shoua } 155297e0dadSMoni Shoua EXPORT_SYMBOL_GPL(mlx4_find_cached_mac); 156297e0dadSMoni Shoua 157ffe455adSEugenia Emantayev int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 158ffe455adSEugenia Emantayev { 159ffe455adSEugenia Emantayev struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 160ffe455adSEugenia Emantayev struct mlx4_mac_table *table = &info->mac_table; 161ffe455adSEugenia Emantayev int i, err = 0; 162ffe455adSEugenia Emantayev int free = -1; 163ffe455adSEugenia Emantayev 164ffe455adSEugenia Emantayev mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d\n", 165ffe455adSEugenia Emantayev (unsigned long long) mac, port); 166ffe455adSEugenia Emantayev 167ffe455adSEugenia Emantayev mutex_lock(&table->mutex); 168ffe455adSEugenia Emantayev for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 169f4fd40b2SJack Morgenstein if (!table->refs[i]) { 170f4fd40b2SJack Morgenstein if (free < 0) 171ffe455adSEugenia Emantayev free = i; 172ffe455adSEugenia Emantayev continue; 173ffe455adSEugenia Emantayev } 174ffe455adSEugenia Emantayev 175f4fd40b2SJack Morgenstein if ((MLX4_MAC_MASK & mac) == 176f4fd40b2SJack Morgenstein (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 1776ce71acdSRony Efraim /* MAC already registered, increment ref count */ 1786ce71acdSRony Efraim err = i; 1796ce71acdSRony Efraim ++table->refs[i]; 180ffe455adSEugenia Emantayev goto out; 181ffe455adSEugenia Emantayev } 182ffe455adSEugenia Emantayev } 183ffe455adSEugenia Emantayev 184ffe455adSEugenia Emantayev mlx4_dbg(dev, "Free MAC index is %d\n", free); 185ffe455adSEugenia Emantayev 186ffe455adSEugenia Emantayev if (table->total == table->max) { 187ffe455adSEugenia Emantayev /* No free mac entries */ 188ffe455adSEugenia Emantayev err = -ENOSPC; 189ffe455adSEugenia Emantayev goto out; 190ffe455adSEugenia Emantayev } 191ffe455adSEugenia Emantayev 192ffe455adSEugenia Emantayev /* Register new MAC */ 193ffe455adSEugenia Emantayev table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); 194ffe455adSEugenia Emantayev 195ffe455adSEugenia Emantayev err = mlx4_set_port_mac_table(dev, port, table->entries); 196ffe455adSEugenia Emantayev if (unlikely(err)) { 197ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 198ffe455adSEugenia Emantayev (unsigned long long) mac); 199ffe455adSEugenia Emantayev table->entries[free] = 0; 200ffe455adSEugenia Emantayev goto out; 201ffe455adSEugenia Emantayev } 2026ce71acdSRony Efraim table->refs[free] = 1; 203ffe455adSEugenia Emantayev err = free; 204ffe455adSEugenia Emantayev ++table->total; 205ffe455adSEugenia Emantayev out: 206ffe455adSEugenia Emantayev mutex_unlock(&table->mutex); 207ffe455adSEugenia Emantayev return err; 208ffe455adSEugenia Emantayev } 209ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_register_mac); 210ffe455adSEugenia Emantayev 211ffe455adSEugenia Emantayev int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 212ffe455adSEugenia Emantayev { 213e7dbeba8SJack Morgenstein u64 out_param = 0; 214acddd5ddSJack Morgenstein int err = -EINVAL; 215ffe455adSEugenia Emantayev 216ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 217acddd5ddSJack Morgenstein if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 218acddd5ddSJack Morgenstein err = mlx4_cmd_imm(dev, mac, &out_param, 219acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_MAC, 220acddd5ddSJack Morgenstein RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 221acddd5ddSJack Morgenstein MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 222acddd5ddSJack Morgenstein } 223acddd5ddSJack Morgenstein if (err && err == -EINVAL && mlx4_is_slave(dev)) { 224acddd5ddSJack Morgenstein /* retry using old REG_MAC format */ 225ffe455adSEugenia Emantayev set_param_l(&out_param, port); 226ffe455adSEugenia Emantayev err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 227ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 228ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 229acddd5ddSJack Morgenstein if (!err) 230acddd5ddSJack Morgenstein dev->flags |= MLX4_FLAG_OLD_REG_MAC; 231acddd5ddSJack Morgenstein } 232ffe455adSEugenia Emantayev if (err) 233ffe455adSEugenia Emantayev return err; 234ffe455adSEugenia Emantayev 235ffe455adSEugenia Emantayev return get_param_l(&out_param); 236ffe455adSEugenia Emantayev } 237ffe455adSEugenia Emantayev return __mlx4_register_mac(dev, port, mac); 238ffe455adSEugenia Emantayev } 239ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(mlx4_register_mac); 240ffe455adSEugenia Emantayev 24116a10ffdSYan Burman int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port) 24216a10ffdSYan Burman { 24316a10ffdSYan Burman return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] + 24416a10ffdSYan Burman (port - 1) * (1 << dev->caps.log_num_macs); 24516a10ffdSYan Burman } 24616a10ffdSYan Burman EXPORT_SYMBOL_GPL(mlx4_get_base_qpn); 247ffe455adSEugenia Emantayev 248ffe455adSEugenia Emantayev void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 249ffe455adSEugenia Emantayev { 250143b3efbSEugenia Emantayev struct mlx4_port_info *info; 251143b3efbSEugenia Emantayev struct mlx4_mac_table *table; 252ffe455adSEugenia Emantayev int index; 253ffe455adSEugenia Emantayev 254143b3efbSEugenia Emantayev if (port < 1 || port > dev->caps.num_ports) { 255143b3efbSEugenia Emantayev mlx4_warn(dev, "invalid port number (%d), aborting...\n", port); 256143b3efbSEugenia Emantayev return; 257143b3efbSEugenia Emantayev } 258143b3efbSEugenia Emantayev info = &mlx4_priv(dev)->port[port]; 259143b3efbSEugenia Emantayev table = &info->mac_table; 2605a2cc190SJeff Kirsher mutex_lock(&table->mutex); 2616ce71acdSRony Efraim index = find_index(dev, table, mac); 2625a2cc190SJeff Kirsher 2635a2cc190SJeff Kirsher if (validate_index(dev, table, index)) 2645a2cc190SJeff Kirsher goto out; 2656ce71acdSRony Efraim if (--table->refs[index]) { 2661a91de28SJoe Perches mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n", 2671a91de28SJoe Perches index); 2686ce71acdSRony Efraim goto out; 2696ce71acdSRony Efraim } 2705a2cc190SJeff Kirsher 2715a2cc190SJeff Kirsher table->entries[index] = 0; 2725a2cc190SJeff Kirsher mlx4_set_port_mac_table(dev, port, table->entries); 2735a2cc190SJeff Kirsher --table->total; 2745a2cc190SJeff Kirsher out: 2755a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 2765a2cc190SJeff Kirsher } 277ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_unregister_mac); 278ffe455adSEugenia Emantayev 279ffe455adSEugenia Emantayev void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 280ffe455adSEugenia Emantayev { 281e7dbeba8SJack Morgenstein u64 out_param = 0; 282ffe455adSEugenia Emantayev 283ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 284acddd5ddSJack Morgenstein if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) { 285acddd5ddSJack Morgenstein (void) mlx4_cmd_imm(dev, mac, &out_param, 286acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_MAC, 287acddd5ddSJack Morgenstein RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 288acddd5ddSJack Morgenstein MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 289acddd5ddSJack Morgenstein } else { 290acddd5ddSJack Morgenstein /* use old unregister mac format */ 291ffe455adSEugenia Emantayev set_param_l(&out_param, port); 292162344edSOr Gerlitz (void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 293ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 294ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 295acddd5ddSJack Morgenstein } 296ffe455adSEugenia Emantayev return; 297ffe455adSEugenia Emantayev } 298ffe455adSEugenia Emantayev __mlx4_unregister_mac(dev, port, mac); 299ffe455adSEugenia Emantayev return; 300ffe455adSEugenia Emantayev } 3015a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_mac); 3025a2cc190SJeff Kirsher 30316a10ffdSYan Burman int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac) 3045a2cc190SJeff Kirsher { 3055a2cc190SJeff Kirsher struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 3065a2cc190SJeff Kirsher struct mlx4_mac_table *table = &info->mac_table; 307ffe455adSEugenia Emantayev int index = qpn - info->base_qpn; 308ffe455adSEugenia Emantayev int err = 0; 3095a2cc190SJeff Kirsher 310ffe455adSEugenia Emantayev /* CX1 doesn't support multi-functions */ 3115a2cc190SJeff Kirsher mutex_lock(&table->mutex); 3125a2cc190SJeff Kirsher 3135a2cc190SJeff Kirsher err = validate_index(dev, table, index); 3145a2cc190SJeff Kirsher if (err) 3155a2cc190SJeff Kirsher goto out; 3165a2cc190SJeff Kirsher 3175a2cc190SJeff Kirsher table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); 3185a2cc190SJeff Kirsher 3195a2cc190SJeff Kirsher err = mlx4_set_port_mac_table(dev, port, table->entries); 3205a2cc190SJeff Kirsher if (unlikely(err)) { 321ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 322ffe455adSEugenia Emantayev (unsigned long long) new_mac); 3235a2cc190SJeff Kirsher table->entries[index] = 0; 3245a2cc190SJeff Kirsher } 3255a2cc190SJeff Kirsher out: 3265a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 3275a2cc190SJeff Kirsher return err; 3285a2cc190SJeff Kirsher } 32916a10ffdSYan Burman EXPORT_SYMBOL_GPL(__mlx4_replace_mac); 330ffe455adSEugenia Emantayev 3315a2cc190SJeff Kirsher static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, 3325a2cc190SJeff Kirsher __be32 *entries) 3335a2cc190SJeff Kirsher { 3345a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 3355a2cc190SJeff Kirsher u32 in_mod; 3365a2cc190SJeff Kirsher int err; 3375a2cc190SJeff Kirsher 3385a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 3395a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 3405a2cc190SJeff Kirsher return PTR_ERR(mailbox); 3415a2cc190SJeff Kirsher 3425a2cc190SJeff Kirsher memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); 3435a2cc190SJeff Kirsher in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; 3445a2cc190SJeff Kirsher err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 345162226a1SJack Morgenstein MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 3465a2cc190SJeff Kirsher 3475a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 3485a2cc190SJeff Kirsher 3495a2cc190SJeff Kirsher return err; 3505a2cc190SJeff Kirsher } 3515a2cc190SJeff Kirsher 3525a2cc190SJeff Kirsher int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx) 3535a2cc190SJeff Kirsher { 3545a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 3555a2cc190SJeff Kirsher int i; 3565a2cc190SJeff Kirsher 3575a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) { 3585a2cc190SJeff Kirsher if (table->refs[i] && 3595a2cc190SJeff Kirsher (vid == (MLX4_VLAN_MASK & 3605a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 3615a2cc190SJeff Kirsher /* VLAN already registered, increase reference count */ 3625a2cc190SJeff Kirsher *idx = i; 3635a2cc190SJeff Kirsher return 0; 3645a2cc190SJeff Kirsher } 3655a2cc190SJeff Kirsher } 3665a2cc190SJeff Kirsher 3675a2cc190SJeff Kirsher return -ENOENT; 3685a2cc190SJeff Kirsher } 3695a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan); 3705a2cc190SJeff Kirsher 3713f7fb021SRony Efraim int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, 372ffe455adSEugenia Emantayev int *index) 3735a2cc190SJeff Kirsher { 3745a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 3755a2cc190SJeff Kirsher int i, err = 0; 3765a2cc190SJeff Kirsher int free = -1; 3775a2cc190SJeff Kirsher 3785a2cc190SJeff Kirsher mutex_lock(&table->mutex); 379e72ebf5aSYevgeny Petrilin 380e72ebf5aSYevgeny Petrilin if (table->total == table->max) { 381e72ebf5aSYevgeny Petrilin /* No free vlan entries */ 382e72ebf5aSYevgeny Petrilin err = -ENOSPC; 383e72ebf5aSYevgeny Petrilin goto out; 384e72ebf5aSYevgeny Petrilin } 385e72ebf5aSYevgeny Petrilin 3865a2cc190SJeff Kirsher for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 3875a2cc190SJeff Kirsher if (free < 0 && (table->refs[i] == 0)) { 3885a2cc190SJeff Kirsher free = i; 3895a2cc190SJeff Kirsher continue; 3905a2cc190SJeff Kirsher } 3915a2cc190SJeff Kirsher 3925a2cc190SJeff Kirsher if (table->refs[i] && 3935a2cc190SJeff Kirsher (vlan == (MLX4_VLAN_MASK & 3945a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 3955a2cc190SJeff Kirsher /* Vlan already registered, increase references count */ 3965a2cc190SJeff Kirsher *index = i; 3975a2cc190SJeff Kirsher ++table->refs[i]; 3985a2cc190SJeff Kirsher goto out; 3995a2cc190SJeff Kirsher } 4005a2cc190SJeff Kirsher } 4015a2cc190SJeff Kirsher 4025a2cc190SJeff Kirsher if (free < 0) { 4035a2cc190SJeff Kirsher err = -ENOMEM; 4045a2cc190SJeff Kirsher goto out; 4055a2cc190SJeff Kirsher } 4065a2cc190SJeff Kirsher 407ffe455adSEugenia Emantayev /* Register new VLAN */ 4085a2cc190SJeff Kirsher table->refs[free] = 1; 4095a2cc190SJeff Kirsher table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 4105a2cc190SJeff Kirsher 4115a2cc190SJeff Kirsher err = mlx4_set_port_vlan_table(dev, port, table->entries); 4125a2cc190SJeff Kirsher if (unlikely(err)) { 4135a2cc190SJeff Kirsher mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); 4145a2cc190SJeff Kirsher table->refs[free] = 0; 4155a2cc190SJeff Kirsher table->entries[free] = 0; 4165a2cc190SJeff Kirsher goto out; 4175a2cc190SJeff Kirsher } 4185a2cc190SJeff Kirsher 4195a2cc190SJeff Kirsher *index = free; 4205a2cc190SJeff Kirsher ++table->total; 4215a2cc190SJeff Kirsher out: 4225a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 4235a2cc190SJeff Kirsher return err; 4245a2cc190SJeff Kirsher } 425ffe455adSEugenia Emantayev 426ffe455adSEugenia Emantayev int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) 427ffe455adSEugenia Emantayev { 428e7dbeba8SJack Morgenstein u64 out_param = 0; 429ffe455adSEugenia Emantayev int err; 430ffe455adSEugenia Emantayev 431162226a1SJack Morgenstein if (vlan > 4095) 432162226a1SJack Morgenstein return -EINVAL; 433162226a1SJack Morgenstein 434ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 435acddd5ddSJack Morgenstein err = mlx4_cmd_imm(dev, vlan, &out_param, 436acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN, 437ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 438ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 439ffe455adSEugenia Emantayev if (!err) 440ffe455adSEugenia Emantayev *index = get_param_l(&out_param); 441ffe455adSEugenia Emantayev 442ffe455adSEugenia Emantayev return err; 443ffe455adSEugenia Emantayev } 444ffe455adSEugenia Emantayev return __mlx4_register_vlan(dev, port, vlan, index); 445ffe455adSEugenia Emantayev } 4465a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_register_vlan); 4475a2cc190SJeff Kirsher 4482009d005SJack Morgenstein void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 4495a2cc190SJeff Kirsher { 4505a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 4512009d005SJack Morgenstein int index; 4522009d005SJack Morgenstein 4532009d005SJack Morgenstein mutex_lock(&table->mutex); 4542009d005SJack Morgenstein if (mlx4_find_cached_vlan(dev, port, vlan, &index)) { 4552009d005SJack Morgenstein mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan); 4562009d005SJack Morgenstein goto out; 4572009d005SJack Morgenstein } 4585a2cc190SJeff Kirsher 4595a2cc190SJeff Kirsher if (index < MLX4_VLAN_REGULAR) { 4605a2cc190SJeff Kirsher mlx4_warn(dev, "Trying to free special vlan index %d\n", index); 4615a2cc190SJeff Kirsher goto out; 4625a2cc190SJeff Kirsher } 4632009d005SJack Morgenstein 4645a2cc190SJeff Kirsher if (--table->refs[index]) { 4651a91de28SJoe Perches mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n", 4661a91de28SJoe Perches table->refs[index], index); 4675a2cc190SJeff Kirsher goto out; 4685a2cc190SJeff Kirsher } 4695a2cc190SJeff Kirsher table->entries[index] = 0; 4705a2cc190SJeff Kirsher mlx4_set_port_vlan_table(dev, port, table->entries); 4715a2cc190SJeff Kirsher --table->total; 4725a2cc190SJeff Kirsher out: 4735a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 4745a2cc190SJeff Kirsher } 475ffe455adSEugenia Emantayev 4762009d005SJack Morgenstein void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan) 477ffe455adSEugenia Emantayev { 478162226a1SJack Morgenstein u64 out_param = 0; 479ffe455adSEugenia Emantayev 480ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 4812009d005SJack Morgenstein (void) mlx4_cmd_imm(dev, vlan, &out_param, 482acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN, 483162226a1SJack Morgenstein RES_OP_RESERVE_AND_MAP, 484ffe455adSEugenia Emantayev MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, 485ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 486ffe455adSEugenia Emantayev return; 487ffe455adSEugenia Emantayev } 4882009d005SJack Morgenstein __mlx4_unregister_vlan(dev, port, vlan); 489ffe455adSEugenia Emantayev } 4905a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_vlan); 4915a2cc190SJeff Kirsher 4925a2cc190SJeff Kirsher int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) 4935a2cc190SJeff Kirsher { 4945a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *inmailbox, *outmailbox; 4955a2cc190SJeff Kirsher u8 *inbuf, *outbuf; 4965a2cc190SJeff Kirsher int err; 4975a2cc190SJeff Kirsher 4985a2cc190SJeff Kirsher inmailbox = mlx4_alloc_cmd_mailbox(dev); 4995a2cc190SJeff Kirsher if (IS_ERR(inmailbox)) 5005a2cc190SJeff Kirsher return PTR_ERR(inmailbox); 5015a2cc190SJeff Kirsher 5025a2cc190SJeff Kirsher outmailbox = mlx4_alloc_cmd_mailbox(dev); 5035a2cc190SJeff Kirsher if (IS_ERR(outmailbox)) { 5045a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 5055a2cc190SJeff Kirsher return PTR_ERR(outmailbox); 5065a2cc190SJeff Kirsher } 5075a2cc190SJeff Kirsher 5085a2cc190SJeff Kirsher inbuf = inmailbox->buf; 5095a2cc190SJeff Kirsher outbuf = outmailbox->buf; 5105a2cc190SJeff Kirsher inbuf[0] = 1; 5115a2cc190SJeff Kirsher inbuf[1] = 1; 5125a2cc190SJeff Kirsher inbuf[2] = 1; 5135a2cc190SJeff Kirsher inbuf[3] = 1; 5145a2cc190SJeff Kirsher *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015); 5155a2cc190SJeff Kirsher *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); 5165a2cc190SJeff Kirsher 5175a2cc190SJeff Kirsher err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, 518f9baff50SJack Morgenstein MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 519f9baff50SJack Morgenstein MLX4_CMD_NATIVE); 5205a2cc190SJeff Kirsher if (!err) 5215a2cc190SJeff Kirsher *caps = *(__be32 *) (outbuf + 84); 5225a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 5235a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, outmailbox); 5245a2cc190SJeff Kirsher return err; 5255a2cc190SJeff Kirsher } 5269cd59352SJack Morgenstein static struct mlx4_roce_gid_entry zgid_entry; 5275a2cc190SJeff Kirsher 528449fc488SMatan Barak int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port) 529b6ffaeffSJack Morgenstein { 530449fc488SMatan Barak int vfs; 531449fc488SMatan Barak int slave_gid = slave; 532449fc488SMatan Barak unsigned i; 533449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 534449fc488SMatan Barak struct mlx4_active_ports actv_ports; 535449fc488SMatan Barak unsigned max_port_p_one; 536449fc488SMatan Barak 537b6ffaeffSJack Morgenstein if (slave == 0) 538b6ffaeffSJack Morgenstein return MLX4_ROCE_PF_GIDS; 539449fc488SMatan Barak 540449fc488SMatan Barak /* Slave is a VF */ 541449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 542449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave); 543449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 544449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 545449fc488SMatan Barak 546449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 547449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 548449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 549449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 550449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 551449fc488SMatan Barak if (i == port) 552449fc488SMatan Barak continue; 553449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 554449fc488SMatan Barak dev, &exclusive_ports); 555449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 556449fc488SMatan Barak dev->num_vfs + 1); 557449fc488SMatan Barak } 558449fc488SMatan Barak vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1; 559449fc488SMatan Barak if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs)) 560449fc488SMatan Barak return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1; 561449fc488SMatan Barak return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs; 562b6ffaeffSJack Morgenstein } 563b6ffaeffSJack Morgenstein 564449fc488SMatan Barak int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port) 565b6ffaeffSJack Morgenstein { 566b6ffaeffSJack Morgenstein int gids; 567449fc488SMatan Barak unsigned i; 568449fc488SMatan Barak int slave_gid = slave; 569b6ffaeffSJack Morgenstein int vfs; 570b6ffaeffSJack Morgenstein 571449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 572449fc488SMatan Barak struct mlx4_active_ports actv_ports; 573449fc488SMatan Barak unsigned max_port_p_one; 574b6ffaeffSJack Morgenstein 575b6ffaeffSJack Morgenstein if (slave == 0) 576b6ffaeffSJack Morgenstein return 0; 577b6ffaeffSJack Morgenstein 578449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 579449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave); 580449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) + 581449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1; 582449fc488SMatan Barak 583449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 584449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 585449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 586449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 587449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 588449fc488SMatan Barak if (i == port) 589449fc488SMatan Barak continue; 590449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv( 591449fc488SMatan Barak dev, &exclusive_ports); 592449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves, 593449fc488SMatan Barak dev->num_vfs + 1); 594b6ffaeffSJack Morgenstein } 595449fc488SMatan Barak gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 596449fc488SMatan Barak vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1; 597449fc488SMatan Barak if (slave_gid <= gids % vfs) 598449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1); 599449fc488SMatan Barak 600449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + (gids % vfs) + 601449fc488SMatan Barak ((gids / vfs) * (slave_gid - 1)); 602449fc488SMatan Barak } 603449fc488SMatan Barak EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix); 604b6ffaeffSJack Morgenstein 605111c6094SJack Morgenstein static int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave, 606111c6094SJack Morgenstein int port, struct mlx4_cmd_mailbox *mailbox) 607111c6094SJack Morgenstein { 608111c6094SJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_mbox; 609111c6094SJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 610111c6094SJack Morgenstein int num_gids, base, offset; 611111c6094SJack Morgenstein int i, err; 612111c6094SJack Morgenstein 613111c6094SJack Morgenstein num_gids = mlx4_get_slave_num_gids(dev, slave, port); 614111c6094SJack Morgenstein base = mlx4_get_base_gid_ix(dev, slave, port); 615111c6094SJack Morgenstein 616111c6094SJack Morgenstein memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE); 617111c6094SJack Morgenstein 618111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex)); 619111c6094SJack Morgenstein /* Zero-out gids belonging to that slave in the port GID table */ 620111c6094SJack Morgenstein for (i = 0, offset = base; i < num_gids; offset++, i++) 621111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 622111c6094SJack Morgenstein zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE); 623111c6094SJack Morgenstein 624111c6094SJack Morgenstein /* Now, copy roce port gids table to mailbox for passing to FW */ 625111c6094SJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf; 626111c6094SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 627111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw, 628111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw, 629111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 630111c6094SJack Morgenstein 631111c6094SJack Morgenstein err = mlx4_cmd(dev, mailbox->dma, 632111c6094SJack Morgenstein ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8), 1, 633111c6094SJack Morgenstein MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 634111c6094SJack Morgenstein MLX4_CMD_NATIVE); 635111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 636111c6094SJack Morgenstein return err; 637111c6094SJack Morgenstein } 638111c6094SJack Morgenstein 639111c6094SJack Morgenstein 640111c6094SJack Morgenstein void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave) 641111c6094SJack Morgenstein { 642111c6094SJack Morgenstein struct mlx4_active_ports actv_ports; 643111c6094SJack Morgenstein struct mlx4_cmd_mailbox *mailbox; 644111c6094SJack Morgenstein int num_eth_ports, err; 645111c6094SJack Morgenstein int i; 646111c6094SJack Morgenstein 647111c6094SJack Morgenstein if (slave < 0 || slave > dev->num_vfs) 648111c6094SJack Morgenstein return; 649111c6094SJack Morgenstein 650111c6094SJack Morgenstein actv_ports = mlx4_get_active_ports(dev, slave); 651111c6094SJack Morgenstein 652111c6094SJack Morgenstein for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) { 653111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) { 654111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 655111c6094SJack Morgenstein continue; 656111c6094SJack Morgenstein num_eth_ports++; 657111c6094SJack Morgenstein } 658111c6094SJack Morgenstein } 659111c6094SJack Morgenstein 660111c6094SJack Morgenstein if (!num_eth_ports) 661111c6094SJack Morgenstein return; 662111c6094SJack Morgenstein 663111c6094SJack Morgenstein /* have ETH ports. Alloc mailbox for SET_PORT command */ 664111c6094SJack Morgenstein mailbox = mlx4_alloc_cmd_mailbox(dev); 665111c6094SJack Morgenstein if (IS_ERR(mailbox)) 666111c6094SJack Morgenstein return; 667111c6094SJack Morgenstein 668111c6094SJack Morgenstein for (i = 0; i < dev->caps.num_ports; i++) { 669111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) { 670111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH) 671111c6094SJack Morgenstein continue; 672111c6094SJack Morgenstein err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox); 673111c6094SJack Morgenstein if (err) 674111c6094SJack Morgenstein mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n", 675111c6094SJack Morgenstein slave, i + 1, err); 676111c6094SJack Morgenstein } 677111c6094SJack Morgenstein } 678111c6094SJack Morgenstein 679111c6094SJack Morgenstein mlx4_free_cmd_mailbox(dev, mailbox); 680111c6094SJack Morgenstein return; 681111c6094SJack Morgenstein } 682111c6094SJack Morgenstein 683ffe455adSEugenia Emantayev static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, 684ffe455adSEugenia Emantayev u8 op_mod, struct mlx4_cmd_mailbox *inbox) 685ffe455adSEugenia Emantayev { 686ffe455adSEugenia Emantayev struct mlx4_priv *priv = mlx4_priv(dev); 687ffe455adSEugenia Emantayev struct mlx4_port_info *port_info; 688ffe455adSEugenia Emantayev struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; 689ffe455adSEugenia Emantayev struct mlx4_slave_state *slave_st = &master->slave_state[slave]; 690ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *qpn_context; 691ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *gen_context; 692b6ffaeffSJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1; 693ffe455adSEugenia Emantayev int reset_qkey_viols; 694ffe455adSEugenia Emantayev int port; 695ffe455adSEugenia Emantayev int is_eth; 696b6ffaeffSJack Morgenstein int num_gids; 697b6ffaeffSJack Morgenstein int base; 698ffe455adSEugenia Emantayev u32 in_modifier; 699ffe455adSEugenia Emantayev u32 promisc; 700ffe455adSEugenia Emantayev u16 mtu, prev_mtu; 701ffe455adSEugenia Emantayev int err; 702b6ffaeffSJack Morgenstein int i, j; 703b6ffaeffSJack Morgenstein int offset; 704ffe455adSEugenia Emantayev __be32 agg_cap_mask; 705ffe455adSEugenia Emantayev __be32 slave_cap_mask; 706ffe455adSEugenia Emantayev __be32 new_cap_mask; 707ffe455adSEugenia Emantayev 708ffe455adSEugenia Emantayev port = in_mod & 0xff; 709ffe455adSEugenia Emantayev in_modifier = in_mod >> 8; 710ffe455adSEugenia Emantayev is_eth = op_mod; 711ffe455adSEugenia Emantayev port_info = &priv->port[port]; 712ffe455adSEugenia Emantayev 713ffe455adSEugenia Emantayev /* Slaves cannot perform SET_PORT operations except changing MTU */ 714ffe455adSEugenia Emantayev if (is_eth) { 715ffe455adSEugenia Emantayev if (slave != dev->caps.function && 7169cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GENERAL && 7179cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GID_TABLE) { 718ffe455adSEugenia Emantayev mlx4_warn(dev, "denying SET_PORT for slave:%d\n", 719ffe455adSEugenia Emantayev slave); 720ffe455adSEugenia Emantayev return -EINVAL; 721ffe455adSEugenia Emantayev } 722ffe455adSEugenia Emantayev switch (in_modifier) { 723ffe455adSEugenia Emantayev case MLX4_SET_PORT_RQP_CALC: 724ffe455adSEugenia Emantayev qpn_context = inbox->buf; 725ffe455adSEugenia Emantayev qpn_context->base_qpn = 726ffe455adSEugenia Emantayev cpu_to_be32(port_info->base_qpn); 727ffe455adSEugenia Emantayev qpn_context->n_mac = 0x7; 728ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->promisc) >> 729ffe455adSEugenia Emantayev SET_PORT_PROMISC_SHIFT; 730ffe455adSEugenia Emantayev qpn_context->promisc = cpu_to_be32( 731ffe455adSEugenia Emantayev promisc << SET_PORT_PROMISC_SHIFT | 732ffe455adSEugenia Emantayev port_info->base_qpn); 733ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->mcast) >> 734ffe455adSEugenia Emantayev SET_PORT_MC_PROMISC_SHIFT; 735ffe455adSEugenia Emantayev qpn_context->mcast = cpu_to_be32( 736ffe455adSEugenia Emantayev promisc << SET_PORT_MC_PROMISC_SHIFT | 737ffe455adSEugenia Emantayev port_info->base_qpn); 738ffe455adSEugenia Emantayev break; 739ffe455adSEugenia Emantayev case MLX4_SET_PORT_GENERAL: 740ffe455adSEugenia Emantayev gen_context = inbox->buf; 741ffe455adSEugenia Emantayev /* Mtu is configured as the max MTU among all the 742ffe455adSEugenia Emantayev * the functions on the port. */ 743ffe455adSEugenia Emantayev mtu = be16_to_cpu(gen_context->mtu); 744c59fec20SEugenia Emantayev mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] + 745c59fec20SEugenia Emantayev ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); 746ffe455adSEugenia Emantayev prev_mtu = slave_st->mtu[port]; 747ffe455adSEugenia Emantayev slave_st->mtu[port] = mtu; 748ffe455adSEugenia Emantayev if (mtu > master->max_mtu[port]) 749ffe455adSEugenia Emantayev master->max_mtu[port] = mtu; 750ffe455adSEugenia Emantayev if (mtu < prev_mtu && prev_mtu == 751ffe455adSEugenia Emantayev master->max_mtu[port]) { 752ffe455adSEugenia Emantayev slave_st->mtu[port] = mtu; 753ffe455adSEugenia Emantayev master->max_mtu[port] = mtu; 754ffe455adSEugenia Emantayev for (i = 0; i < dev->num_slaves; i++) { 755ffe455adSEugenia Emantayev master->max_mtu[port] = 756ffe455adSEugenia Emantayev max(master->max_mtu[port], 757ffe455adSEugenia Emantayev master->slave_state[i].mtu[port]); 758ffe455adSEugenia Emantayev } 759ffe455adSEugenia Emantayev } 760ffe455adSEugenia Emantayev 761ffe455adSEugenia Emantayev gen_context->mtu = cpu_to_be16(master->max_mtu[port]); 762ffe455adSEugenia Emantayev break; 7639cd59352SJack Morgenstein case MLX4_SET_PORT_GID_TABLE: 764b6ffaeffSJack Morgenstein /* change to MULTIPLE entries: number of guest's gids 765b6ffaeffSJack Morgenstein * need a FOR-loop here over number of gids the guest has. 766b6ffaeffSJack Morgenstein * 1. Check no duplicates in gids passed by slave 767b6ffaeffSJack Morgenstein */ 768449fc488SMatan Barak num_gids = mlx4_get_slave_num_gids(dev, slave, port); 769449fc488SMatan Barak base = mlx4_get_base_gid_ix(dev, slave, port); 770b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 771b6ffaeffSJack Morgenstein for (i = 0; i < num_gids; gid_entry_mbox++, i++) { 772b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 773b6ffaeffSJack Morgenstein sizeof(zgid_entry))) 774b6ffaeffSJack Morgenstein continue; 775b6ffaeffSJack Morgenstein gid_entry_mb1 = gid_entry_mbox + 1; 776b6ffaeffSJack Morgenstein for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) { 777b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw, 778b6ffaeffSJack Morgenstein zgid_entry.raw, sizeof(zgid_entry))) 779b6ffaeffSJack Morgenstein continue; 780b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw, 781b6ffaeffSJack Morgenstein sizeof(gid_entry_mbox->raw))) { 782b6ffaeffSJack Morgenstein /* found duplicate */ 783b6ffaeffSJack Morgenstein return -EINVAL; 784b6ffaeffSJack Morgenstein } 785b6ffaeffSJack Morgenstein } 786b6ffaeffSJack Morgenstein } 787b6ffaeffSJack Morgenstein 788b6ffaeffSJack Morgenstein /* 2. Check that do not have duplicates in OTHER 789b6ffaeffSJack Morgenstein * entries in the port GID table 790b6ffaeffSJack Morgenstein */ 791111c6094SJack Morgenstein 792111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex)); 7939cd59352SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 794b6ffaeffSJack Morgenstein if (i >= base && i < base + num_gids) 795b6ffaeffSJack Morgenstein continue; /* don't compare to slave's current gids */ 796111c6094SJack Morgenstein gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i]; 797b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry))) 798b6ffaeffSJack Morgenstein continue; 799b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 800b6ffaeffSJack Morgenstein for (j = 0; j < num_gids; gid_entry_mbox++, j++) { 801b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, 802b6ffaeffSJack Morgenstein sizeof(zgid_entry))) 803b6ffaeffSJack Morgenstein continue; 804b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw, 805b6ffaeffSJack Morgenstein sizeof(gid_entry_tbl->raw))) { 806b6ffaeffSJack Morgenstein /* found duplicate */ 8071a91de28SJoe Perches mlx4_warn(dev, "requested gid entry for slave:%d is a duplicate of gid at index %d\n", 8089cd59352SJack Morgenstein slave, i); 809111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 810b6ffaeffSJack Morgenstein return -EINVAL; 8119cd59352SJack Morgenstein } 8129cd59352SJack Morgenstein } 8139cd59352SJack Morgenstein } 814b6ffaeffSJack Morgenstein 815b6ffaeffSJack Morgenstein /* insert slave GIDs with memcpy, starting at slave's base index */ 816b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 817b6ffaeffSJack Morgenstein for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++) 818111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw, 819111c6094SJack Morgenstein gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE); 820b6ffaeffSJack Morgenstein 821b6ffaeffSJack Morgenstein /* Now, copy roce port gids table to current mailbox for passing to FW */ 822b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); 823b6ffaeffSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) 824111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw, 825111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw, 826111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 827b6ffaeffSJack Morgenstein 828111c6094SJack Morgenstein err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 829111c6094SJack Morgenstein MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 830111c6094SJack Morgenstein MLX4_CMD_NATIVE); 831111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex)); 832111c6094SJack Morgenstein return err; 833ffe455adSEugenia Emantayev } 834111c6094SJack Morgenstein 835111c6094SJack Morgenstein return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod, 836ffe455adSEugenia Emantayev MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 837ffe455adSEugenia Emantayev MLX4_CMD_NATIVE); 838ffe455adSEugenia Emantayev } 839ffe455adSEugenia Emantayev 840ffe455adSEugenia Emantayev /* For IB, we only consider: 841ffe455adSEugenia Emantayev * - The capability mask, which is set to the aggregate of all 842ffe455adSEugenia Emantayev * slave function capabilities 843ffe455adSEugenia Emantayev * - The QKey violatin counter - reset according to each request. 844ffe455adSEugenia Emantayev */ 845ffe455adSEugenia Emantayev 846ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 847ffe455adSEugenia Emantayev reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40; 848ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[2]; 849ffe455adSEugenia Emantayev } else { 850ffe455adSEugenia Emantayev reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1; 851ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[1]; 852ffe455adSEugenia Emantayev } 853ffe455adSEugenia Emantayev 854efcd235dSJack Morgenstein /* slave may not set the IS_SM capability for the port */ 855efcd235dSJack Morgenstein if (slave != mlx4_master_func_num(dev) && 856efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM)) 857efcd235dSJack Morgenstein return -EINVAL; 858efcd235dSJack Morgenstein 859efcd235dSJack Morgenstein /* No DEV_MGMT in multifunc mode */ 860efcd235dSJack Morgenstein if (mlx4_is_mfunc(dev) && 861efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP)) 862efcd235dSJack Morgenstein return -EINVAL; 863efcd235dSJack Morgenstein 864ffe455adSEugenia Emantayev agg_cap_mask = 0; 865ffe455adSEugenia Emantayev slave_cap_mask = 866ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; 867ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask; 868ffe455adSEugenia Emantayev for (i = 0; i < dev->num_slaves; i++) 869ffe455adSEugenia Emantayev agg_cap_mask |= 870ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[i].ib_cap_mask[port]; 871ffe455adSEugenia Emantayev 872ffe455adSEugenia Emantayev /* only clear mailbox for guests. Master may be setting 873ffe455adSEugenia Emantayev * MTU or PKEY table size 874ffe455adSEugenia Emantayev */ 875ffe455adSEugenia Emantayev if (slave != dev->caps.function) 876ffe455adSEugenia Emantayev memset(inbox->buf, 0, 256); 877ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 878edc4a67eSJack Morgenstein *(u8 *) inbox->buf |= !!reset_qkey_viols << 6; 879ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[2] = agg_cap_mask; 880ffe455adSEugenia Emantayev } else { 881edc4a67eSJack Morgenstein ((u8 *) inbox->buf)[3] |= !!reset_qkey_viols; 882ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[1] = agg_cap_mask; 883ffe455adSEugenia Emantayev } 884ffe455adSEugenia Emantayev 885ffe455adSEugenia Emantayev err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT, 886ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 887ffe455adSEugenia Emantayev if (err) 888ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = 889ffe455adSEugenia Emantayev slave_cap_mask; 890ffe455adSEugenia Emantayev return err; 891ffe455adSEugenia Emantayev } 892ffe455adSEugenia Emantayev 893ffe455adSEugenia Emantayev int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, 894ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 895ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 896ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 897ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 898ffe455adSEugenia Emantayev { 899449fc488SMatan Barak int port = mlx4_slave_convert_port( 900449fc488SMatan Barak dev, slave, vhcr->in_modifier & 0xFF); 901449fc488SMatan Barak 902449fc488SMatan Barak if (port < 0) 903449fc488SMatan Barak return -EINVAL; 904449fc488SMatan Barak 905449fc488SMatan Barak vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) | 906449fc488SMatan Barak (port & 0xFF); 907449fc488SMatan Barak 908ffe455adSEugenia Emantayev return mlx4_common_set_port(dev, slave, vhcr->in_modifier, 909ffe455adSEugenia Emantayev vhcr->op_modifier, inbox); 910ffe455adSEugenia Emantayev } 911ffe455adSEugenia Emantayev 912096335b3SOr Gerlitz /* bit locations for set port command with zero op modifier */ 913096335b3SOr Gerlitz enum { 914096335b3SOr Gerlitz MLX4_SET_PORT_VL_CAP = 4, /* bits 7:4 */ 915096335b3SOr Gerlitz MLX4_SET_PORT_MTU_CAP = 12, /* bits 15:12 */ 9166634961cSJack Morgenstein MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20, 917096335b3SOr Gerlitz MLX4_CHANGE_PORT_VL_CAP = 21, 918096335b3SOr Gerlitz MLX4_CHANGE_PORT_MTU_CAP = 22, 919096335b3SOr Gerlitz }; 920096335b3SOr Gerlitz 9216634961cSJack Morgenstein int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz) 9225a2cc190SJeff Kirsher { 9235a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 9246634961cSJack Morgenstein int err, vl_cap, pkey_tbl_flag = 0; 9255a2cc190SJeff Kirsher 9265a2cc190SJeff Kirsher if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) 9275a2cc190SJeff Kirsher return 0; 9285a2cc190SJeff Kirsher 9295a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 9305a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 9315a2cc190SJeff Kirsher return PTR_ERR(mailbox); 9325a2cc190SJeff Kirsher 9335a2cc190SJeff Kirsher ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; 934096335b3SOr Gerlitz 9356634961cSJack Morgenstein if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) { 9366634961cSJack Morgenstein pkey_tbl_flag = 1; 9376634961cSJack Morgenstein ((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz); 9386634961cSJack Morgenstein } 9396634961cSJack Morgenstein 940096335b3SOr Gerlitz /* IB VL CAP enum isn't used by the firmware, just numerical values */ 941096335b3SOr Gerlitz for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) { 942096335b3SOr Gerlitz ((__be32 *) mailbox->buf)[0] = cpu_to_be32( 943096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_MTU_CAP) | 944096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_VL_CAP) | 9456634961cSJack Morgenstein (pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) | 946096335b3SOr Gerlitz (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) | 947096335b3SOr Gerlitz (vl_cap << MLX4_SET_PORT_VL_CAP)); 9485a2cc190SJeff Kirsher err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT, 949f9baff50SJack Morgenstein MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 950096335b3SOr Gerlitz if (err != -ENOMEM) 951096335b3SOr Gerlitz break; 952096335b3SOr Gerlitz } 9535a2cc190SJeff Kirsher 9545a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 9555a2cc190SJeff Kirsher return err; 9565a2cc190SJeff Kirsher } 957ffe455adSEugenia Emantayev 958cb9ffb76SJoerg Roedel int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, 959ffe455adSEugenia Emantayev u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx) 960ffe455adSEugenia Emantayev { 961ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 962ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *context; 963ffe455adSEugenia Emantayev int err; 964ffe455adSEugenia Emantayev u32 in_mod; 965ffe455adSEugenia Emantayev 966ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 967ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 968ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 969ffe455adSEugenia Emantayev context = mailbox->buf; 970ffe455adSEugenia Emantayev context->flags = SET_PORT_GEN_ALL_VALID; 971ffe455adSEugenia Emantayev context->mtu = cpu_to_be16(mtu); 972ffe455adSEugenia Emantayev context->pptx = (pptx * (!pfctx)) << 7; 973ffe455adSEugenia Emantayev context->pfctx = pfctx; 974ffe455adSEugenia Emantayev context->pprx = (pprx * (!pfcrx)) << 7; 975ffe455adSEugenia Emantayev context->pfcrx = pfcrx; 976ffe455adSEugenia Emantayev 977ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 978ffe455adSEugenia Emantayev err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 979ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, 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; 1015ffe455adSEugenia Emantayev err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 1016ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 1017ffe455adSEugenia Emantayev 1018ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 1019ffe455adSEugenia Emantayev return err; 1020ffe455adSEugenia Emantayev } 1021ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); 1022ffe455adSEugenia Emantayev 1023e5395e92SAmir Vadai int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc) 1024e5395e92SAmir Vadai { 1025e5395e92SAmir Vadai struct mlx4_cmd_mailbox *mailbox; 1026e5395e92SAmir Vadai struct mlx4_set_port_prio2tc_context *context; 1027e5395e92SAmir Vadai int err; 1028e5395e92SAmir Vadai u32 in_mod; 1029e5395e92SAmir Vadai int i; 1030e5395e92SAmir Vadai 1031e5395e92SAmir Vadai mailbox = mlx4_alloc_cmd_mailbox(dev); 1032e5395e92SAmir Vadai if (IS_ERR(mailbox)) 1033e5395e92SAmir Vadai return PTR_ERR(mailbox); 1034e5395e92SAmir Vadai context = mailbox->buf; 1035e5395e92SAmir Vadai for (i = 0; i < MLX4_NUM_UP; i += 2) 1036e5395e92SAmir Vadai context->prio2tc[i >> 1] = prio2tc[i] << 4 | prio2tc[i + 1]; 1037e5395e92SAmir Vadai 1038e5395e92SAmir Vadai in_mod = MLX4_SET_PORT_PRIO2TC << 8 | port; 1039e5395e92SAmir Vadai err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 1040e5395e92SAmir Vadai MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1041e5395e92SAmir Vadai 1042e5395e92SAmir Vadai mlx4_free_cmd_mailbox(dev, mailbox); 1043e5395e92SAmir Vadai return err; 1044e5395e92SAmir Vadai } 1045e5395e92SAmir Vadai EXPORT_SYMBOL(mlx4_SET_PORT_PRIO2TC); 1046e5395e92SAmir Vadai 1047e5395e92SAmir Vadai int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, 1048e5395e92SAmir Vadai u8 *pg, u16 *ratelimit) 1049e5395e92SAmir Vadai { 1050e5395e92SAmir Vadai struct mlx4_cmd_mailbox *mailbox; 1051e5395e92SAmir Vadai struct mlx4_set_port_scheduler_context *context; 1052e5395e92SAmir Vadai int err; 1053e5395e92SAmir Vadai u32 in_mod; 1054e5395e92SAmir Vadai int i; 1055e5395e92SAmir Vadai 1056e5395e92SAmir Vadai mailbox = mlx4_alloc_cmd_mailbox(dev); 1057e5395e92SAmir Vadai if (IS_ERR(mailbox)) 1058e5395e92SAmir Vadai return PTR_ERR(mailbox); 1059e5395e92SAmir Vadai context = mailbox->buf; 1060e5395e92SAmir Vadai 1061e5395e92SAmir Vadai for (i = 0; i < MLX4_NUM_TC; i++) { 1062e5395e92SAmir Vadai struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i]; 1063523ece88SEugenia Emantayev u16 r; 1064523ece88SEugenia Emantayev 1065523ece88SEugenia Emantayev if (ratelimit && ratelimit[i]) { 1066523ece88SEugenia Emantayev if (ratelimit[i] <= MLX4_MAX_100M_UNITS_VAL) { 1067523ece88SEugenia Emantayev r = ratelimit[i]; 1068523ece88SEugenia Emantayev tc->max_bw_units = 1069523ece88SEugenia Emantayev htons(MLX4_RATELIMIT_100M_UNITS); 1070523ece88SEugenia Emantayev } else { 1071523ece88SEugenia Emantayev r = ratelimit[i]/10; 1072523ece88SEugenia Emantayev tc->max_bw_units = 1073523ece88SEugenia Emantayev htons(MLX4_RATELIMIT_1G_UNITS); 1074523ece88SEugenia Emantayev } 1075523ece88SEugenia Emantayev tc->max_bw_value = htons(r); 1076523ece88SEugenia Emantayev } else { 1077523ece88SEugenia Emantayev tc->max_bw_value = htons(MLX4_RATELIMIT_DEFAULT); 1078523ece88SEugenia Emantayev tc->max_bw_units = htons(MLX4_RATELIMIT_1G_UNITS); 1079523ece88SEugenia Emantayev } 1080e5395e92SAmir Vadai 1081e5395e92SAmir Vadai tc->pg = htons(pg[i]); 1082e5395e92SAmir Vadai tc->bw_precentage = htons(tc_tx_bw[i]); 1083e5395e92SAmir Vadai } 1084e5395e92SAmir Vadai 1085e5395e92SAmir Vadai in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port; 1086e5395e92SAmir Vadai err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 1087e5395e92SAmir Vadai MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 1088e5395e92SAmir Vadai 1089e5395e92SAmir Vadai mlx4_free_cmd_mailbox(dev, mailbox); 1090e5395e92SAmir Vadai return err; 1091e5395e92SAmir Vadai } 1092e5395e92SAmir Vadai EXPORT_SYMBOL(mlx4_SET_PORT_SCHEDULER); 1093e5395e92SAmir Vadai 10947ffdf726SOr Gerlitz enum { 10957ffdf726SOr Gerlitz VXLAN_ENABLE_MODIFY = 1 << 7, 10967ffdf726SOr Gerlitz VXLAN_STEERING_MODIFY = 1 << 6, 10977ffdf726SOr Gerlitz 10987ffdf726SOr Gerlitz VXLAN_ENABLE = 1 << 7, 10997ffdf726SOr Gerlitz }; 11007ffdf726SOr Gerlitz 11017ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context { 11027ffdf726SOr Gerlitz u32 reserved1; 11037ffdf726SOr Gerlitz u8 modify_flags; 11047ffdf726SOr Gerlitz u8 reserved2; 11057ffdf726SOr Gerlitz u8 enable_flags; 11067ffdf726SOr Gerlitz u8 steering; 11077ffdf726SOr Gerlitz }; 11087ffdf726SOr Gerlitz 11091b136de1SOr Gerlitz int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable) 11107ffdf726SOr Gerlitz { 11117ffdf726SOr Gerlitz int err; 11127ffdf726SOr Gerlitz u32 in_mod; 11137ffdf726SOr Gerlitz struct mlx4_cmd_mailbox *mailbox; 11147ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context *context; 11157ffdf726SOr Gerlitz 11167ffdf726SOr Gerlitz mailbox = mlx4_alloc_cmd_mailbox(dev); 11177ffdf726SOr Gerlitz if (IS_ERR(mailbox)) 11187ffdf726SOr Gerlitz return PTR_ERR(mailbox); 11197ffdf726SOr Gerlitz context = mailbox->buf; 11207ffdf726SOr Gerlitz memset(context, 0, sizeof(*context)); 11217ffdf726SOr Gerlitz 11227ffdf726SOr Gerlitz context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY; 11231b136de1SOr Gerlitz if (enable) 11247ffdf726SOr Gerlitz context->enable_flags = VXLAN_ENABLE; 11257ffdf726SOr Gerlitz context->steering = steering; 11267ffdf726SOr Gerlitz 11277ffdf726SOr Gerlitz in_mod = MLX4_SET_PORT_VXLAN << 8 | port; 11287ffdf726SOr Gerlitz err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 11297ffdf726SOr Gerlitz MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 11307ffdf726SOr Gerlitz 11317ffdf726SOr Gerlitz mlx4_free_cmd_mailbox(dev, mailbox); 11327ffdf726SOr Gerlitz return err; 11337ffdf726SOr Gerlitz } 11347ffdf726SOr Gerlitz EXPORT_SYMBOL(mlx4_SET_PORT_VXLAN); 11357ffdf726SOr Gerlitz 1136ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1137ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1138ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1139ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1140ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1141ffe455adSEugenia Emantayev { 1142ffe455adSEugenia Emantayev int err = 0; 1143ffe455adSEugenia Emantayev 1144ffe455adSEugenia Emantayev return err; 1145ffe455adSEugenia Emantayev } 1146ffe455adSEugenia Emantayev 1147ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, 1148ffe455adSEugenia Emantayev u64 mac, u64 clear, u8 mode) 1149ffe455adSEugenia Emantayev { 1150ffe455adSEugenia Emantayev return mlx4_cmd(dev, (mac | (clear << 63)), port, mode, 1151ffe455adSEugenia Emantayev MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B, 1152ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 1153ffe455adSEugenia Emantayev } 1154ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR); 1155ffe455adSEugenia Emantayev 1156ffe455adSEugenia Emantayev int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, 1157ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1158ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1159ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1160ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1161ffe455adSEugenia Emantayev { 1162ffe455adSEugenia Emantayev int err = 0; 1163ffe455adSEugenia Emantayev 1164ffe455adSEugenia Emantayev return err; 1165ffe455adSEugenia Emantayev } 1166ffe455adSEugenia Emantayev 1167ffe455adSEugenia Emantayev int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave, 1168ffe455adSEugenia Emantayev u32 in_mod, struct mlx4_cmd_mailbox *outbox) 1169ffe455adSEugenia Emantayev { 1170ffe455adSEugenia Emantayev return mlx4_cmd_box(dev, 0, outbox->dma, in_mod, 0, 1171ffe455adSEugenia Emantayev MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B, 1172ffe455adSEugenia Emantayev MLX4_CMD_NATIVE); 1173ffe455adSEugenia Emantayev } 1174ffe455adSEugenia Emantayev 1175ffe455adSEugenia Emantayev int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, 1176ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 1177ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 1178ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 1179ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 1180ffe455adSEugenia Emantayev { 118135fb9afbSEugenia Emantayev if (slave != dev->caps.function) 118235fb9afbSEugenia Emantayev return 0; 1183ffe455adSEugenia Emantayev return mlx4_common_dump_eth_stats(dev, slave, 1184ffe455adSEugenia Emantayev vhcr->in_modifier, outbox); 1185ffe455adSEugenia Emantayev } 118693ece0c1SEugenia Emantayev 118793ece0c1SEugenia Emantayev void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap) 118893ece0c1SEugenia Emantayev { 118993ece0c1SEugenia Emantayev if (!mlx4_is_mfunc(dev)) { 119093ece0c1SEugenia Emantayev *stats_bitmap = 0; 119193ece0c1SEugenia Emantayev return; 119293ece0c1SEugenia Emantayev } 119393ece0c1SEugenia Emantayev 119493ece0c1SEugenia Emantayev *stats_bitmap = (MLX4_STATS_TRAFFIC_COUNTERS_MASK | 119593ece0c1SEugenia Emantayev MLX4_STATS_TRAFFIC_DROPS_MASK | 119693ece0c1SEugenia Emantayev MLX4_STATS_PORT_COUNTERS_MASK); 119793ece0c1SEugenia Emantayev 119893ece0c1SEugenia Emantayev if (mlx4_is_master(dev)) 119993ece0c1SEugenia Emantayev *stats_bitmap |= MLX4_STATS_ERROR_COUNTERS_MASK; 120093ece0c1SEugenia Emantayev } 120193ece0c1SEugenia Emantayev EXPORT_SYMBOL(mlx4_set_stats_bitmap); 12026ee51a4eSJack Morgenstein 12039cd59352SJack Morgenstein int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, 12049cd59352SJack Morgenstein int *slave_id) 12056ee51a4eSJack Morgenstein { 12066ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 12076ee51a4eSJack Morgenstein int i, found_ix = -1; 1208b6ffaeffSJack Morgenstein int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; 1209449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport; 1210449fc488SMatan Barak unsigned num_vfs; 1211449fc488SMatan Barak int slave_gid; 12126ee51a4eSJack Morgenstein 12136ee51a4eSJack Morgenstein if (!mlx4_is_mfunc(dev)) 12146ee51a4eSJack Morgenstein return -EINVAL; 12156ee51a4eSJack Morgenstein 1216449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port); 1217449fc488SMatan Barak num_vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1; 1218449fc488SMatan Barak 12196ee51a4eSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { 1220111c6094SJack Morgenstein if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid, 1221111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE)) { 12226ee51a4eSJack Morgenstein found_ix = i; 12236ee51a4eSJack Morgenstein break; 12246ee51a4eSJack Morgenstein } 12256ee51a4eSJack Morgenstein } 12266ee51a4eSJack Morgenstein 1227b6ffaeffSJack Morgenstein if (found_ix >= 0) { 12280254bc82SMatan Barak /* Calculate a slave_gid which is the slave number in the gid 12290254bc82SMatan Barak * table and not a globally unique slave number. 12300254bc82SMatan Barak */ 1231b6ffaeffSJack Morgenstein if (found_ix < MLX4_ROCE_PF_GIDS) 1232449fc488SMatan Barak slave_gid = 0; 1233449fc488SMatan Barak else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) * 1234449fc488SMatan Barak (vf_gids / num_vfs + 1)) 1235449fc488SMatan Barak slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) / 1236449fc488SMatan Barak (vf_gids / num_vfs + 1)) + 1; 1237b6ffaeffSJack Morgenstein else 1238449fc488SMatan Barak slave_gid = 1239b6ffaeffSJack Morgenstein ((found_ix - MLX4_ROCE_PF_GIDS - 1240449fc488SMatan Barak ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) / 1241449fc488SMatan Barak (vf_gids / num_vfs)) + vf_gids % num_vfs + 1; 1242449fc488SMatan Barak 12430254bc82SMatan Barak /* Calculate the globally unique slave id */ 1244449fc488SMatan Barak if (slave_gid) { 1245449fc488SMatan Barak struct mlx4_active_ports exclusive_ports; 1246449fc488SMatan Barak struct mlx4_active_ports actv_ports; 1247449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv; 1248449fc488SMatan Barak unsigned max_port_p_one; 12490254bc82SMatan Barak int num_vfs_before = 0; 12500254bc82SMatan Barak int candidate_slave_gid; 1251449fc488SMatan Barak 12520254bc82SMatan Barak /* Calculate how many VFs are on the previous port, if exists */ 1253449fc488SMatan Barak for (i = 1; i < port; i++) { 1254449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports); 12550254bc82SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1256449fc488SMatan Barak slaves_pport_actv = 1257449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv( 1258449fc488SMatan Barak dev, &exclusive_ports); 12590254bc82SMatan Barak num_vfs_before += bitmap_weight( 1260449fc488SMatan Barak slaves_pport_actv.slaves, 1261449fc488SMatan Barak dev->num_vfs + 1); 1262449fc488SMatan Barak } 1263449fc488SMatan Barak 12640254bc82SMatan Barak /* candidate_slave_gid isn't necessarily the correct slave, but 12650254bc82SMatan Barak * it has the same number of ports and is assigned to the same 12660254bc82SMatan Barak * ports as the real slave we're looking for. On dual port VF, 12670254bc82SMatan Barak * slave_gid = [single port VFs on port <port>] + 12680254bc82SMatan Barak * [offset of the current slave from the first dual port VF] + 12690254bc82SMatan Barak * 1 (for the PF). 12700254bc82SMatan Barak */ 12710254bc82SMatan Barak candidate_slave_gid = slave_gid + num_vfs_before; 12720254bc82SMatan Barak 12730254bc82SMatan Barak actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid); 1274449fc488SMatan Barak max_port_p_one = find_first_bit( 1275449fc488SMatan Barak actv_ports.ports, dev->caps.num_ports) + 1276449fc488SMatan Barak bitmap_weight(actv_ports.ports, 1277449fc488SMatan Barak dev->caps.num_ports) + 1; 1278449fc488SMatan Barak 12790254bc82SMatan Barak /* Calculate the real slave number */ 1280449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) { 1281449fc488SMatan Barak if (i == port) 1282449fc488SMatan Barak continue; 1283449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, 1284449fc488SMatan Barak dev->caps.num_ports); 1285449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports); 1286449fc488SMatan Barak slaves_pport_actv = 1287449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv( 1288449fc488SMatan Barak dev, &exclusive_ports); 1289449fc488SMatan Barak slave_gid += bitmap_weight( 1290449fc488SMatan Barak slaves_pport_actv.slaves, 1291449fc488SMatan Barak dev->num_vfs + 1); 1292449fc488SMatan Barak } 1293449fc488SMatan Barak } 1294449fc488SMatan Barak *slave_id = slave_gid; 1295b6ffaeffSJack Morgenstein } 12966ee51a4eSJack Morgenstein 12976ee51a4eSJack Morgenstein return (found_ix >= 0) ? 0 : -EINVAL; 12986ee51a4eSJack Morgenstein } 12996ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid); 13006ee51a4eSJack Morgenstein 13019cd59352SJack Morgenstein int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, 13029cd59352SJack Morgenstein u8 *gid) 13036ee51a4eSJack Morgenstein { 13046ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev); 13056ee51a4eSJack Morgenstein 13066ee51a4eSJack Morgenstein if (!mlx4_is_master(dev)) 13076ee51a4eSJack Morgenstein return -EINVAL; 13086ee51a4eSJack Morgenstein 1309111c6094SJack Morgenstein memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw, 1310111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE); 13116ee51a4eSJack Morgenstein return 0; 13126ee51a4eSJack Morgenstein } 13136ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); 1314