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> 35ee40fa06SPaul Gortmaker #include <linux/export.h> 365a2cc190SJeff Kirsher 375a2cc190SJeff Kirsher #include <linux/mlx4/cmd.h> 385a2cc190SJeff Kirsher 395a2cc190SJeff Kirsher #include "mlx4.h" 405a2cc190SJeff Kirsher 415a2cc190SJeff Kirsher #define MLX4_MAC_VALID (1ull << 63) 425a2cc190SJeff Kirsher #define MLX4_MAC_MASK 0xffffffffffffULL 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 78ffe455adSEugenia Emantayev static int mlx4_uc_steer_add(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn) 795a2cc190SJeff Kirsher { 805a2cc190SJeff Kirsher struct mlx4_qp qp; 815a2cc190SJeff Kirsher u8 gid[16] = {0}; 822ab573c5SYevgeny Petrilin __be64 be_mac; 835a2cc190SJeff Kirsher int err; 845a2cc190SJeff Kirsher 855a2cc190SJeff Kirsher qp.qpn = *qpn; 865a2cc190SJeff Kirsher 875a2cc190SJeff Kirsher mac &= 0xffffffffffffULL; 882ab573c5SYevgeny Petrilin be_mac = cpu_to_be64(mac << 16); 892ab573c5SYevgeny Petrilin memcpy(&gid[10], &be_mac, ETH_ALEN); 905a2cc190SJeff Kirsher gid[5] = port; 915a2cc190SJeff Kirsher 92ffe455adSEugenia Emantayev err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH); 93ffe455adSEugenia Emantayev if (err) 94ffe455adSEugenia Emantayev mlx4_warn(dev, "Failed Attaching Unicast\n"); 955a2cc190SJeff Kirsher 965a2cc190SJeff Kirsher return err; 975a2cc190SJeff Kirsher } 985a2cc190SJeff Kirsher 995a2cc190SJeff Kirsher static void mlx4_uc_steer_release(struct mlx4_dev *dev, u8 port, 100ffe455adSEugenia Emantayev u64 mac, int qpn) 1015a2cc190SJeff Kirsher { 1025a2cc190SJeff Kirsher struct mlx4_qp qp; 1035a2cc190SJeff Kirsher u8 gid[16] = {0}; 1042ab573c5SYevgeny Petrilin __be64 be_mac; 1055a2cc190SJeff Kirsher 1065a2cc190SJeff Kirsher qp.qpn = qpn; 1075a2cc190SJeff Kirsher mac &= 0xffffffffffffULL; 1082ab573c5SYevgeny Petrilin be_mac = cpu_to_be64(mac << 16); 1092ab573c5SYevgeny Petrilin memcpy(&gid[10], &be_mac, ETH_ALEN); 1105a2cc190SJeff Kirsher gid[5] = port; 1115a2cc190SJeff Kirsher 112ffe455adSEugenia Emantayev mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH); 1135a2cc190SJeff Kirsher } 1145a2cc190SJeff Kirsher 1155a2cc190SJeff Kirsher static int validate_index(struct mlx4_dev *dev, 1165a2cc190SJeff Kirsher struct mlx4_mac_table *table, int index) 1175a2cc190SJeff Kirsher { 1185a2cc190SJeff Kirsher int err = 0; 1195a2cc190SJeff Kirsher 1205a2cc190SJeff Kirsher if (index < 0 || index >= table->max || !table->entries[index]) { 1215a2cc190SJeff Kirsher mlx4_warn(dev, "No valid Mac entry for the given index\n"); 1225a2cc190SJeff Kirsher err = -EINVAL; 1235a2cc190SJeff Kirsher } 1245a2cc190SJeff Kirsher return err; 1255a2cc190SJeff Kirsher } 1265a2cc190SJeff Kirsher 1275a2cc190SJeff Kirsher static int find_index(struct mlx4_dev *dev, 1285a2cc190SJeff Kirsher struct mlx4_mac_table *table, u64 mac) 1295a2cc190SJeff Kirsher { 1305a2cc190SJeff Kirsher int i; 131ffe455adSEugenia Emantayev 1325a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 133ffe455adSEugenia Emantayev if ((mac & MLX4_MAC_MASK) == 134ffe455adSEugenia Emantayev (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) 1355a2cc190SJeff Kirsher return i; 1365a2cc190SJeff Kirsher } 1375a2cc190SJeff Kirsher /* Mac not found */ 1385a2cc190SJeff Kirsher return -EINVAL; 1395a2cc190SJeff Kirsher } 1405a2cc190SJeff Kirsher 141ffe455adSEugenia Emantayev int mlx4_get_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn) 1425a2cc190SJeff Kirsher { 1435a2cc190SJeff Kirsher struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 1445a2cc190SJeff Kirsher struct mlx4_mac_entry *entry; 145ffe455adSEugenia Emantayev int index = 0; 146ffe455adSEugenia Emantayev int err = 0; 147ffe455adSEugenia Emantayev 148ffe455adSEugenia Emantayev mlx4_dbg(dev, "Registering MAC: 0x%llx for adding\n", 149ffe455adSEugenia Emantayev (unsigned long long) mac); 150ffe455adSEugenia Emantayev index = mlx4_register_mac(dev, port, mac); 151ffe455adSEugenia Emantayev if (index < 0) { 152ffe455adSEugenia Emantayev err = index; 153ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 154ffe455adSEugenia Emantayev (unsigned long long) mac); 155ffe455adSEugenia Emantayev return err; 156ffe455adSEugenia Emantayev } 157ffe455adSEugenia Emantayev 158c96d97f4SHadar Hen Zion if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { 159ffe455adSEugenia Emantayev *qpn = info->base_qpn + index; 160ffe455adSEugenia Emantayev return 0; 161ffe455adSEugenia Emantayev } 162ffe455adSEugenia Emantayev 163ffe455adSEugenia Emantayev err = mlx4_qp_reserve_range(dev, 1, 1, qpn); 164ffe455adSEugenia Emantayev mlx4_dbg(dev, "Reserved qp %d\n", *qpn); 165ffe455adSEugenia Emantayev if (err) { 166ffe455adSEugenia Emantayev mlx4_err(dev, "Failed to reserve qp for mac registration\n"); 167ffe455adSEugenia Emantayev goto qp_err; 168ffe455adSEugenia Emantayev } 169ffe455adSEugenia Emantayev 170ffe455adSEugenia Emantayev err = mlx4_uc_steer_add(dev, port, mac, qpn); 171ffe455adSEugenia Emantayev if (err) 172ffe455adSEugenia Emantayev goto steer_err; 173ffe455adSEugenia Emantayev 174ffe455adSEugenia Emantayev entry = kmalloc(sizeof *entry, GFP_KERNEL); 175ffe455adSEugenia Emantayev if (!entry) { 176ffe455adSEugenia Emantayev err = -ENOMEM; 177ffe455adSEugenia Emantayev goto alloc_err; 178ffe455adSEugenia Emantayev } 179ffe455adSEugenia Emantayev entry->mac = mac; 180ffe455adSEugenia Emantayev err = radix_tree_insert(&info->mac_tree, *qpn, entry); 181ffe455adSEugenia Emantayev if (err) 182ffe455adSEugenia Emantayev goto insert_err; 183ffe455adSEugenia Emantayev return 0; 184ffe455adSEugenia Emantayev 185ffe455adSEugenia Emantayev insert_err: 186ffe455adSEugenia Emantayev kfree(entry); 187ffe455adSEugenia Emantayev 188ffe455adSEugenia Emantayev alloc_err: 189ffe455adSEugenia Emantayev mlx4_uc_steer_release(dev, port, mac, *qpn); 190ffe455adSEugenia Emantayev 191ffe455adSEugenia Emantayev steer_err: 192ffe455adSEugenia Emantayev mlx4_qp_release_range(dev, *qpn, 1); 193ffe455adSEugenia Emantayev 194ffe455adSEugenia Emantayev qp_err: 195ffe455adSEugenia Emantayev mlx4_unregister_mac(dev, port, mac); 196ffe455adSEugenia Emantayev return err; 197ffe455adSEugenia Emantayev } 198ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(mlx4_get_eth_qp); 199ffe455adSEugenia Emantayev 200ffe455adSEugenia Emantayev void mlx4_put_eth_qp(struct mlx4_dev *dev, u8 port, u64 mac, int qpn) 201ffe455adSEugenia Emantayev { 202ffe455adSEugenia Emantayev struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 203ffe455adSEugenia Emantayev struct mlx4_mac_entry *entry; 204ffe455adSEugenia Emantayev 205ffe455adSEugenia Emantayev mlx4_dbg(dev, "Registering MAC: 0x%llx for deleting\n", 206ffe455adSEugenia Emantayev (unsigned long long) mac); 207ffe455adSEugenia Emantayev mlx4_unregister_mac(dev, port, mac); 2085a2cc190SJeff Kirsher 209c96d97f4SHadar Hen Zion if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) { 2105a2cc190SJeff Kirsher entry = radix_tree_lookup(&info->mac_tree, qpn); 2115a2cc190SJeff Kirsher if (entry) { 212ffe455adSEugenia Emantayev mlx4_dbg(dev, "Releasing qp: port %d, mac 0x%llx," 213ffe455adSEugenia Emantayev " qpn %d\n", port, 214ffe455adSEugenia Emantayev (unsigned long long) mac, qpn); 215ffe455adSEugenia Emantayev mlx4_uc_steer_release(dev, port, entry->mac, qpn); 216ffe455adSEugenia Emantayev mlx4_qp_release_range(dev, qpn, 1); 2175a2cc190SJeff Kirsher radix_tree_delete(&info->mac_tree, qpn); 2185a2cc190SJeff Kirsher kfree(entry); 2195a2cc190SJeff Kirsher } 2205a2cc190SJeff Kirsher } 221ffe455adSEugenia Emantayev } 222ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(mlx4_put_eth_qp); 223ffe455adSEugenia Emantayev 224ffe455adSEugenia Emantayev static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, 225ffe455adSEugenia Emantayev __be64 *entries) 226ffe455adSEugenia Emantayev { 227ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 228ffe455adSEugenia Emantayev u32 in_mod; 229ffe455adSEugenia Emantayev int err; 230ffe455adSEugenia Emantayev 231ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 232ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 233ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 234ffe455adSEugenia Emantayev 235ffe455adSEugenia Emantayev memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); 236ffe455adSEugenia Emantayev 237ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; 238ffe455adSEugenia Emantayev 239ffe455adSEugenia Emantayev err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 240ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 241ffe455adSEugenia Emantayev 242ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 243ffe455adSEugenia Emantayev return err; 244ffe455adSEugenia Emantayev } 245ffe455adSEugenia Emantayev 246ffe455adSEugenia Emantayev int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 247ffe455adSEugenia Emantayev { 248ffe455adSEugenia Emantayev struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 249ffe455adSEugenia Emantayev struct mlx4_mac_table *table = &info->mac_table; 250ffe455adSEugenia Emantayev int i, err = 0; 251ffe455adSEugenia Emantayev int free = -1; 252ffe455adSEugenia Emantayev 253ffe455adSEugenia Emantayev mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d\n", 254ffe455adSEugenia Emantayev (unsigned long long) mac, port); 255ffe455adSEugenia Emantayev 256ffe455adSEugenia Emantayev mutex_lock(&table->mutex); 257ffe455adSEugenia Emantayev for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { 258ffe455adSEugenia Emantayev if (free < 0 && !table->entries[i]) { 259ffe455adSEugenia Emantayev free = i; 260ffe455adSEugenia Emantayev continue; 261ffe455adSEugenia Emantayev } 262ffe455adSEugenia Emantayev 263ffe455adSEugenia Emantayev if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 264ffe455adSEugenia Emantayev /* MAC already registered, Must not have duplicates */ 265ffe455adSEugenia Emantayev err = -EEXIST; 266ffe455adSEugenia Emantayev goto out; 267ffe455adSEugenia Emantayev } 268ffe455adSEugenia Emantayev } 269ffe455adSEugenia Emantayev 270ffe455adSEugenia Emantayev mlx4_dbg(dev, "Free MAC index is %d\n", free); 271ffe455adSEugenia Emantayev 272ffe455adSEugenia Emantayev if (table->total == table->max) { 273ffe455adSEugenia Emantayev /* No free mac entries */ 274ffe455adSEugenia Emantayev err = -ENOSPC; 275ffe455adSEugenia Emantayev goto out; 276ffe455adSEugenia Emantayev } 277ffe455adSEugenia Emantayev 278ffe455adSEugenia Emantayev /* Register new MAC */ 279ffe455adSEugenia Emantayev table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); 280ffe455adSEugenia Emantayev 281ffe455adSEugenia Emantayev err = mlx4_set_port_mac_table(dev, port, table->entries); 282ffe455adSEugenia Emantayev if (unlikely(err)) { 283ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 284ffe455adSEugenia Emantayev (unsigned long long) mac); 285ffe455adSEugenia Emantayev table->entries[free] = 0; 286ffe455adSEugenia Emantayev goto out; 287ffe455adSEugenia Emantayev } 288ffe455adSEugenia Emantayev 289ffe455adSEugenia Emantayev err = free; 290ffe455adSEugenia Emantayev ++table->total; 291ffe455adSEugenia Emantayev out: 292ffe455adSEugenia Emantayev mutex_unlock(&table->mutex); 293ffe455adSEugenia Emantayev return err; 294ffe455adSEugenia Emantayev } 295ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_register_mac); 296ffe455adSEugenia Emantayev 297ffe455adSEugenia Emantayev int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac) 298ffe455adSEugenia Emantayev { 299ffe455adSEugenia Emantayev u64 out_param; 300ffe455adSEugenia Emantayev int err; 301ffe455adSEugenia Emantayev 302ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 303ffe455adSEugenia Emantayev set_param_l(&out_param, port); 304ffe455adSEugenia Emantayev err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 305ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 306ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 307ffe455adSEugenia Emantayev if (err) 308ffe455adSEugenia Emantayev return err; 309ffe455adSEugenia Emantayev 310ffe455adSEugenia Emantayev return get_param_l(&out_param); 311ffe455adSEugenia Emantayev } 312ffe455adSEugenia Emantayev return __mlx4_register_mac(dev, port, mac); 313ffe455adSEugenia Emantayev } 314ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(mlx4_register_mac); 315ffe455adSEugenia Emantayev 316ffe455adSEugenia Emantayev 317ffe455adSEugenia Emantayev void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 318ffe455adSEugenia Emantayev { 319ffe455adSEugenia Emantayev struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 320ffe455adSEugenia Emantayev struct mlx4_mac_table *table = &info->mac_table; 321ffe455adSEugenia Emantayev int index; 322ffe455adSEugenia Emantayev 323ffe455adSEugenia Emantayev index = find_index(dev, table, mac); 3245a2cc190SJeff Kirsher 3255a2cc190SJeff Kirsher mutex_lock(&table->mutex); 3265a2cc190SJeff Kirsher 3275a2cc190SJeff Kirsher if (validate_index(dev, table, index)) 3285a2cc190SJeff Kirsher goto out; 3295a2cc190SJeff Kirsher 3305a2cc190SJeff Kirsher table->entries[index] = 0; 3315a2cc190SJeff Kirsher mlx4_set_port_mac_table(dev, port, table->entries); 3325a2cc190SJeff Kirsher --table->total; 3335a2cc190SJeff Kirsher out: 3345a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 3355a2cc190SJeff Kirsher } 336ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_unregister_mac); 337ffe455adSEugenia Emantayev 338ffe455adSEugenia Emantayev void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac) 339ffe455adSEugenia Emantayev { 340ffe455adSEugenia Emantayev u64 out_param; 341ffe455adSEugenia Emantayev 342ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 343ffe455adSEugenia Emantayev set_param_l(&out_param, port); 344162344edSOr Gerlitz (void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC, 345ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES, 346ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 347ffe455adSEugenia Emantayev return; 348ffe455adSEugenia Emantayev } 349ffe455adSEugenia Emantayev __mlx4_unregister_mac(dev, port, mac); 350ffe455adSEugenia Emantayev return; 351ffe455adSEugenia Emantayev } 3525a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_mac); 3535a2cc190SJeff Kirsher 354ffe455adSEugenia Emantayev int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac) 3555a2cc190SJeff Kirsher { 3565a2cc190SJeff Kirsher struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 3575a2cc190SJeff Kirsher struct mlx4_mac_table *table = &info->mac_table; 3585a2cc190SJeff Kirsher struct mlx4_mac_entry *entry; 359ffe455adSEugenia Emantayev int index = qpn - info->base_qpn; 360ffe455adSEugenia Emantayev int err = 0; 3615a2cc190SJeff Kirsher 362c96d97f4SHadar Hen Zion if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) { 3635a2cc190SJeff Kirsher entry = radix_tree_lookup(&info->mac_tree, qpn); 3645a2cc190SJeff Kirsher if (!entry) 3655a2cc190SJeff Kirsher return -EINVAL; 366ffe455adSEugenia Emantayev mlx4_uc_steer_release(dev, port, entry->mac, qpn); 367ffe455adSEugenia Emantayev mlx4_unregister_mac(dev, port, entry->mac); 3685a2cc190SJeff Kirsher entry->mac = new_mac; 369ffe455adSEugenia Emantayev mlx4_register_mac(dev, port, new_mac); 370ffe455adSEugenia Emantayev err = mlx4_uc_steer_add(dev, port, entry->mac, &qpn); 3715a2cc190SJeff Kirsher return err; 3725a2cc190SJeff Kirsher } 3735a2cc190SJeff Kirsher 374ffe455adSEugenia Emantayev /* CX1 doesn't support multi-functions */ 3755a2cc190SJeff Kirsher mutex_lock(&table->mutex); 3765a2cc190SJeff Kirsher 3775a2cc190SJeff Kirsher err = validate_index(dev, table, index); 3785a2cc190SJeff Kirsher if (err) 3795a2cc190SJeff Kirsher goto out; 3805a2cc190SJeff Kirsher 3815a2cc190SJeff Kirsher table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); 3825a2cc190SJeff Kirsher 3835a2cc190SJeff Kirsher err = mlx4_set_port_mac_table(dev, port, table->entries); 3845a2cc190SJeff Kirsher if (unlikely(err)) { 385ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n", 386ffe455adSEugenia Emantayev (unsigned long long) new_mac); 3875a2cc190SJeff Kirsher table->entries[index] = 0; 3885a2cc190SJeff Kirsher } 3895a2cc190SJeff Kirsher out: 3905a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 3915a2cc190SJeff Kirsher return err; 3925a2cc190SJeff Kirsher } 3935a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_replace_mac); 394ffe455adSEugenia Emantayev 3955a2cc190SJeff Kirsher static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, 3965a2cc190SJeff Kirsher __be32 *entries) 3975a2cc190SJeff Kirsher { 3985a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 3995a2cc190SJeff Kirsher u32 in_mod; 4005a2cc190SJeff Kirsher int err; 4015a2cc190SJeff Kirsher 4025a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 4035a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 4045a2cc190SJeff Kirsher return PTR_ERR(mailbox); 4055a2cc190SJeff Kirsher 4065a2cc190SJeff Kirsher memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); 4075a2cc190SJeff Kirsher in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; 4085a2cc190SJeff Kirsher err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 409f9baff50SJack Morgenstein MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 4105a2cc190SJeff Kirsher 4115a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 4125a2cc190SJeff Kirsher 4135a2cc190SJeff Kirsher return err; 4145a2cc190SJeff Kirsher } 4155a2cc190SJeff Kirsher 4165a2cc190SJeff Kirsher int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx) 4175a2cc190SJeff Kirsher { 4185a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 4195a2cc190SJeff Kirsher int i; 4205a2cc190SJeff Kirsher 4215a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) { 4225a2cc190SJeff Kirsher if (table->refs[i] && 4235a2cc190SJeff Kirsher (vid == (MLX4_VLAN_MASK & 4245a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 4255a2cc190SJeff Kirsher /* VLAN already registered, increase reference count */ 4265a2cc190SJeff Kirsher *idx = i; 4275a2cc190SJeff Kirsher return 0; 4285a2cc190SJeff Kirsher } 4295a2cc190SJeff Kirsher } 4305a2cc190SJeff Kirsher 4315a2cc190SJeff Kirsher return -ENOENT; 4325a2cc190SJeff Kirsher } 4335a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan); 4345a2cc190SJeff Kirsher 435ffe455adSEugenia Emantayev static int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, 436ffe455adSEugenia Emantayev int *index) 4375a2cc190SJeff Kirsher { 4385a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 4395a2cc190SJeff Kirsher int i, err = 0; 4405a2cc190SJeff Kirsher int free = -1; 4415a2cc190SJeff Kirsher 4425a2cc190SJeff Kirsher mutex_lock(&table->mutex); 443e72ebf5aSYevgeny Petrilin 444e72ebf5aSYevgeny Petrilin if (table->total == table->max) { 445e72ebf5aSYevgeny Petrilin /* No free vlan entries */ 446e72ebf5aSYevgeny Petrilin err = -ENOSPC; 447e72ebf5aSYevgeny Petrilin goto out; 448e72ebf5aSYevgeny Petrilin } 449e72ebf5aSYevgeny Petrilin 4505a2cc190SJeff Kirsher for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 4515a2cc190SJeff Kirsher if (free < 0 && (table->refs[i] == 0)) { 4525a2cc190SJeff Kirsher free = i; 4535a2cc190SJeff Kirsher continue; 4545a2cc190SJeff Kirsher } 4555a2cc190SJeff Kirsher 4565a2cc190SJeff Kirsher if (table->refs[i] && 4575a2cc190SJeff Kirsher (vlan == (MLX4_VLAN_MASK & 4585a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) { 4595a2cc190SJeff Kirsher /* Vlan already registered, increase references count */ 4605a2cc190SJeff Kirsher *index = i; 4615a2cc190SJeff Kirsher ++table->refs[i]; 4625a2cc190SJeff Kirsher goto out; 4635a2cc190SJeff Kirsher } 4645a2cc190SJeff Kirsher } 4655a2cc190SJeff Kirsher 4665a2cc190SJeff Kirsher if (free < 0) { 4675a2cc190SJeff Kirsher err = -ENOMEM; 4685a2cc190SJeff Kirsher goto out; 4695a2cc190SJeff Kirsher } 4705a2cc190SJeff Kirsher 471ffe455adSEugenia Emantayev /* Register new VLAN */ 4725a2cc190SJeff Kirsher table->refs[free] = 1; 4735a2cc190SJeff Kirsher table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 4745a2cc190SJeff Kirsher 4755a2cc190SJeff Kirsher err = mlx4_set_port_vlan_table(dev, port, table->entries); 4765a2cc190SJeff Kirsher if (unlikely(err)) { 4775a2cc190SJeff Kirsher mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); 4785a2cc190SJeff Kirsher table->refs[free] = 0; 4795a2cc190SJeff Kirsher table->entries[free] = 0; 4805a2cc190SJeff Kirsher goto out; 4815a2cc190SJeff Kirsher } 4825a2cc190SJeff Kirsher 4835a2cc190SJeff Kirsher *index = free; 4845a2cc190SJeff Kirsher ++table->total; 4855a2cc190SJeff Kirsher out: 4865a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 4875a2cc190SJeff Kirsher return err; 4885a2cc190SJeff Kirsher } 489ffe455adSEugenia Emantayev 490ffe455adSEugenia Emantayev int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) 491ffe455adSEugenia Emantayev { 492ffe455adSEugenia Emantayev u64 out_param; 493ffe455adSEugenia Emantayev int err; 494ffe455adSEugenia Emantayev 495ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 496ffe455adSEugenia Emantayev set_param_l(&out_param, port); 497ffe455adSEugenia Emantayev err = mlx4_cmd_imm(dev, vlan, &out_param, RES_VLAN, 498ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES, 499ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 500ffe455adSEugenia Emantayev if (!err) 501ffe455adSEugenia Emantayev *index = get_param_l(&out_param); 502ffe455adSEugenia Emantayev 503ffe455adSEugenia Emantayev return err; 504ffe455adSEugenia Emantayev } 505ffe455adSEugenia Emantayev return __mlx4_register_vlan(dev, port, vlan, index); 506ffe455adSEugenia Emantayev } 5075a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_register_vlan); 5085a2cc190SJeff Kirsher 509ffe455adSEugenia Emantayev static void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index) 5105a2cc190SJeff Kirsher { 5115a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 5125a2cc190SJeff Kirsher 5135a2cc190SJeff Kirsher if (index < MLX4_VLAN_REGULAR) { 5145a2cc190SJeff Kirsher mlx4_warn(dev, "Trying to free special vlan index %d\n", index); 5155a2cc190SJeff Kirsher return; 5165a2cc190SJeff Kirsher } 5175a2cc190SJeff Kirsher 5185a2cc190SJeff Kirsher mutex_lock(&table->mutex); 5195a2cc190SJeff Kirsher if (!table->refs[index]) { 5205a2cc190SJeff Kirsher mlx4_warn(dev, "No vlan entry for index %d\n", index); 5215a2cc190SJeff Kirsher goto out; 5225a2cc190SJeff Kirsher } 5235a2cc190SJeff Kirsher if (--table->refs[index]) { 5245a2cc190SJeff Kirsher mlx4_dbg(dev, "Have more references for index %d," 5255a2cc190SJeff Kirsher "no need to modify vlan table\n", index); 5265a2cc190SJeff Kirsher goto out; 5275a2cc190SJeff Kirsher } 5285a2cc190SJeff Kirsher table->entries[index] = 0; 5295a2cc190SJeff Kirsher mlx4_set_port_vlan_table(dev, port, table->entries); 5305a2cc190SJeff Kirsher --table->total; 5315a2cc190SJeff Kirsher out: 5325a2cc190SJeff Kirsher mutex_unlock(&table->mutex); 5335a2cc190SJeff Kirsher } 534ffe455adSEugenia Emantayev 535ffe455adSEugenia Emantayev void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index) 536ffe455adSEugenia Emantayev { 537ffe455adSEugenia Emantayev u64 in_param; 538ffe455adSEugenia Emantayev int err; 539ffe455adSEugenia Emantayev 540ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) { 541ffe455adSEugenia Emantayev set_param_l(&in_param, port); 542ffe455adSEugenia Emantayev err = mlx4_cmd(dev, in_param, RES_VLAN, RES_OP_RESERVE_AND_MAP, 543ffe455adSEugenia Emantayev MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A, 544ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 545ffe455adSEugenia Emantayev if (!err) 546ffe455adSEugenia Emantayev mlx4_warn(dev, "Failed freeing vlan at index:%d\n", 547ffe455adSEugenia Emantayev index); 548ffe455adSEugenia Emantayev 549ffe455adSEugenia Emantayev return; 550ffe455adSEugenia Emantayev } 551ffe455adSEugenia Emantayev __mlx4_unregister_vlan(dev, port, index); 552ffe455adSEugenia Emantayev } 5535a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_vlan); 5545a2cc190SJeff Kirsher 5555a2cc190SJeff Kirsher int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) 5565a2cc190SJeff Kirsher { 5575a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *inmailbox, *outmailbox; 5585a2cc190SJeff Kirsher u8 *inbuf, *outbuf; 5595a2cc190SJeff Kirsher int err; 5605a2cc190SJeff Kirsher 5615a2cc190SJeff Kirsher inmailbox = mlx4_alloc_cmd_mailbox(dev); 5625a2cc190SJeff Kirsher if (IS_ERR(inmailbox)) 5635a2cc190SJeff Kirsher return PTR_ERR(inmailbox); 5645a2cc190SJeff Kirsher 5655a2cc190SJeff Kirsher outmailbox = mlx4_alloc_cmd_mailbox(dev); 5665a2cc190SJeff Kirsher if (IS_ERR(outmailbox)) { 5675a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 5685a2cc190SJeff Kirsher return PTR_ERR(outmailbox); 5695a2cc190SJeff Kirsher } 5705a2cc190SJeff Kirsher 5715a2cc190SJeff Kirsher inbuf = inmailbox->buf; 5725a2cc190SJeff Kirsher outbuf = outmailbox->buf; 5735a2cc190SJeff Kirsher memset(inbuf, 0, 256); 5745a2cc190SJeff Kirsher memset(outbuf, 0, 256); 5755a2cc190SJeff Kirsher inbuf[0] = 1; 5765a2cc190SJeff Kirsher inbuf[1] = 1; 5775a2cc190SJeff Kirsher inbuf[2] = 1; 5785a2cc190SJeff Kirsher inbuf[3] = 1; 5795a2cc190SJeff Kirsher *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015); 5805a2cc190SJeff Kirsher *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); 5815a2cc190SJeff Kirsher 5825a2cc190SJeff Kirsher err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, 583f9baff50SJack Morgenstein MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 584f9baff50SJack Morgenstein MLX4_CMD_NATIVE); 5855a2cc190SJeff Kirsher if (!err) 5865a2cc190SJeff Kirsher *caps = *(__be32 *) (outbuf + 84); 5875a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox); 5885a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, outmailbox); 5895a2cc190SJeff Kirsher return err; 5905a2cc190SJeff Kirsher } 5915a2cc190SJeff Kirsher 592ffe455adSEugenia Emantayev static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, 593ffe455adSEugenia Emantayev u8 op_mod, struct mlx4_cmd_mailbox *inbox) 594ffe455adSEugenia Emantayev { 595ffe455adSEugenia Emantayev struct mlx4_priv *priv = mlx4_priv(dev); 596ffe455adSEugenia Emantayev struct mlx4_port_info *port_info; 597ffe455adSEugenia Emantayev struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master; 598ffe455adSEugenia Emantayev struct mlx4_slave_state *slave_st = &master->slave_state[slave]; 599ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *qpn_context; 600ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *gen_context; 601ffe455adSEugenia Emantayev int reset_qkey_viols; 602ffe455adSEugenia Emantayev int port; 603ffe455adSEugenia Emantayev int is_eth; 604ffe455adSEugenia Emantayev u32 in_modifier; 605ffe455adSEugenia Emantayev u32 promisc; 606ffe455adSEugenia Emantayev u16 mtu, prev_mtu; 607ffe455adSEugenia Emantayev int err; 608ffe455adSEugenia Emantayev int i; 609ffe455adSEugenia Emantayev __be32 agg_cap_mask; 610ffe455adSEugenia Emantayev __be32 slave_cap_mask; 611ffe455adSEugenia Emantayev __be32 new_cap_mask; 612ffe455adSEugenia Emantayev 613ffe455adSEugenia Emantayev port = in_mod & 0xff; 614ffe455adSEugenia Emantayev in_modifier = in_mod >> 8; 615ffe455adSEugenia Emantayev is_eth = op_mod; 616ffe455adSEugenia Emantayev port_info = &priv->port[port]; 617ffe455adSEugenia Emantayev 618ffe455adSEugenia Emantayev /* Slaves cannot perform SET_PORT operations except changing MTU */ 619ffe455adSEugenia Emantayev if (is_eth) { 620ffe455adSEugenia Emantayev if (slave != dev->caps.function && 621ffe455adSEugenia Emantayev in_modifier != MLX4_SET_PORT_GENERAL) { 622ffe455adSEugenia Emantayev mlx4_warn(dev, "denying SET_PORT for slave:%d\n", 623ffe455adSEugenia Emantayev slave); 624ffe455adSEugenia Emantayev return -EINVAL; 625ffe455adSEugenia Emantayev } 626ffe455adSEugenia Emantayev switch (in_modifier) { 627ffe455adSEugenia Emantayev case MLX4_SET_PORT_RQP_CALC: 628ffe455adSEugenia Emantayev qpn_context = inbox->buf; 629ffe455adSEugenia Emantayev qpn_context->base_qpn = 630ffe455adSEugenia Emantayev cpu_to_be32(port_info->base_qpn); 631ffe455adSEugenia Emantayev qpn_context->n_mac = 0x7; 632ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->promisc) >> 633ffe455adSEugenia Emantayev SET_PORT_PROMISC_SHIFT; 634ffe455adSEugenia Emantayev qpn_context->promisc = cpu_to_be32( 635ffe455adSEugenia Emantayev promisc << SET_PORT_PROMISC_SHIFT | 636ffe455adSEugenia Emantayev port_info->base_qpn); 637ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->mcast) >> 638ffe455adSEugenia Emantayev SET_PORT_MC_PROMISC_SHIFT; 639ffe455adSEugenia Emantayev qpn_context->mcast = cpu_to_be32( 640ffe455adSEugenia Emantayev promisc << SET_PORT_MC_PROMISC_SHIFT | 641ffe455adSEugenia Emantayev port_info->base_qpn); 642ffe455adSEugenia Emantayev break; 643ffe455adSEugenia Emantayev case MLX4_SET_PORT_GENERAL: 644ffe455adSEugenia Emantayev gen_context = inbox->buf; 645ffe455adSEugenia Emantayev /* Mtu is configured as the max MTU among all the 646ffe455adSEugenia Emantayev * the functions on the port. */ 647ffe455adSEugenia Emantayev mtu = be16_to_cpu(gen_context->mtu); 648ffe455adSEugenia Emantayev mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port]); 649ffe455adSEugenia Emantayev prev_mtu = slave_st->mtu[port]; 650ffe455adSEugenia Emantayev slave_st->mtu[port] = mtu; 651ffe455adSEugenia Emantayev if (mtu > master->max_mtu[port]) 652ffe455adSEugenia Emantayev master->max_mtu[port] = mtu; 653ffe455adSEugenia Emantayev if (mtu < prev_mtu && prev_mtu == 654ffe455adSEugenia Emantayev master->max_mtu[port]) { 655ffe455adSEugenia Emantayev slave_st->mtu[port] = mtu; 656ffe455adSEugenia Emantayev master->max_mtu[port] = mtu; 657ffe455adSEugenia Emantayev for (i = 0; i < dev->num_slaves; i++) { 658ffe455adSEugenia Emantayev master->max_mtu[port] = 659ffe455adSEugenia Emantayev max(master->max_mtu[port], 660ffe455adSEugenia Emantayev master->slave_state[i].mtu[port]); 661ffe455adSEugenia Emantayev } 662ffe455adSEugenia Emantayev } 663ffe455adSEugenia Emantayev 664ffe455adSEugenia Emantayev gen_context->mtu = cpu_to_be16(master->max_mtu[port]); 665ffe455adSEugenia Emantayev break; 666ffe455adSEugenia Emantayev } 667ffe455adSEugenia Emantayev return mlx4_cmd(dev, inbox->dma, in_mod, op_mod, 668ffe455adSEugenia Emantayev MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, 669ffe455adSEugenia Emantayev MLX4_CMD_NATIVE); 670ffe455adSEugenia Emantayev } 671ffe455adSEugenia Emantayev 672ffe455adSEugenia Emantayev /* For IB, we only consider: 673ffe455adSEugenia Emantayev * - The capability mask, which is set to the aggregate of all 674ffe455adSEugenia Emantayev * slave function capabilities 675ffe455adSEugenia Emantayev * - The QKey violatin counter - reset according to each request. 676ffe455adSEugenia Emantayev */ 677ffe455adSEugenia Emantayev 678ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 679ffe455adSEugenia Emantayev reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40; 680ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[2]; 681ffe455adSEugenia Emantayev } else { 682ffe455adSEugenia Emantayev reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1; 683ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[1]; 684ffe455adSEugenia Emantayev } 685ffe455adSEugenia Emantayev 686ffe455adSEugenia Emantayev agg_cap_mask = 0; 687ffe455adSEugenia Emantayev slave_cap_mask = 688ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port]; 689ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask; 690ffe455adSEugenia Emantayev for (i = 0; i < dev->num_slaves; i++) 691ffe455adSEugenia Emantayev agg_cap_mask |= 692ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[i].ib_cap_mask[port]; 693ffe455adSEugenia Emantayev 694ffe455adSEugenia Emantayev /* only clear mailbox for guests. Master may be setting 695ffe455adSEugenia Emantayev * MTU or PKEY table size 696ffe455adSEugenia Emantayev */ 697ffe455adSEugenia Emantayev if (slave != dev->caps.function) 698ffe455adSEugenia Emantayev memset(inbox->buf, 0, 256); 699ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { 700edc4a67eSJack Morgenstein *(u8 *) inbox->buf |= !!reset_qkey_viols << 6; 701ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[2] = agg_cap_mask; 702ffe455adSEugenia Emantayev } else { 703edc4a67eSJack Morgenstein ((u8 *) inbox->buf)[3] |= !!reset_qkey_viols; 704ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[1] = agg_cap_mask; 705ffe455adSEugenia Emantayev } 706ffe455adSEugenia Emantayev 707ffe455adSEugenia Emantayev err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT, 708ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 709ffe455adSEugenia Emantayev if (err) 710ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = 711ffe455adSEugenia Emantayev slave_cap_mask; 712ffe455adSEugenia Emantayev return err; 713ffe455adSEugenia Emantayev } 714ffe455adSEugenia Emantayev 715ffe455adSEugenia Emantayev int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, 716ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 717ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 718ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 719ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 720ffe455adSEugenia Emantayev { 721ffe455adSEugenia Emantayev return mlx4_common_set_port(dev, slave, vhcr->in_modifier, 722ffe455adSEugenia Emantayev vhcr->op_modifier, inbox); 723ffe455adSEugenia Emantayev } 724ffe455adSEugenia Emantayev 725096335b3SOr Gerlitz /* bit locations for set port command with zero op modifier */ 726096335b3SOr Gerlitz enum { 727096335b3SOr Gerlitz MLX4_SET_PORT_VL_CAP = 4, /* bits 7:4 */ 728096335b3SOr Gerlitz MLX4_SET_PORT_MTU_CAP = 12, /* bits 15:12 */ 729096335b3SOr Gerlitz MLX4_CHANGE_PORT_VL_CAP = 21, 730096335b3SOr Gerlitz MLX4_CHANGE_PORT_MTU_CAP = 22, 731096335b3SOr Gerlitz }; 732096335b3SOr Gerlitz 7335a2cc190SJeff Kirsher int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port) 7345a2cc190SJeff Kirsher { 7355a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 736096335b3SOr Gerlitz int err, vl_cap; 7375a2cc190SJeff Kirsher 7385a2cc190SJeff Kirsher if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) 7395a2cc190SJeff Kirsher return 0; 7405a2cc190SJeff Kirsher 7415a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev); 7425a2cc190SJeff Kirsher if (IS_ERR(mailbox)) 7435a2cc190SJeff Kirsher return PTR_ERR(mailbox); 7445a2cc190SJeff Kirsher 7455a2cc190SJeff Kirsher memset(mailbox->buf, 0, 256); 7465a2cc190SJeff Kirsher 7475a2cc190SJeff Kirsher ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; 748096335b3SOr Gerlitz 749096335b3SOr Gerlitz /* IB VL CAP enum isn't used by the firmware, just numerical values */ 750096335b3SOr Gerlitz for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) { 751096335b3SOr Gerlitz ((__be32 *) mailbox->buf)[0] = cpu_to_be32( 752096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_MTU_CAP) | 753096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_VL_CAP) | 754096335b3SOr Gerlitz (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) | 755096335b3SOr Gerlitz (vl_cap << MLX4_SET_PORT_VL_CAP)); 7565a2cc190SJeff Kirsher err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT, 757f9baff50SJack Morgenstein MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 758096335b3SOr Gerlitz if (err != -ENOMEM) 759096335b3SOr Gerlitz break; 760096335b3SOr Gerlitz } 7615a2cc190SJeff Kirsher 7625a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox); 7635a2cc190SJeff Kirsher return err; 7645a2cc190SJeff Kirsher } 765ffe455adSEugenia Emantayev 766cb9ffb76SJoerg Roedel int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, 767ffe455adSEugenia Emantayev u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx) 768ffe455adSEugenia Emantayev { 769ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 770ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *context; 771ffe455adSEugenia Emantayev int err; 772ffe455adSEugenia Emantayev u32 in_mod; 773ffe455adSEugenia Emantayev 774ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 775ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 776ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 777ffe455adSEugenia Emantayev context = mailbox->buf; 778ffe455adSEugenia Emantayev memset(context, 0, sizeof *context); 779ffe455adSEugenia Emantayev 780ffe455adSEugenia Emantayev context->flags = SET_PORT_GEN_ALL_VALID; 781ffe455adSEugenia Emantayev context->mtu = cpu_to_be16(mtu); 782ffe455adSEugenia Emantayev context->pptx = (pptx * (!pfctx)) << 7; 783ffe455adSEugenia Emantayev context->pfctx = pfctx; 784ffe455adSEugenia Emantayev context->pprx = (pprx * (!pfcrx)) << 7; 785ffe455adSEugenia Emantayev context->pfcrx = pfcrx; 786ffe455adSEugenia Emantayev 787ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_GENERAL << 8 | port; 788ffe455adSEugenia Emantayev err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 789ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 790ffe455adSEugenia Emantayev 791ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 792ffe455adSEugenia Emantayev return err; 793ffe455adSEugenia Emantayev } 794ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_general); 795ffe455adSEugenia Emantayev 796cb9ffb76SJoerg Roedel int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, 797ffe455adSEugenia Emantayev u8 promisc) 798ffe455adSEugenia Emantayev { 799ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox; 800ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *context; 801ffe455adSEugenia Emantayev int err; 802ffe455adSEugenia Emantayev u32 in_mod; 803ffe455adSEugenia Emantayev u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ? 804ffe455adSEugenia Emantayev MCAST_DIRECT : MCAST_DEFAULT; 805ffe455adSEugenia Emantayev 806c96d97f4SHadar Hen Zion if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) 807ffe455adSEugenia Emantayev return 0; 808ffe455adSEugenia Emantayev 809ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev); 810ffe455adSEugenia Emantayev if (IS_ERR(mailbox)) 811ffe455adSEugenia Emantayev return PTR_ERR(mailbox); 812ffe455adSEugenia Emantayev context = mailbox->buf; 813ffe455adSEugenia Emantayev memset(context, 0, sizeof *context); 814ffe455adSEugenia Emantayev 815ffe455adSEugenia Emantayev context->base_qpn = cpu_to_be32(base_qpn); 816ffe455adSEugenia Emantayev context->n_mac = dev->caps.log_num_macs; 817ffe455adSEugenia Emantayev context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | 818ffe455adSEugenia Emantayev base_qpn); 819ffe455adSEugenia Emantayev context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | 820ffe455adSEugenia Emantayev base_qpn); 821ffe455adSEugenia Emantayev context->intra_no_vlan = 0; 822ffe455adSEugenia Emantayev context->no_vlan = MLX4_NO_VLAN_IDX; 823ffe455adSEugenia Emantayev context->intra_vlan_miss = 0; 824ffe455adSEugenia Emantayev context->vlan_miss = MLX4_VLAN_MISS_IDX; 825ffe455adSEugenia Emantayev 826ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port; 827ffe455adSEugenia Emantayev err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 828ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); 829ffe455adSEugenia Emantayev 830ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox); 831ffe455adSEugenia Emantayev return err; 832ffe455adSEugenia Emantayev } 833ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); 834ffe455adSEugenia Emantayev 835e5395e92SAmir Vadai int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc) 836e5395e92SAmir Vadai { 837e5395e92SAmir Vadai struct mlx4_cmd_mailbox *mailbox; 838e5395e92SAmir Vadai struct mlx4_set_port_prio2tc_context *context; 839e5395e92SAmir Vadai int err; 840e5395e92SAmir Vadai u32 in_mod; 841e5395e92SAmir Vadai int i; 842e5395e92SAmir Vadai 843e5395e92SAmir Vadai mailbox = mlx4_alloc_cmd_mailbox(dev); 844e5395e92SAmir Vadai if (IS_ERR(mailbox)) 845e5395e92SAmir Vadai return PTR_ERR(mailbox); 846e5395e92SAmir Vadai context = mailbox->buf; 847e5395e92SAmir Vadai memset(context, 0, sizeof *context); 848e5395e92SAmir Vadai 849e5395e92SAmir Vadai for (i = 0; i < MLX4_NUM_UP; i += 2) 850e5395e92SAmir Vadai context->prio2tc[i >> 1] = prio2tc[i] << 4 | prio2tc[i + 1]; 851e5395e92SAmir Vadai 852e5395e92SAmir Vadai in_mod = MLX4_SET_PORT_PRIO2TC << 8 | port; 853e5395e92SAmir Vadai err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 854e5395e92SAmir Vadai MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 855e5395e92SAmir Vadai 856e5395e92SAmir Vadai mlx4_free_cmd_mailbox(dev, mailbox); 857e5395e92SAmir Vadai return err; 858e5395e92SAmir Vadai } 859e5395e92SAmir Vadai EXPORT_SYMBOL(mlx4_SET_PORT_PRIO2TC); 860e5395e92SAmir Vadai 861e5395e92SAmir Vadai int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, 862e5395e92SAmir Vadai u8 *pg, u16 *ratelimit) 863e5395e92SAmir Vadai { 864e5395e92SAmir Vadai struct mlx4_cmd_mailbox *mailbox; 865e5395e92SAmir Vadai struct mlx4_set_port_scheduler_context *context; 866e5395e92SAmir Vadai int err; 867e5395e92SAmir Vadai u32 in_mod; 868e5395e92SAmir Vadai int i; 869e5395e92SAmir Vadai 870e5395e92SAmir Vadai mailbox = mlx4_alloc_cmd_mailbox(dev); 871e5395e92SAmir Vadai if (IS_ERR(mailbox)) 872e5395e92SAmir Vadai return PTR_ERR(mailbox); 873e5395e92SAmir Vadai context = mailbox->buf; 874e5395e92SAmir Vadai memset(context, 0, sizeof *context); 875e5395e92SAmir Vadai 876e5395e92SAmir Vadai for (i = 0; i < MLX4_NUM_TC; i++) { 877e5395e92SAmir Vadai struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i]; 878e5395e92SAmir Vadai u16 r = ratelimit && ratelimit[i] ? ratelimit[i] : 879e5395e92SAmir Vadai MLX4_RATELIMIT_DEFAULT; 880e5395e92SAmir Vadai 881e5395e92SAmir Vadai tc->pg = htons(pg[i]); 882e5395e92SAmir Vadai tc->bw_precentage = htons(tc_tx_bw[i]); 883e5395e92SAmir Vadai 884e5395e92SAmir Vadai tc->max_bw_units = htons(MLX4_RATELIMIT_UNITS); 885e5395e92SAmir Vadai tc->max_bw_value = htons(r); 886e5395e92SAmir Vadai } 887e5395e92SAmir Vadai 888e5395e92SAmir Vadai in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port; 889e5395e92SAmir Vadai err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 890e5395e92SAmir Vadai MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); 891e5395e92SAmir Vadai 892e5395e92SAmir Vadai mlx4_free_cmd_mailbox(dev, mailbox); 893e5395e92SAmir Vadai return err; 894e5395e92SAmir Vadai } 895e5395e92SAmir Vadai EXPORT_SYMBOL(mlx4_SET_PORT_SCHEDULER); 896e5395e92SAmir Vadai 897ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, 898ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 899ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 900ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 901ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 902ffe455adSEugenia Emantayev { 903ffe455adSEugenia Emantayev int err = 0; 904ffe455adSEugenia Emantayev 905ffe455adSEugenia Emantayev return err; 906ffe455adSEugenia Emantayev } 907ffe455adSEugenia Emantayev 908ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, 909ffe455adSEugenia Emantayev u64 mac, u64 clear, u8 mode) 910ffe455adSEugenia Emantayev { 911ffe455adSEugenia Emantayev return mlx4_cmd(dev, (mac | (clear << 63)), port, mode, 912ffe455adSEugenia Emantayev MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B, 913ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED); 914ffe455adSEugenia Emantayev } 915ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR); 916ffe455adSEugenia Emantayev 917ffe455adSEugenia Emantayev int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave, 918ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 919ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 920ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 921ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 922ffe455adSEugenia Emantayev { 923ffe455adSEugenia Emantayev int err = 0; 924ffe455adSEugenia Emantayev 925ffe455adSEugenia Emantayev return err; 926ffe455adSEugenia Emantayev } 927ffe455adSEugenia Emantayev 928ffe455adSEugenia Emantayev int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave, 929ffe455adSEugenia Emantayev u32 in_mod, struct mlx4_cmd_mailbox *outbox) 930ffe455adSEugenia Emantayev { 931ffe455adSEugenia Emantayev return mlx4_cmd_box(dev, 0, outbox->dma, in_mod, 0, 932ffe455adSEugenia Emantayev MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B, 933ffe455adSEugenia Emantayev MLX4_CMD_NATIVE); 934ffe455adSEugenia Emantayev } 935ffe455adSEugenia Emantayev 936ffe455adSEugenia Emantayev int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave, 937ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr, 938ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox, 939ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox, 940ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd) 941ffe455adSEugenia Emantayev { 94235fb9afbSEugenia Emantayev if (slave != dev->caps.function) 94335fb9afbSEugenia Emantayev return 0; 944ffe455adSEugenia Emantayev return mlx4_common_dump_eth_stats(dev, slave, 945ffe455adSEugenia Emantayev vhcr->in_modifier, outbox); 946ffe455adSEugenia Emantayev } 94793ece0c1SEugenia Emantayev 94893ece0c1SEugenia Emantayev void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap) 94993ece0c1SEugenia Emantayev { 95093ece0c1SEugenia Emantayev if (!mlx4_is_mfunc(dev)) { 95193ece0c1SEugenia Emantayev *stats_bitmap = 0; 95293ece0c1SEugenia Emantayev return; 95393ece0c1SEugenia Emantayev } 95493ece0c1SEugenia Emantayev 95593ece0c1SEugenia Emantayev *stats_bitmap = (MLX4_STATS_TRAFFIC_COUNTERS_MASK | 95693ece0c1SEugenia Emantayev MLX4_STATS_TRAFFIC_DROPS_MASK | 95793ece0c1SEugenia Emantayev MLX4_STATS_PORT_COUNTERS_MASK); 95893ece0c1SEugenia Emantayev 95993ece0c1SEugenia Emantayev if (mlx4_is_master(dev)) 96093ece0c1SEugenia Emantayev *stats_bitmap |= MLX4_STATS_ERROR_COUNTERS_MASK; 96193ece0c1SEugenia Emantayev } 96293ece0c1SEugenia Emantayev EXPORT_SYMBOL(mlx4_set_stats_bitmap); 963