15a2cc190SJeff Kirsher /*
25a2cc190SJeff Kirsher * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
35a2cc190SJeff Kirsher *
45a2cc190SJeff Kirsher * This software is available to you under a choice of one of two
55a2cc190SJeff Kirsher * licenses. You may choose to be licensed under the terms of the GNU
65a2cc190SJeff Kirsher * General Public License (GPL) Version 2, available from the file
75a2cc190SJeff Kirsher * COPYING in the main directory of this source tree, or the
85a2cc190SJeff Kirsher * OpenIB.org BSD license below:
95a2cc190SJeff Kirsher *
105a2cc190SJeff Kirsher * Redistribution and use in source and binary forms, with or
115a2cc190SJeff Kirsher * without modification, are permitted provided that the following
125a2cc190SJeff Kirsher * conditions are met:
135a2cc190SJeff Kirsher *
145a2cc190SJeff Kirsher * - Redistributions of source code must retain the above
155a2cc190SJeff Kirsher * copyright notice, this list of conditions and the following
165a2cc190SJeff Kirsher * disclaimer.
175a2cc190SJeff Kirsher *
185a2cc190SJeff Kirsher * - Redistributions in binary form must reproduce the above
195a2cc190SJeff Kirsher * copyright notice, this list of conditions and the following
205a2cc190SJeff Kirsher * disclaimer in the documentation and/or other materials
215a2cc190SJeff Kirsher * provided with the distribution.
225a2cc190SJeff Kirsher *
235a2cc190SJeff Kirsher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
245a2cc190SJeff Kirsher * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
255a2cc190SJeff Kirsher * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
265a2cc190SJeff Kirsher * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
275a2cc190SJeff Kirsher * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
285a2cc190SJeff Kirsher * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
295a2cc190SJeff Kirsher * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
305a2cc190SJeff Kirsher * SOFTWARE.
315a2cc190SJeff Kirsher */
325a2cc190SJeff Kirsher
335a2cc190SJeff Kirsher #include <linux/errno.h>
345a2cc190SJeff Kirsher #include <linux/if_ether.h>
35c59fec20SEugenia Emantayev #include <linux/if_vlan.h>
36ee40fa06SPaul Gortmaker #include <linux/export.h>
375a2cc190SJeff Kirsher
385a2cc190SJeff Kirsher #include <linux/mlx4/cmd.h>
395a2cc190SJeff Kirsher
405a2cc190SJeff Kirsher #include "mlx4.h"
41b4b6e842SEran Ben Elisha #include "mlx4_stats.h"
425a2cc190SJeff Kirsher
435a2cc190SJeff Kirsher #define MLX4_MAC_VALID (1ull << 63)
445a2cc190SJeff Kirsher
455a2cc190SJeff Kirsher #define MLX4_VLAN_VALID (1u << 31)
465a2cc190SJeff Kirsher #define MLX4_VLAN_MASK 0xfff
475a2cc190SJeff Kirsher
4878500b8cSMuhammad Mahajna #define MLX4_STATS_TRAFFIC_COUNTERS_MASK 0xfULL
4978500b8cSMuhammad Mahajna #define MLX4_STATS_TRAFFIC_DROPS_MASK 0xc0ULL
5078500b8cSMuhammad Mahajna #define MLX4_STATS_ERROR_COUNTERS_MASK 0x1ffc30ULL
5178500b8cSMuhammad Mahajna #define MLX4_STATS_PORT_COUNTERS_MASK 0x1fe00000ULL
5278500b8cSMuhammad Mahajna
5340fb4fc1SShaker Daibes #define MLX4_FLAG2_V_IGNORE_FCS_MASK BIT(1)
5440fb4fc1SShaker Daibes #define MLX4_FLAG2_V_USER_MTU_MASK BIT(5)
55be599603SMoshe Shemesh #define MLX4_FLAG2_V_USER_MAC_MASK BIT(6)
56bf1f9396SShaker Daibes #define MLX4_FLAG_V_MTU_MASK BIT(0)
571f8176f7SShaker Daibes #define MLX4_FLAG_V_PPRX_MASK BIT(1)
581f8176f7SShaker Daibes #define MLX4_FLAG_V_PPTX_MASK BIT(2)
5978500b8cSMuhammad Mahajna #define MLX4_IGNORE_FCS_MASK 0x1
60564ed9b1STariq Toukan #define MLX4_TC_MAX_NUMBER 8
6178500b8cSMuhammad Mahajna
mlx4_init_mac_table(struct mlx4_dev * dev,struct mlx4_mac_table * table)625a2cc190SJeff Kirsher void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table)
635a2cc190SJeff Kirsher {
645a2cc190SJeff Kirsher int i;
655a2cc190SJeff Kirsher
665a2cc190SJeff Kirsher mutex_init(&table->mutex);
675a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
685a2cc190SJeff Kirsher table->entries[i] = 0;
695a2cc190SJeff Kirsher table->refs[i] = 0;
705f61385dSMoni Shoua table->is_dup[i] = false;
715a2cc190SJeff Kirsher }
725a2cc190SJeff Kirsher table->max = 1 << dev->caps.log_num_macs;
735a2cc190SJeff Kirsher table->total = 0;
745a2cc190SJeff Kirsher }
755a2cc190SJeff Kirsher
mlx4_init_vlan_table(struct mlx4_dev * dev,struct mlx4_vlan_table * table)765a2cc190SJeff Kirsher void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
775a2cc190SJeff Kirsher {
785a2cc190SJeff Kirsher int i;
795a2cc190SJeff Kirsher
805a2cc190SJeff Kirsher mutex_init(&table->mutex);
815a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
825a2cc190SJeff Kirsher table->entries[i] = 0;
835a2cc190SJeff Kirsher table->refs[i] = 0;
845f61385dSMoni Shoua table->is_dup[i] = false;
855a2cc190SJeff Kirsher }
86e72ebf5aSYevgeny Petrilin table->max = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR;
875a2cc190SJeff Kirsher table->total = 0;
885a2cc190SJeff Kirsher }
895a2cc190SJeff Kirsher
mlx4_init_roce_gid_table(struct mlx4_dev * dev,struct mlx4_roce_gid_table * table)90111c6094SJack Morgenstein void mlx4_init_roce_gid_table(struct mlx4_dev *dev,
91111c6094SJack Morgenstein struct mlx4_roce_gid_table *table)
92111c6094SJack Morgenstein {
93111c6094SJack Morgenstein int i;
94111c6094SJack Morgenstein
95111c6094SJack Morgenstein mutex_init(&table->mutex);
96111c6094SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++)
97111c6094SJack Morgenstein memset(table->roce_gids[i].raw, 0, MLX4_ROCE_GID_ENTRY_SIZE);
98111c6094SJack Morgenstein }
99111c6094SJack Morgenstein
validate_index(struct mlx4_dev * dev,struct mlx4_mac_table * table,int index)1005a2cc190SJeff Kirsher static int validate_index(struct mlx4_dev *dev,
1015a2cc190SJeff Kirsher struct mlx4_mac_table *table, int index)
1025a2cc190SJeff Kirsher {
1035a2cc190SJeff Kirsher int err = 0;
1045a2cc190SJeff Kirsher
1055a2cc190SJeff Kirsher if (index < 0 || index >= table->max || !table->entries[index]) {
1065a2cc190SJeff Kirsher mlx4_warn(dev, "No valid Mac entry for the given index\n");
1075a2cc190SJeff Kirsher err = -EINVAL;
1085a2cc190SJeff Kirsher }
1095a2cc190SJeff Kirsher return err;
1105a2cc190SJeff Kirsher }
1115a2cc190SJeff Kirsher
find_index(struct mlx4_dev * dev,struct mlx4_mac_table * table,u64 mac)1125a2cc190SJeff Kirsher static int find_index(struct mlx4_dev *dev,
1135a2cc190SJeff Kirsher struct mlx4_mac_table *table, u64 mac)
1145a2cc190SJeff Kirsher {
1155a2cc190SJeff Kirsher int i;
116ffe455adSEugenia Emantayev
1175a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
118f4fd40b2SJack Morgenstein if (table->refs[i] &&
119f4fd40b2SJack Morgenstein (MLX4_MAC_MASK & mac) ==
120ffe455adSEugenia Emantayev (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))
1215a2cc190SJeff Kirsher return i;
1225a2cc190SJeff Kirsher }
1235a2cc190SJeff Kirsher /* Mac not found */
1245a2cc190SJeff Kirsher return -EINVAL;
1255a2cc190SJeff Kirsher }
1265a2cc190SJeff Kirsher
mlx4_set_port_mac_table(struct mlx4_dev * dev,u8 port,__be64 * entries)127ffe455adSEugenia Emantayev static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
128ffe455adSEugenia Emantayev __be64 *entries)
129ffe455adSEugenia Emantayev {
130ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox;
131ffe455adSEugenia Emantayev u32 in_mod;
132ffe455adSEugenia Emantayev int err;
133ffe455adSEugenia Emantayev
134ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev);
135ffe455adSEugenia Emantayev if (IS_ERR(mailbox))
136ffe455adSEugenia Emantayev return PTR_ERR(mailbox);
137ffe455adSEugenia Emantayev
138ffe455adSEugenia Emantayev memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE);
139ffe455adSEugenia Emantayev
140ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port;
141ffe455adSEugenia Emantayev
142a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
143a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
144a130b590SIdo Shamay MLX4_CMD_NATIVE);
145ffe455adSEugenia Emantayev
146ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox);
147ffe455adSEugenia Emantayev return err;
148ffe455adSEugenia Emantayev }
149ffe455adSEugenia Emantayev
mlx4_find_cached_mac(struct mlx4_dev * dev,u8 port,u64 mac,int * idx)150297e0dadSMoni Shoua int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx)
151297e0dadSMoni Shoua {
152297e0dadSMoni Shoua struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
153297e0dadSMoni Shoua struct mlx4_mac_table *table = &info->mac_table;
154297e0dadSMoni Shoua int i;
155297e0dadSMoni Shoua
156297e0dadSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
157297e0dadSMoni Shoua if (!table->refs[i])
158297e0dadSMoni Shoua continue;
159297e0dadSMoni Shoua
160297e0dadSMoni Shoua if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
161297e0dadSMoni Shoua *idx = i;
162297e0dadSMoni Shoua return 0;
163297e0dadSMoni Shoua }
164297e0dadSMoni Shoua }
165297e0dadSMoni Shoua
166297e0dadSMoni Shoua return -ENOENT;
167297e0dadSMoni Shoua }
168297e0dadSMoni Shoua EXPORT_SYMBOL_GPL(mlx4_find_cached_mac);
169297e0dadSMoni Shoua
mlx4_need_mf_bond(struct mlx4_dev * dev)1705f61385dSMoni Shoua static bool mlx4_need_mf_bond(struct mlx4_dev *dev)
1715f61385dSMoni Shoua {
1725f61385dSMoni Shoua int i, num_eth_ports = 0;
1735f61385dSMoni Shoua
1745f61385dSMoni Shoua if (!mlx4_is_mfunc(dev))
1755f61385dSMoni Shoua return false;
1765f61385dSMoni Shoua mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
1775f61385dSMoni Shoua ++num_eth_ports;
1785f61385dSMoni Shoua
1795f61385dSMoni Shoua return (num_eth_ports == 2) ? true : false;
1805f61385dSMoni Shoua }
1815f61385dSMoni Shoua
__mlx4_register_mac(struct mlx4_dev * dev,u8 port,u64 mac)182ffe455adSEugenia Emantayev int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
183ffe455adSEugenia Emantayev {
184ffe455adSEugenia Emantayev struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
185ffe455adSEugenia Emantayev struct mlx4_mac_table *table = &info->mac_table;
186ffe455adSEugenia Emantayev int i, err = 0;
187ffe455adSEugenia Emantayev int free = -1;
1885f61385dSMoni Shoua int free_for_dup = -1;
1895f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev);
1905f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1;
1915f61385dSMoni Shoua struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
1925f61385dSMoni Shoua bool need_mf_bond = mlx4_need_mf_bond(dev);
1935f61385dSMoni Shoua bool can_mf_bond = true;
194ffe455adSEugenia Emantayev
1955f61385dSMoni Shoua mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d %s duplicate\n",
1965f61385dSMoni Shoua (unsigned long long)mac, port,
1975f61385dSMoni Shoua dup ? "with" : "without");
198ffe455adSEugenia Emantayev
1995f61385dSMoni Shoua if (need_mf_bond) {
2005f61385dSMoni Shoua if (port == 1) {
201ffe455adSEugenia Emantayev mutex_lock(&table->mutex);
20203a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
2035f61385dSMoni Shoua } else {
2045f61385dSMoni Shoua mutex_lock(&dup_table->mutex);
20503a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
2065f61385dSMoni Shoua }
2075f61385dSMoni Shoua } else {
2085f61385dSMoni Shoua mutex_lock(&table->mutex);
2095f61385dSMoni Shoua }
2105f61385dSMoni Shoua
2115f61385dSMoni Shoua if (need_mf_bond) {
2125f61385dSMoni Shoua int index_at_port = -1;
2135f61385dSMoni Shoua int index_at_dup_port = -1;
2145f61385dSMoni Shoua
2155f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
2165f61385dSMoni Shoua if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))))
2175f61385dSMoni Shoua index_at_port = i;
2185f61385dSMoni Shoua if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]))))
2195f61385dSMoni Shoua index_at_dup_port = i;
2205f61385dSMoni Shoua }
2215f61385dSMoni Shoua
2225f61385dSMoni Shoua /* check that same mac is not in the tables at different indices */
2235f61385dSMoni Shoua if ((index_at_port != index_at_dup_port) &&
2245f61385dSMoni Shoua (index_at_port >= 0) &&
2255f61385dSMoni Shoua (index_at_dup_port >= 0))
2265f61385dSMoni Shoua can_mf_bond = false;
2275f61385dSMoni Shoua
2285f61385dSMoni Shoua /* If the mac is already in the primary table, the slot must be
2295f61385dSMoni Shoua * available in the duplicate table as well.
2305f61385dSMoni Shoua */
2315f61385dSMoni Shoua if (index_at_port >= 0 && index_at_dup_port < 0 &&
2325f61385dSMoni Shoua dup_table->refs[index_at_port]) {
2335f61385dSMoni Shoua can_mf_bond = false;
2345f61385dSMoni Shoua }
2355f61385dSMoni Shoua /* If the mac is already in the duplicate table, check that the
2365f61385dSMoni Shoua * corresponding index is not occupied in the primary table, or
2375f61385dSMoni Shoua * the primary table already contains the mac at the same index.
2385f61385dSMoni Shoua * Otherwise, you cannot bond (primary contains a different mac
2395f61385dSMoni Shoua * at that index).
2405f61385dSMoni Shoua */
2415f61385dSMoni Shoua if (index_at_dup_port >= 0) {
2425f61385dSMoni Shoua if (!table->refs[index_at_dup_port] ||
2435f61385dSMoni Shoua ((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[index_at_dup_port]))))
2445f61385dSMoni Shoua free_for_dup = index_at_dup_port;
2455f61385dSMoni Shoua else
2465f61385dSMoni Shoua can_mf_bond = false;
2475f61385dSMoni Shoua }
2485f61385dSMoni Shoua }
2495f61385dSMoni Shoua
250ffe455adSEugenia Emantayev for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
251f4fd40b2SJack Morgenstein if (!table->refs[i]) {
252f4fd40b2SJack Morgenstein if (free < 0)
253ffe455adSEugenia Emantayev free = i;
2545f61385dSMoni Shoua if (free_for_dup < 0 && need_mf_bond && can_mf_bond) {
2555f61385dSMoni Shoua if (!dup_table->refs[i])
2565f61385dSMoni Shoua free_for_dup = i;
2575f61385dSMoni Shoua }
258ffe455adSEugenia Emantayev continue;
259ffe455adSEugenia Emantayev }
260ffe455adSEugenia Emantayev
261f4fd40b2SJack Morgenstein if ((MLX4_MAC_MASK & mac) ==
262f4fd40b2SJack Morgenstein (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
2636ce71acdSRony Efraim /* MAC already registered, increment ref count */
2646ce71acdSRony Efraim err = i;
2656ce71acdSRony Efraim ++table->refs[i];
2665f61385dSMoni Shoua if (dup) {
2675f61385dSMoni Shoua u64 dup_mac = MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]);
2685f61385dSMoni Shoua
2695f61385dSMoni Shoua if (dup_mac != mac || !dup_table->is_dup[i]) {
2705f61385dSMoni Shoua mlx4_warn(dev, "register mac: expect duplicate mac 0x%llx on port %d index %d\n",
2715f61385dSMoni Shoua mac, dup_port, i);
2725f61385dSMoni Shoua }
2735f61385dSMoni Shoua }
274ffe455adSEugenia Emantayev goto out;
275ffe455adSEugenia Emantayev }
276ffe455adSEugenia Emantayev }
277ffe455adSEugenia Emantayev
2785f61385dSMoni Shoua if (need_mf_bond && (free_for_dup < 0)) {
2795f61385dSMoni Shoua if (dup) {
2805f61385dSMoni Shoua mlx4_warn(dev, "Fail to allocate duplicate MAC table entry\n");
2815f61385dSMoni Shoua mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n");
2825f61385dSMoni Shoua dup = false;
2835f61385dSMoni Shoua }
2845f61385dSMoni Shoua can_mf_bond = false;
2855f61385dSMoni Shoua }
2865f61385dSMoni Shoua
2875f61385dSMoni Shoua if (need_mf_bond && can_mf_bond)
2885f61385dSMoni Shoua free = free_for_dup;
2895f61385dSMoni Shoua
290ffe455adSEugenia Emantayev mlx4_dbg(dev, "Free MAC index is %d\n", free);
291ffe455adSEugenia Emantayev
292ffe455adSEugenia Emantayev if (table->total == table->max) {
293ffe455adSEugenia Emantayev /* No free mac entries */
294ffe455adSEugenia Emantayev err = -ENOSPC;
295ffe455adSEugenia Emantayev goto out;
296ffe455adSEugenia Emantayev }
297ffe455adSEugenia Emantayev
298ffe455adSEugenia Emantayev /* Register new MAC */
299ffe455adSEugenia Emantayev table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
300ffe455adSEugenia Emantayev
301ffe455adSEugenia Emantayev err = mlx4_set_port_mac_table(dev, port, table->entries);
302ffe455adSEugenia Emantayev if (unlikely(err)) {
303ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
304ffe455adSEugenia Emantayev (unsigned long long) mac);
305ffe455adSEugenia Emantayev table->entries[free] = 0;
306ffe455adSEugenia Emantayev goto out;
307ffe455adSEugenia Emantayev }
3086ce71acdSRony Efraim table->refs[free] = 1;
3095f61385dSMoni Shoua table->is_dup[free] = false;
310ffe455adSEugenia Emantayev ++table->total;
3115f61385dSMoni Shoua if (dup) {
3125f61385dSMoni Shoua dup_table->refs[free] = 0;
3135f61385dSMoni Shoua dup_table->is_dup[free] = true;
3145f61385dSMoni Shoua dup_table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
3155f61385dSMoni Shoua
3165f61385dSMoni Shoua err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries);
3175f61385dSMoni Shoua if (unlikely(err)) {
3185f61385dSMoni Shoua mlx4_warn(dev, "Failed adding duplicate mac: 0x%llx\n", mac);
3195f61385dSMoni Shoua dup_table->is_dup[free] = false;
3205f61385dSMoni Shoua dup_table->entries[free] = 0;
3215f61385dSMoni Shoua goto out;
3225f61385dSMoni Shoua }
3235f61385dSMoni Shoua ++dup_table->total;
3245f61385dSMoni Shoua }
3255f61385dSMoni Shoua err = free;
326ffe455adSEugenia Emantayev out:
3275f61385dSMoni Shoua if (need_mf_bond) {
3285f61385dSMoni Shoua if (port == 2) {
329ffe455adSEugenia Emantayev mutex_unlock(&table->mutex);
3305f61385dSMoni Shoua mutex_unlock(&dup_table->mutex);
3315f61385dSMoni Shoua } else {
3325f61385dSMoni Shoua mutex_unlock(&dup_table->mutex);
3335f61385dSMoni Shoua mutex_unlock(&table->mutex);
3345f61385dSMoni Shoua }
3355f61385dSMoni Shoua } else {
3365f61385dSMoni Shoua mutex_unlock(&table->mutex);
3375f61385dSMoni Shoua }
338ffe455adSEugenia Emantayev return err;
339ffe455adSEugenia Emantayev }
340ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_register_mac);
341ffe455adSEugenia Emantayev
mlx4_register_mac(struct mlx4_dev * dev,u8 port,u64 mac)342ffe455adSEugenia Emantayev int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
343ffe455adSEugenia Emantayev {
344e7dbeba8SJack Morgenstein u64 out_param = 0;
345acddd5ddSJack Morgenstein int err = -EINVAL;
346ffe455adSEugenia Emantayev
347ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) {
348acddd5ddSJack Morgenstein if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) {
349acddd5ddSJack Morgenstein err = mlx4_cmd_imm(dev, mac, &out_param,
350acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_MAC,
351acddd5ddSJack Morgenstein RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
352acddd5ddSJack Morgenstein MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
353acddd5ddSJack Morgenstein }
354acddd5ddSJack Morgenstein if (err && err == -EINVAL && mlx4_is_slave(dev)) {
355acddd5ddSJack Morgenstein /* retry using old REG_MAC format */
356ffe455adSEugenia Emantayev set_param_l(&out_param, port);
357ffe455adSEugenia Emantayev err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC,
358ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
359ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
360acddd5ddSJack Morgenstein if (!err)
361acddd5ddSJack Morgenstein dev->flags |= MLX4_FLAG_OLD_REG_MAC;
362acddd5ddSJack Morgenstein }
363ffe455adSEugenia Emantayev if (err)
364ffe455adSEugenia Emantayev return err;
365ffe455adSEugenia Emantayev
366ffe455adSEugenia Emantayev return get_param_l(&out_param);
367ffe455adSEugenia Emantayev }
368ffe455adSEugenia Emantayev return __mlx4_register_mac(dev, port, mac);
369ffe455adSEugenia Emantayev }
370ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(mlx4_register_mac);
371ffe455adSEugenia Emantayev
mlx4_get_base_qpn(struct mlx4_dev * dev,u8 port)37216a10ffdSYan Burman int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port)
37316a10ffdSYan Burman {
37416a10ffdSYan Burman return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
37516a10ffdSYan Burman (port - 1) * (1 << dev->caps.log_num_macs);
37616a10ffdSYan Burman }
37716a10ffdSYan Burman EXPORT_SYMBOL_GPL(mlx4_get_base_qpn);
378ffe455adSEugenia Emantayev
__mlx4_unregister_mac(struct mlx4_dev * dev,u8 port,u64 mac)379ffe455adSEugenia Emantayev void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
380ffe455adSEugenia Emantayev {
381143b3efbSEugenia Emantayev struct mlx4_port_info *info;
382143b3efbSEugenia Emantayev struct mlx4_mac_table *table;
383ffe455adSEugenia Emantayev int index;
3845f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev);
3855f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1;
3865f61385dSMoni Shoua struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
387ffe455adSEugenia Emantayev
388143b3efbSEugenia Emantayev if (port < 1 || port > dev->caps.num_ports) {
389143b3efbSEugenia Emantayev mlx4_warn(dev, "invalid port number (%d), aborting...\n", port);
390143b3efbSEugenia Emantayev return;
391143b3efbSEugenia Emantayev }
392143b3efbSEugenia Emantayev info = &mlx4_priv(dev)->port[port];
393143b3efbSEugenia Emantayev table = &info->mac_table;
3945f61385dSMoni Shoua
3955f61385dSMoni Shoua if (dup) {
3965f61385dSMoni Shoua if (port == 1) {
3975a2cc190SJeff Kirsher mutex_lock(&table->mutex);
39803a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
3995f61385dSMoni Shoua } else {
4005f61385dSMoni Shoua mutex_lock(&dup_table->mutex);
40103a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
4025f61385dSMoni Shoua }
4035f61385dSMoni Shoua } else {
4045f61385dSMoni Shoua mutex_lock(&table->mutex);
4055f61385dSMoni Shoua }
4065f61385dSMoni Shoua
4076ce71acdSRony Efraim index = find_index(dev, table, mac);
4085a2cc190SJeff Kirsher
4095a2cc190SJeff Kirsher if (validate_index(dev, table, index))
4105a2cc190SJeff Kirsher goto out;
4115f61385dSMoni Shoua
4125f61385dSMoni Shoua if (--table->refs[index] || table->is_dup[index]) {
4131a91de28SJoe Perches mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n",
4141a91de28SJoe Perches index);
4155f61385dSMoni Shoua if (!table->refs[index])
4165f61385dSMoni Shoua dup_table->is_dup[index] = false;
4176ce71acdSRony Efraim goto out;
4186ce71acdSRony Efraim }
4195a2cc190SJeff Kirsher
4205a2cc190SJeff Kirsher table->entries[index] = 0;
4215f61385dSMoni Shoua if (mlx4_set_port_mac_table(dev, port, table->entries))
4225f61385dSMoni Shoua mlx4_warn(dev, "Fail to set mac in port %d during unregister\n", port);
4235a2cc190SJeff Kirsher --table->total;
4245f61385dSMoni Shoua
4255f61385dSMoni Shoua if (dup) {
4265f61385dSMoni Shoua dup_table->is_dup[index] = false;
4275f61385dSMoni Shoua if (dup_table->refs[index])
4285f61385dSMoni Shoua goto out;
4295f61385dSMoni Shoua dup_table->entries[index] = 0;
4305f61385dSMoni Shoua if (mlx4_set_port_mac_table(dev, dup_port, dup_table->entries))
4315f61385dSMoni Shoua mlx4_warn(dev, "Fail to set mac in duplicate port %d during unregister\n", dup_port);
4325f61385dSMoni Shoua
4335f61385dSMoni Shoua --table->total;
4345f61385dSMoni Shoua }
4355a2cc190SJeff Kirsher out:
4365f61385dSMoni Shoua if (dup) {
4375f61385dSMoni Shoua if (port == 2) {
4385a2cc190SJeff Kirsher mutex_unlock(&table->mutex);
4395f61385dSMoni Shoua mutex_unlock(&dup_table->mutex);
4405f61385dSMoni Shoua } else {
4415f61385dSMoni Shoua mutex_unlock(&dup_table->mutex);
4425f61385dSMoni Shoua mutex_unlock(&table->mutex);
4435f61385dSMoni Shoua }
4445f61385dSMoni Shoua } else {
4455f61385dSMoni Shoua mutex_unlock(&table->mutex);
4465f61385dSMoni Shoua }
4475a2cc190SJeff Kirsher }
448ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_unregister_mac);
449ffe455adSEugenia Emantayev
mlx4_unregister_mac(struct mlx4_dev * dev,u8 port,u64 mac)450ffe455adSEugenia Emantayev void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
451ffe455adSEugenia Emantayev {
452e7dbeba8SJack Morgenstein u64 out_param = 0;
453ffe455adSEugenia Emantayev
454ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) {
455acddd5ddSJack Morgenstein if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) {
456acddd5ddSJack Morgenstein (void) mlx4_cmd_imm(dev, mac, &out_param,
457acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_MAC,
458acddd5ddSJack Morgenstein RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
459acddd5ddSJack Morgenstein MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
460acddd5ddSJack Morgenstein } else {
461acddd5ddSJack Morgenstein /* use old unregister mac format */
462ffe455adSEugenia Emantayev set_param_l(&out_param, port);
463162344edSOr Gerlitz (void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC,
464ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
465ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
466acddd5ddSJack Morgenstein }
467ffe455adSEugenia Emantayev return;
468ffe455adSEugenia Emantayev }
469ffe455adSEugenia Emantayev __mlx4_unregister_mac(dev, port, mac);
470ffe455adSEugenia Emantayev return;
471ffe455adSEugenia Emantayev }
4725a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
4735a2cc190SJeff Kirsher
__mlx4_replace_mac(struct mlx4_dev * dev,u8 port,int qpn,u64 new_mac)47416a10ffdSYan Burman int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
4755a2cc190SJeff Kirsher {
4765a2cc190SJeff Kirsher struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
4775a2cc190SJeff Kirsher struct mlx4_mac_table *table = &info->mac_table;
478ffe455adSEugenia Emantayev int index = qpn - info->base_qpn;
479ffe455adSEugenia Emantayev int err = 0;
4805f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev);
4815f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1;
4825f61385dSMoni Shoua struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
4835a2cc190SJeff Kirsher
484ffe455adSEugenia Emantayev /* CX1 doesn't support multi-functions */
4855f61385dSMoni Shoua if (dup) {
4865f61385dSMoni Shoua if (port == 1) {
4875a2cc190SJeff Kirsher mutex_lock(&table->mutex);
48803a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
4895f61385dSMoni Shoua } else {
4905f61385dSMoni Shoua mutex_lock(&dup_table->mutex);
49103a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
4925f61385dSMoni Shoua }
4935f61385dSMoni Shoua } else {
4945f61385dSMoni Shoua mutex_lock(&table->mutex);
4955f61385dSMoni Shoua }
4965a2cc190SJeff Kirsher
4975a2cc190SJeff Kirsher err = validate_index(dev, table, index);
4985a2cc190SJeff Kirsher if (err)
4995a2cc190SJeff Kirsher goto out;
5005a2cc190SJeff Kirsher
5015a2cc190SJeff Kirsher table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
5025a2cc190SJeff Kirsher
5035a2cc190SJeff Kirsher err = mlx4_set_port_mac_table(dev, port, table->entries);
5045a2cc190SJeff Kirsher if (unlikely(err)) {
505ffe455adSEugenia Emantayev mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
506ffe455adSEugenia Emantayev (unsigned long long) new_mac);
5075a2cc190SJeff Kirsher table->entries[index] = 0;
5085f61385dSMoni Shoua } else {
5095f61385dSMoni Shoua if (dup) {
5105f61385dSMoni Shoua dup_table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
5115f61385dSMoni Shoua
5125f61385dSMoni Shoua err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries);
5135f61385dSMoni Shoua if (unlikely(err)) {
5145f61385dSMoni Shoua mlx4_err(dev, "Failed adding duplicate MAC: 0x%llx\n",
5155f61385dSMoni Shoua (unsigned long long)new_mac);
5165f61385dSMoni Shoua dup_table->entries[index] = 0;
5175f61385dSMoni Shoua }
5185f61385dSMoni Shoua }
5195a2cc190SJeff Kirsher }
5205a2cc190SJeff Kirsher out:
5215f61385dSMoni Shoua if (dup) {
5225f61385dSMoni Shoua if (port == 2) {
5235a2cc190SJeff Kirsher mutex_unlock(&table->mutex);
5245f61385dSMoni Shoua mutex_unlock(&dup_table->mutex);
5255f61385dSMoni Shoua } else {
5265f61385dSMoni Shoua mutex_unlock(&dup_table->mutex);
5275f61385dSMoni Shoua mutex_unlock(&table->mutex);
5285f61385dSMoni Shoua }
5295f61385dSMoni Shoua } else {
5305f61385dSMoni Shoua mutex_unlock(&table->mutex);
5315f61385dSMoni Shoua }
5325a2cc190SJeff Kirsher return err;
5335a2cc190SJeff Kirsher }
53416a10ffdSYan Burman EXPORT_SYMBOL_GPL(__mlx4_replace_mac);
535ffe455adSEugenia Emantayev
mlx4_set_port_vlan_table(struct mlx4_dev * dev,u8 port,__be32 * entries)5365a2cc190SJeff Kirsher static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
5375a2cc190SJeff Kirsher __be32 *entries)
5385a2cc190SJeff Kirsher {
5395a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox;
5405a2cc190SJeff Kirsher u32 in_mod;
5415a2cc190SJeff Kirsher int err;
5425a2cc190SJeff Kirsher
5435a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev);
5445a2cc190SJeff Kirsher if (IS_ERR(mailbox))
5455a2cc190SJeff Kirsher return PTR_ERR(mailbox);
5465a2cc190SJeff Kirsher
5475a2cc190SJeff Kirsher memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE);
5485a2cc190SJeff Kirsher in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port;
549a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
550a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
551a130b590SIdo Shamay MLX4_CMD_NATIVE);
5525a2cc190SJeff Kirsher
5535a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox);
5545a2cc190SJeff Kirsher
5555a2cc190SJeff Kirsher return err;
5565a2cc190SJeff Kirsher }
5575a2cc190SJeff Kirsher
mlx4_find_cached_vlan(struct mlx4_dev * dev,u8 port,u16 vid,int * idx)5585a2cc190SJeff Kirsher int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
5595a2cc190SJeff Kirsher {
5605a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
5615a2cc190SJeff Kirsher int i;
5625a2cc190SJeff Kirsher
5635a2cc190SJeff Kirsher for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) {
5645a2cc190SJeff Kirsher if (table->refs[i] &&
5655a2cc190SJeff Kirsher (vid == (MLX4_VLAN_MASK &
5665a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) {
5675a2cc190SJeff Kirsher /* VLAN already registered, increase reference count */
5685a2cc190SJeff Kirsher *idx = i;
5695a2cc190SJeff Kirsher return 0;
5705a2cc190SJeff Kirsher }
5715a2cc190SJeff Kirsher }
5725a2cc190SJeff Kirsher
5735a2cc190SJeff Kirsher return -ENOENT;
5745a2cc190SJeff Kirsher }
5755a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
5765a2cc190SJeff Kirsher
__mlx4_register_vlan(struct mlx4_dev * dev,u8 port,u16 vlan,int * index)5773f7fb021SRony Efraim int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
578ffe455adSEugenia Emantayev int *index)
5795a2cc190SJeff Kirsher {
5805a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
5815a2cc190SJeff Kirsher int i, err = 0;
5825a2cc190SJeff Kirsher int free = -1;
5835f61385dSMoni Shoua int free_for_dup = -1;
5845f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev);
5855f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1;
5865f61385dSMoni Shoua struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table;
5875f61385dSMoni Shoua bool need_mf_bond = mlx4_need_mf_bond(dev);
5885f61385dSMoni Shoua bool can_mf_bond = true;
5895a2cc190SJeff Kirsher
5905f61385dSMoni Shoua mlx4_dbg(dev, "Registering VLAN: %d for port %d %s duplicate\n",
5915f61385dSMoni Shoua vlan, port,
5925f61385dSMoni Shoua dup ? "with" : "without");
5935f61385dSMoni Shoua
5945f61385dSMoni Shoua if (need_mf_bond) {
5955f61385dSMoni Shoua if (port == 1) {
5965a2cc190SJeff Kirsher mutex_lock(&table->mutex);
59703a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
5985f61385dSMoni Shoua } else {
5995f61385dSMoni Shoua mutex_lock(&dup_table->mutex);
60003a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
6015f61385dSMoni Shoua }
6025f61385dSMoni Shoua } else {
6035f61385dSMoni Shoua mutex_lock(&table->mutex);
6045f61385dSMoni Shoua }
605e72ebf5aSYevgeny Petrilin
606e72ebf5aSYevgeny Petrilin if (table->total == table->max) {
607e72ebf5aSYevgeny Petrilin /* No free vlan entries */
608e72ebf5aSYevgeny Petrilin err = -ENOSPC;
609e72ebf5aSYevgeny Petrilin goto out;
610e72ebf5aSYevgeny Petrilin }
611e72ebf5aSYevgeny Petrilin
6125f61385dSMoni Shoua if (need_mf_bond) {
6135f61385dSMoni Shoua int index_at_port = -1;
6145f61385dSMoni Shoua int index_at_dup_port = -1;
6155f61385dSMoni Shoua
6165a2cc190SJeff Kirsher for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
617cfed0a2cSVarsha Rao if (vlan == (MLX4_VLAN_MASK & be32_to_cpu(table->entries[i])))
6185f61385dSMoni Shoua index_at_port = i;
619cfed0a2cSVarsha Rao if (vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i])))
6205f61385dSMoni Shoua index_at_dup_port = i;
6215f61385dSMoni Shoua }
6225f61385dSMoni Shoua /* check that same vlan is not in the tables at different indices */
6235f61385dSMoni Shoua if ((index_at_port != index_at_dup_port) &&
6245f61385dSMoni Shoua (index_at_port >= 0) &&
6255f61385dSMoni Shoua (index_at_dup_port >= 0))
6265f61385dSMoni Shoua can_mf_bond = false;
6275f61385dSMoni Shoua
6285f61385dSMoni Shoua /* If the vlan is already in the primary table, the slot must be
6295f61385dSMoni Shoua * available in the duplicate table as well.
6305f61385dSMoni Shoua */
6315f61385dSMoni Shoua if (index_at_port >= 0 && index_at_dup_port < 0 &&
6325f61385dSMoni Shoua dup_table->refs[index_at_port]) {
6335f61385dSMoni Shoua can_mf_bond = false;
6345f61385dSMoni Shoua }
6355f61385dSMoni Shoua /* If the vlan is already in the duplicate table, check that the
6365f61385dSMoni Shoua * corresponding index is not occupied in the primary table, or
6375f61385dSMoni Shoua * the primary table already contains the vlan at the same index.
6385f61385dSMoni Shoua * Otherwise, you cannot bond (primary contains a different vlan
6395f61385dSMoni Shoua * at that index).
6405f61385dSMoni Shoua */
6415f61385dSMoni Shoua if (index_at_dup_port >= 0) {
6425f61385dSMoni Shoua if (!table->refs[index_at_dup_port] ||
6435f61385dSMoni Shoua (vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[index_at_dup_port]))))
6445f61385dSMoni Shoua free_for_dup = index_at_dup_port;
6455f61385dSMoni Shoua else
6465f61385dSMoni Shoua can_mf_bond = false;
6475f61385dSMoni Shoua }
6485a2cc190SJeff Kirsher }
6495a2cc190SJeff Kirsher
6505f61385dSMoni Shoua for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
6515f61385dSMoni Shoua if (!table->refs[i]) {
6525f61385dSMoni Shoua if (free < 0)
6535f61385dSMoni Shoua free = i;
6545f61385dSMoni Shoua if (free_for_dup < 0 && need_mf_bond && can_mf_bond) {
6555f61385dSMoni Shoua if (!dup_table->refs[i])
6565f61385dSMoni Shoua free_for_dup = i;
6575f61385dSMoni Shoua }
6585f61385dSMoni Shoua }
6595f61385dSMoni Shoua
6605f61385dSMoni Shoua if ((table->refs[i] || table->is_dup[i]) &&
6615a2cc190SJeff Kirsher (vlan == (MLX4_VLAN_MASK &
6625a2cc190SJeff Kirsher be32_to_cpu(table->entries[i])))) {
6635a2cc190SJeff Kirsher /* Vlan already registered, increase references count */
6645f61385dSMoni Shoua mlx4_dbg(dev, "vlan %u is already registered.\n", vlan);
6655a2cc190SJeff Kirsher *index = i;
6665a2cc190SJeff Kirsher ++table->refs[i];
6675f61385dSMoni Shoua if (dup) {
6685f61385dSMoni Shoua u16 dup_vlan = MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i]);
6695f61385dSMoni Shoua
6705f61385dSMoni Shoua if (dup_vlan != vlan || !dup_table->is_dup[i]) {
6715f61385dSMoni Shoua mlx4_warn(dev, "register vlan: expected duplicate vlan %u on port %d index %d\n",
6725f61385dSMoni Shoua vlan, dup_port, i);
6735f61385dSMoni Shoua }
6745f61385dSMoni Shoua }
6755a2cc190SJeff Kirsher goto out;
6765a2cc190SJeff Kirsher }
6775a2cc190SJeff Kirsher }
6785a2cc190SJeff Kirsher
6795f61385dSMoni Shoua if (need_mf_bond && (free_for_dup < 0)) {
6805f61385dSMoni Shoua if (dup) {
6815f61385dSMoni Shoua mlx4_warn(dev, "Fail to allocate duplicate VLAN table entry\n");
6825f61385dSMoni Shoua mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n");
6835f61385dSMoni Shoua dup = false;
6845f61385dSMoni Shoua }
6855f61385dSMoni Shoua can_mf_bond = false;
6865f61385dSMoni Shoua }
6875f61385dSMoni Shoua
6885f61385dSMoni Shoua if (need_mf_bond && can_mf_bond)
6895f61385dSMoni Shoua free = free_for_dup;
6905f61385dSMoni Shoua
6915a2cc190SJeff Kirsher if (free < 0) {
6925a2cc190SJeff Kirsher err = -ENOMEM;
6935a2cc190SJeff Kirsher goto out;
6945a2cc190SJeff Kirsher }
6955a2cc190SJeff Kirsher
696ffe455adSEugenia Emantayev /* Register new VLAN */
6975a2cc190SJeff Kirsher table->refs[free] = 1;
6985f61385dSMoni Shoua table->is_dup[free] = false;
6995a2cc190SJeff Kirsher table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
7005a2cc190SJeff Kirsher
7015a2cc190SJeff Kirsher err = mlx4_set_port_vlan_table(dev, port, table->entries);
7025a2cc190SJeff Kirsher if (unlikely(err)) {
7035a2cc190SJeff Kirsher mlx4_warn(dev, "Failed adding vlan: %u\n", vlan);
7045a2cc190SJeff Kirsher table->refs[free] = 0;
7055a2cc190SJeff Kirsher table->entries[free] = 0;
7065a2cc190SJeff Kirsher goto out;
7075a2cc190SJeff Kirsher }
7085f61385dSMoni Shoua ++table->total;
7095f61385dSMoni Shoua if (dup) {
7105f61385dSMoni Shoua dup_table->refs[free] = 0;
7115f61385dSMoni Shoua dup_table->is_dup[free] = true;
7125f61385dSMoni Shoua dup_table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
7135f61385dSMoni Shoua
7145f61385dSMoni Shoua err = mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries);
7155f61385dSMoni Shoua if (unlikely(err)) {
7165f61385dSMoni Shoua mlx4_warn(dev, "Failed adding duplicate vlan: %u\n", vlan);
7175f61385dSMoni Shoua dup_table->is_dup[free] = false;
7185f61385dSMoni Shoua dup_table->entries[free] = 0;
7195f61385dSMoni Shoua goto out;
7205f61385dSMoni Shoua }
7215f61385dSMoni Shoua ++dup_table->total;
7225f61385dSMoni Shoua }
7235a2cc190SJeff Kirsher
7245a2cc190SJeff Kirsher *index = free;
7255a2cc190SJeff Kirsher out:
7265f61385dSMoni Shoua if (need_mf_bond) {
7275f61385dSMoni Shoua if (port == 2) {
7285a2cc190SJeff Kirsher mutex_unlock(&table->mutex);
7295f61385dSMoni Shoua mutex_unlock(&dup_table->mutex);
7305f61385dSMoni Shoua } else {
7315f61385dSMoni Shoua mutex_unlock(&dup_table->mutex);
7325f61385dSMoni Shoua mutex_unlock(&table->mutex);
7335f61385dSMoni Shoua }
7345f61385dSMoni Shoua } else {
7355f61385dSMoni Shoua mutex_unlock(&table->mutex);
7365f61385dSMoni Shoua }
7375a2cc190SJeff Kirsher return err;
7385a2cc190SJeff Kirsher }
739ffe455adSEugenia Emantayev
mlx4_register_vlan(struct mlx4_dev * dev,u8 port,u16 vlan,int * index)740ffe455adSEugenia Emantayev int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
741ffe455adSEugenia Emantayev {
742e7dbeba8SJack Morgenstein u64 out_param = 0;
743ffe455adSEugenia Emantayev int err;
744ffe455adSEugenia Emantayev
745162226a1SJack Morgenstein if (vlan > 4095)
746162226a1SJack Morgenstein return -EINVAL;
747162226a1SJack Morgenstein
748ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) {
749acddd5ddSJack Morgenstein err = mlx4_cmd_imm(dev, vlan, &out_param,
750acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN,
751ffe455adSEugenia Emantayev RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
752ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
753ffe455adSEugenia Emantayev if (!err)
754ffe455adSEugenia Emantayev *index = get_param_l(&out_param);
755ffe455adSEugenia Emantayev
756ffe455adSEugenia Emantayev return err;
757ffe455adSEugenia Emantayev }
758ffe455adSEugenia Emantayev return __mlx4_register_vlan(dev, port, vlan, index);
759ffe455adSEugenia Emantayev }
7605a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_register_vlan);
7615a2cc190SJeff Kirsher
__mlx4_unregister_vlan(struct mlx4_dev * dev,u8 port,u16 vlan)7622009d005SJack Morgenstein void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
7635a2cc190SJeff Kirsher {
7645a2cc190SJeff Kirsher struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
7652009d005SJack Morgenstein int index;
7665f61385dSMoni Shoua bool dup = mlx4_is_mf_bonded(dev);
7675f61385dSMoni Shoua u8 dup_port = (port == 1) ? 2 : 1;
7685f61385dSMoni Shoua struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table;
7692009d005SJack Morgenstein
7705f61385dSMoni Shoua if (dup) {
7715f61385dSMoni Shoua if (port == 1) {
7722009d005SJack Morgenstein mutex_lock(&table->mutex);
77303a79f31SJack Morgenstein mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
7745f61385dSMoni Shoua } else {
7755f61385dSMoni Shoua mutex_lock(&dup_table->mutex);
77603a79f31SJack Morgenstein mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
7775f61385dSMoni Shoua }
7785f61385dSMoni Shoua } else {
7795f61385dSMoni Shoua mutex_lock(&table->mutex);
7805f61385dSMoni Shoua }
7815f61385dSMoni Shoua
7822009d005SJack Morgenstein if (mlx4_find_cached_vlan(dev, port, vlan, &index)) {
7832009d005SJack Morgenstein mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan);
7842009d005SJack Morgenstein goto out;
7852009d005SJack Morgenstein }
7865a2cc190SJeff Kirsher
7875a2cc190SJeff Kirsher if (index < MLX4_VLAN_REGULAR) {
7885a2cc190SJeff Kirsher mlx4_warn(dev, "Trying to free special vlan index %d\n", index);
7895a2cc190SJeff Kirsher goto out;
7905a2cc190SJeff Kirsher }
7912009d005SJack Morgenstein
7925f61385dSMoni Shoua if (--table->refs[index] || table->is_dup[index]) {
7931a91de28SJoe Perches mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n",
7941a91de28SJoe Perches table->refs[index], index);
7955f61385dSMoni Shoua if (!table->refs[index])
7965f61385dSMoni Shoua dup_table->is_dup[index] = false;
7975a2cc190SJeff Kirsher goto out;
7985a2cc190SJeff Kirsher }
7995a2cc190SJeff Kirsher table->entries[index] = 0;
8005f61385dSMoni Shoua if (mlx4_set_port_vlan_table(dev, port, table->entries))
8015f61385dSMoni Shoua mlx4_warn(dev, "Fail to set vlan in port %d during unregister\n", port);
8025a2cc190SJeff Kirsher --table->total;
8035f61385dSMoni Shoua if (dup) {
8045f61385dSMoni Shoua dup_table->is_dup[index] = false;
8055f61385dSMoni Shoua if (dup_table->refs[index])
8065f61385dSMoni Shoua goto out;
8075f61385dSMoni Shoua dup_table->entries[index] = 0;
8085f61385dSMoni Shoua if (mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries))
8095f61385dSMoni Shoua mlx4_warn(dev, "Fail to set vlan in duplicate port %d during unregister\n", dup_port);
8105f61385dSMoni Shoua --dup_table->total;
8115f61385dSMoni Shoua }
8125a2cc190SJeff Kirsher out:
8135f61385dSMoni Shoua if (dup) {
8145f61385dSMoni Shoua if (port == 2) {
8155a2cc190SJeff Kirsher mutex_unlock(&table->mutex);
8165f61385dSMoni Shoua mutex_unlock(&dup_table->mutex);
8175f61385dSMoni Shoua } else {
8185f61385dSMoni Shoua mutex_unlock(&dup_table->mutex);
8195f61385dSMoni Shoua mutex_unlock(&table->mutex);
8205f61385dSMoni Shoua }
8215f61385dSMoni Shoua } else {
8225f61385dSMoni Shoua mutex_unlock(&table->mutex);
8235f61385dSMoni Shoua }
8245a2cc190SJeff Kirsher }
825ffe455adSEugenia Emantayev
mlx4_unregister_vlan(struct mlx4_dev * dev,u8 port,u16 vlan)8262009d005SJack Morgenstein void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
827ffe455adSEugenia Emantayev {
828162226a1SJack Morgenstein u64 out_param = 0;
829ffe455adSEugenia Emantayev
830ffe455adSEugenia Emantayev if (mlx4_is_mfunc(dev)) {
8312009d005SJack Morgenstein (void) mlx4_cmd_imm(dev, vlan, &out_param,
832acddd5ddSJack Morgenstein ((u32) port) << 8 | (u32) RES_VLAN,
833162226a1SJack Morgenstein RES_OP_RESERVE_AND_MAP,
834ffe455adSEugenia Emantayev MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A,
835ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED);
836ffe455adSEugenia Emantayev return;
837ffe455adSEugenia Emantayev }
8382009d005SJack Morgenstein __mlx4_unregister_vlan(dev, port, vlan);
839ffe455adSEugenia Emantayev }
8405a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_vlan);
8415a2cc190SJeff Kirsher
mlx4_bond_mac_table(struct mlx4_dev * dev)8425f61385dSMoni Shoua int mlx4_bond_mac_table(struct mlx4_dev *dev)
8435f61385dSMoni Shoua {
8445f61385dSMoni Shoua struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table;
8455f61385dSMoni Shoua struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table;
8465f61385dSMoni Shoua int ret = 0;
8475f61385dSMoni Shoua int i;
8485f61385dSMoni Shoua bool update1 = false;
8495f61385dSMoni Shoua bool update2 = false;
8505f61385dSMoni Shoua
8515f61385dSMoni Shoua mutex_lock(&t1->mutex);
8525f61385dSMoni Shoua mutex_lock(&t2->mutex);
8535f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
8545f61385dSMoni Shoua if ((t1->entries[i] != t2->entries[i]) &&
8555f61385dSMoni Shoua t1->entries[i] && t2->entries[i]) {
8565f61385dSMoni Shoua mlx4_warn(dev, "can't duplicate entry %d in mac table\n", i);
8575f61385dSMoni Shoua ret = -EINVAL;
8585f61385dSMoni Shoua goto unlock;
8595f61385dSMoni Shoua }
8605f61385dSMoni Shoua }
8615f61385dSMoni Shoua
8625f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
8635f61385dSMoni Shoua if (t1->entries[i] && !t2->entries[i]) {
8645f61385dSMoni Shoua t2->entries[i] = t1->entries[i];
8655f61385dSMoni Shoua t2->is_dup[i] = true;
8665f61385dSMoni Shoua update2 = true;
8675f61385dSMoni Shoua } else if (!t1->entries[i] && t2->entries[i]) {
8685f61385dSMoni Shoua t1->entries[i] = t2->entries[i];
8695f61385dSMoni Shoua t1->is_dup[i] = true;
8705f61385dSMoni Shoua update1 = true;
8715f61385dSMoni Shoua } else if (t1->entries[i] && t2->entries[i]) {
8725f61385dSMoni Shoua t1->is_dup[i] = true;
8735f61385dSMoni Shoua t2->is_dup[i] = true;
8745f61385dSMoni Shoua }
8755f61385dSMoni Shoua }
8765f61385dSMoni Shoua
8775f61385dSMoni Shoua if (update1) {
8785f61385dSMoni Shoua ret = mlx4_set_port_mac_table(dev, 1, t1->entries);
8795f61385dSMoni Shoua if (ret)
8805f61385dSMoni Shoua mlx4_warn(dev, "failed to set MAC table for port 1 (%d)\n", ret);
8815f61385dSMoni Shoua }
8825f61385dSMoni Shoua if (!ret && update2) {
8835f61385dSMoni Shoua ret = mlx4_set_port_mac_table(dev, 2, t2->entries);
8845f61385dSMoni Shoua if (ret)
8855f61385dSMoni Shoua mlx4_warn(dev, "failed to set MAC table for port 2 (%d)\n", ret);
8865f61385dSMoni Shoua }
8875f61385dSMoni Shoua
8885f61385dSMoni Shoua if (ret)
8895f61385dSMoni Shoua mlx4_warn(dev, "failed to create mirror MAC tables\n");
8905f61385dSMoni Shoua unlock:
8915f61385dSMoni Shoua mutex_unlock(&t2->mutex);
8925f61385dSMoni Shoua mutex_unlock(&t1->mutex);
8935f61385dSMoni Shoua return ret;
8945f61385dSMoni Shoua }
8955f61385dSMoni Shoua
mlx4_unbond_mac_table(struct mlx4_dev * dev)8965f61385dSMoni Shoua int mlx4_unbond_mac_table(struct mlx4_dev *dev)
8975f61385dSMoni Shoua {
8985f61385dSMoni Shoua struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table;
8995f61385dSMoni Shoua struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table;
9005f61385dSMoni Shoua int ret = 0;
9015f61385dSMoni Shoua int ret1;
9025f61385dSMoni Shoua int i;
9035f61385dSMoni Shoua bool update1 = false;
9045f61385dSMoni Shoua bool update2 = false;
9055f61385dSMoni Shoua
9065f61385dSMoni Shoua mutex_lock(&t1->mutex);
9075f61385dSMoni Shoua mutex_lock(&t2->mutex);
9085f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
9095f61385dSMoni Shoua if (t1->entries[i] != t2->entries[i]) {
9105f61385dSMoni Shoua mlx4_warn(dev, "mac table is in an unexpected state when trying to unbond\n");
9115f61385dSMoni Shoua ret = -EINVAL;
9125f61385dSMoni Shoua goto unlock;
9135f61385dSMoni Shoua }
9145f61385dSMoni Shoua }
9155f61385dSMoni Shoua
9165f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
9175f61385dSMoni Shoua if (!t1->entries[i])
9185f61385dSMoni Shoua continue;
9195f61385dSMoni Shoua t1->is_dup[i] = false;
9205f61385dSMoni Shoua if (!t1->refs[i]) {
9215f61385dSMoni Shoua t1->entries[i] = 0;
9225f61385dSMoni Shoua update1 = true;
9235f61385dSMoni Shoua }
9245f61385dSMoni Shoua t2->is_dup[i] = false;
9255f61385dSMoni Shoua if (!t2->refs[i]) {
9265f61385dSMoni Shoua t2->entries[i] = 0;
9275f61385dSMoni Shoua update2 = true;
9285f61385dSMoni Shoua }
9295f61385dSMoni Shoua }
9305f61385dSMoni Shoua
9315f61385dSMoni Shoua if (update1) {
9325f61385dSMoni Shoua ret = mlx4_set_port_mac_table(dev, 1, t1->entries);
9335f61385dSMoni Shoua if (ret)
9345f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror MAC tables for port 1(%d)\n", ret);
9355f61385dSMoni Shoua }
9365f61385dSMoni Shoua if (update2) {
9375f61385dSMoni Shoua ret1 = mlx4_set_port_mac_table(dev, 2, t2->entries);
9385f61385dSMoni Shoua if (ret1) {
9395f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror MAC tables for port 2(%d)\n", ret1);
9405f61385dSMoni Shoua ret = ret1;
9415f61385dSMoni Shoua }
9425f61385dSMoni Shoua }
9435f61385dSMoni Shoua unlock:
9445f61385dSMoni Shoua mutex_unlock(&t2->mutex);
9455f61385dSMoni Shoua mutex_unlock(&t1->mutex);
9465f61385dSMoni Shoua return ret;
9475f61385dSMoni Shoua }
9485f61385dSMoni Shoua
mlx4_bond_vlan_table(struct mlx4_dev * dev)9495f61385dSMoni Shoua int mlx4_bond_vlan_table(struct mlx4_dev *dev)
9505f61385dSMoni Shoua {
9515f61385dSMoni Shoua struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table;
9525f61385dSMoni Shoua struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table;
9535f61385dSMoni Shoua int ret = 0;
9545f61385dSMoni Shoua int i;
9555f61385dSMoni Shoua bool update1 = false;
9565f61385dSMoni Shoua bool update2 = false;
9575f61385dSMoni Shoua
9585f61385dSMoni Shoua mutex_lock(&t1->mutex);
9595f61385dSMoni Shoua mutex_lock(&t2->mutex);
9605f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
9615f61385dSMoni Shoua if ((t1->entries[i] != t2->entries[i]) &&
9625f61385dSMoni Shoua t1->entries[i] && t2->entries[i]) {
9635f61385dSMoni Shoua mlx4_warn(dev, "can't duplicate entry %d in vlan table\n", i);
9645f61385dSMoni Shoua ret = -EINVAL;
9655f61385dSMoni Shoua goto unlock;
9665f61385dSMoni Shoua }
9675f61385dSMoni Shoua }
9685f61385dSMoni Shoua
9695f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
9705f61385dSMoni Shoua if (t1->entries[i] && !t2->entries[i]) {
9715f61385dSMoni Shoua t2->entries[i] = t1->entries[i];
9725f61385dSMoni Shoua t2->is_dup[i] = true;
9735f61385dSMoni Shoua update2 = true;
9745f61385dSMoni Shoua } else if (!t1->entries[i] && t2->entries[i]) {
9755f61385dSMoni Shoua t1->entries[i] = t2->entries[i];
9765f61385dSMoni Shoua t1->is_dup[i] = true;
9775f61385dSMoni Shoua update1 = true;
9785f61385dSMoni Shoua } else if (t1->entries[i] && t2->entries[i]) {
9795f61385dSMoni Shoua t1->is_dup[i] = true;
9805f61385dSMoni Shoua t2->is_dup[i] = true;
9815f61385dSMoni Shoua }
9825f61385dSMoni Shoua }
9835f61385dSMoni Shoua
9845f61385dSMoni Shoua if (update1) {
9855f61385dSMoni Shoua ret = mlx4_set_port_vlan_table(dev, 1, t1->entries);
9865f61385dSMoni Shoua if (ret)
9875f61385dSMoni Shoua mlx4_warn(dev, "failed to set VLAN table for port 1 (%d)\n", ret);
9885f61385dSMoni Shoua }
9895f61385dSMoni Shoua if (!ret && update2) {
9905f61385dSMoni Shoua ret = mlx4_set_port_vlan_table(dev, 2, t2->entries);
9915f61385dSMoni Shoua if (ret)
9925f61385dSMoni Shoua mlx4_warn(dev, "failed to set VLAN table for port 2 (%d)\n", ret);
9935f61385dSMoni Shoua }
9945f61385dSMoni Shoua
9955f61385dSMoni Shoua if (ret)
9965f61385dSMoni Shoua mlx4_warn(dev, "failed to create mirror VLAN tables\n");
9975f61385dSMoni Shoua unlock:
9985f61385dSMoni Shoua mutex_unlock(&t2->mutex);
9995f61385dSMoni Shoua mutex_unlock(&t1->mutex);
10005f61385dSMoni Shoua return ret;
10015f61385dSMoni Shoua }
10025f61385dSMoni Shoua
mlx4_unbond_vlan_table(struct mlx4_dev * dev)10035f61385dSMoni Shoua int mlx4_unbond_vlan_table(struct mlx4_dev *dev)
10045f61385dSMoni Shoua {
10055f61385dSMoni Shoua struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table;
10065f61385dSMoni Shoua struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table;
10075f61385dSMoni Shoua int ret = 0;
10085f61385dSMoni Shoua int ret1;
10095f61385dSMoni Shoua int i;
10105f61385dSMoni Shoua bool update1 = false;
10115f61385dSMoni Shoua bool update2 = false;
10125f61385dSMoni Shoua
10135f61385dSMoni Shoua mutex_lock(&t1->mutex);
10145f61385dSMoni Shoua mutex_lock(&t2->mutex);
10155f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
10165f61385dSMoni Shoua if (t1->entries[i] != t2->entries[i]) {
10175f61385dSMoni Shoua mlx4_warn(dev, "vlan table is in an unexpected state when trying to unbond\n");
10185f61385dSMoni Shoua ret = -EINVAL;
10195f61385dSMoni Shoua goto unlock;
10205f61385dSMoni Shoua }
10215f61385dSMoni Shoua }
10225f61385dSMoni Shoua
10235f61385dSMoni Shoua for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
10245f61385dSMoni Shoua if (!t1->entries[i])
10255f61385dSMoni Shoua continue;
10265f61385dSMoni Shoua t1->is_dup[i] = false;
10275f61385dSMoni Shoua if (!t1->refs[i]) {
10285f61385dSMoni Shoua t1->entries[i] = 0;
10295f61385dSMoni Shoua update1 = true;
10305f61385dSMoni Shoua }
10315f61385dSMoni Shoua t2->is_dup[i] = false;
10325f61385dSMoni Shoua if (!t2->refs[i]) {
10335f61385dSMoni Shoua t2->entries[i] = 0;
10345f61385dSMoni Shoua update2 = true;
10355f61385dSMoni Shoua }
10365f61385dSMoni Shoua }
10375f61385dSMoni Shoua
10385f61385dSMoni Shoua if (update1) {
10395f61385dSMoni Shoua ret = mlx4_set_port_vlan_table(dev, 1, t1->entries);
10405f61385dSMoni Shoua if (ret)
10415f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror VLAN tables for port 1(%d)\n", ret);
10425f61385dSMoni Shoua }
10435f61385dSMoni Shoua if (update2) {
10445f61385dSMoni Shoua ret1 = mlx4_set_port_vlan_table(dev, 2, t2->entries);
10455f61385dSMoni Shoua if (ret1) {
10465f61385dSMoni Shoua mlx4_warn(dev, "failed to unmirror VLAN tables for port 2(%d)\n", ret1);
10475f61385dSMoni Shoua ret = ret1;
10485f61385dSMoni Shoua }
10495f61385dSMoni Shoua }
10505f61385dSMoni Shoua unlock:
10515f61385dSMoni Shoua mutex_unlock(&t2->mutex);
10525f61385dSMoni Shoua mutex_unlock(&t1->mutex);
10535f61385dSMoni Shoua return ret;
10545f61385dSMoni Shoua }
10555f61385dSMoni Shoua
mlx4_get_port_ib_caps(struct mlx4_dev * dev,u8 port,__be32 * caps)10565a2cc190SJeff Kirsher int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
10575a2cc190SJeff Kirsher {
10585a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
10595a2cc190SJeff Kirsher u8 *inbuf, *outbuf;
10605a2cc190SJeff Kirsher int err;
10615a2cc190SJeff Kirsher
10625a2cc190SJeff Kirsher inmailbox = mlx4_alloc_cmd_mailbox(dev);
10635a2cc190SJeff Kirsher if (IS_ERR(inmailbox))
10645a2cc190SJeff Kirsher return PTR_ERR(inmailbox);
10655a2cc190SJeff Kirsher
10665a2cc190SJeff Kirsher outmailbox = mlx4_alloc_cmd_mailbox(dev);
10675a2cc190SJeff Kirsher if (IS_ERR(outmailbox)) {
10685a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox);
10695a2cc190SJeff Kirsher return PTR_ERR(outmailbox);
10705a2cc190SJeff Kirsher }
10715a2cc190SJeff Kirsher
10725a2cc190SJeff Kirsher inbuf = inmailbox->buf;
10735a2cc190SJeff Kirsher outbuf = outmailbox->buf;
10745a2cc190SJeff Kirsher inbuf[0] = 1;
10755a2cc190SJeff Kirsher inbuf[1] = 1;
10765a2cc190SJeff Kirsher inbuf[2] = 1;
10775a2cc190SJeff Kirsher inbuf[3] = 1;
10785a2cc190SJeff Kirsher *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015);
10795a2cc190SJeff Kirsher *(__be32 *) (&inbuf[20]) = cpu_to_be32(port);
10805a2cc190SJeff Kirsher
10815a2cc190SJeff Kirsher err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3,
1082f9baff50SJack Morgenstein MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
1083f9baff50SJack Morgenstein MLX4_CMD_NATIVE);
10845a2cc190SJeff Kirsher if (!err)
10855a2cc190SJeff Kirsher *caps = *(__be32 *) (outbuf + 84);
10865a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, inmailbox);
10875a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, outmailbox);
10885a2cc190SJeff Kirsher return err;
10895a2cc190SJeff Kirsher }
10909cd59352SJack Morgenstein static struct mlx4_roce_gid_entry zgid_entry;
10915a2cc190SJeff Kirsher
mlx4_get_slave_num_gids(struct mlx4_dev * dev,int slave,int port)1092449fc488SMatan Barak int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port)
1093b6ffaeffSJack Morgenstein {
1094449fc488SMatan Barak int vfs;
1095449fc488SMatan Barak int slave_gid = slave;
1096449fc488SMatan Barak unsigned i;
1097449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport;
1098449fc488SMatan Barak struct mlx4_active_ports actv_ports;
1099449fc488SMatan Barak unsigned max_port_p_one;
1100449fc488SMatan Barak
1101b6ffaeffSJack Morgenstein if (slave == 0)
1102b6ffaeffSJack Morgenstein return MLX4_ROCE_PF_GIDS;
1103449fc488SMatan Barak
1104449fc488SMatan Barak /* Slave is a VF */
1105449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1106449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave);
1107449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
1108449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
1109449fc488SMatan Barak
1110449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) {
1111449fc488SMatan Barak struct mlx4_active_ports exclusive_ports;
1112449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv;
1113449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
1114449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports);
1115449fc488SMatan Barak if (i == port)
1116449fc488SMatan Barak continue;
1117449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
1118449fc488SMatan Barak dev, &exclusive_ports);
1119449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
1120872bf2fbSYishai Hadas dev->persist->num_vfs + 1);
1121449fc488SMatan Barak }
1122872bf2fbSYishai Hadas vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1;
1123449fc488SMatan Barak if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs))
1124449fc488SMatan Barak return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1;
1125449fc488SMatan Barak return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs;
1126b6ffaeffSJack Morgenstein }
1127b6ffaeffSJack Morgenstein
mlx4_get_base_gid_ix(struct mlx4_dev * dev,int slave,int port)1128449fc488SMatan Barak int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port)
1129b6ffaeffSJack Morgenstein {
1130b6ffaeffSJack Morgenstein int gids;
1131449fc488SMatan Barak unsigned i;
1132449fc488SMatan Barak int slave_gid = slave;
1133b6ffaeffSJack Morgenstein int vfs;
1134b6ffaeffSJack Morgenstein
1135449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport;
1136449fc488SMatan Barak struct mlx4_active_ports actv_ports;
1137449fc488SMatan Barak unsigned max_port_p_one;
1138b6ffaeffSJack Morgenstein
1139b6ffaeffSJack Morgenstein if (slave == 0)
1140b6ffaeffSJack Morgenstein return 0;
1141b6ffaeffSJack Morgenstein
1142449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1143449fc488SMatan Barak actv_ports = mlx4_get_active_ports(dev, slave);
1144449fc488SMatan Barak max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
1145449fc488SMatan Barak bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
1146449fc488SMatan Barak
1147449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) {
1148449fc488SMatan Barak struct mlx4_active_ports exclusive_ports;
1149449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv;
1150449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
1151449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports);
1152449fc488SMatan Barak if (i == port)
1153449fc488SMatan Barak continue;
1154449fc488SMatan Barak slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
1155449fc488SMatan Barak dev, &exclusive_ports);
1156449fc488SMatan Barak slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
1157872bf2fbSYishai Hadas dev->persist->num_vfs + 1);
1158b6ffaeffSJack Morgenstein }
1159449fc488SMatan Barak gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
1160872bf2fbSYishai Hadas vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1;
1161449fc488SMatan Barak if (slave_gid <= gids % vfs)
1162449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1);
1163449fc488SMatan Barak
1164449fc488SMatan Barak return MLX4_ROCE_PF_GIDS + (gids % vfs) +
1165449fc488SMatan Barak ((gids / vfs) * (slave_gid - 1));
1166449fc488SMatan Barak }
1167449fc488SMatan Barak EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix);
1168b6ffaeffSJack Morgenstein
mlx4_reset_roce_port_gids(struct mlx4_dev * dev,int slave,int port,struct mlx4_cmd_mailbox * mailbox)1169111c6094SJack Morgenstein static int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave,
1170111c6094SJack Morgenstein int port, struct mlx4_cmd_mailbox *mailbox)
1171111c6094SJack Morgenstein {
1172111c6094SJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_mbox;
1173111c6094SJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev);
1174111c6094SJack Morgenstein int num_gids, base, offset;
1175111c6094SJack Morgenstein int i, err;
1176111c6094SJack Morgenstein
1177111c6094SJack Morgenstein num_gids = mlx4_get_slave_num_gids(dev, slave, port);
1178111c6094SJack Morgenstein base = mlx4_get_base_gid_ix(dev, slave, port);
1179111c6094SJack Morgenstein
1180111c6094SJack Morgenstein memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE);
1181111c6094SJack Morgenstein
1182111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex));
1183111c6094SJack Morgenstein /* Zero-out gids belonging to that slave in the port GID table */
1184111c6094SJack Morgenstein for (i = 0, offset = base; i < num_gids; offset++, i++)
1185111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
1186111c6094SJack Morgenstein zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE);
1187111c6094SJack Morgenstein
1188111c6094SJack Morgenstein /* Now, copy roce port gids table to mailbox for passing to FW */
1189111c6094SJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf;
1190111c6094SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
1191111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw,
1192111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw,
1193111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE);
1194111c6094SJack Morgenstein
1195111c6094SJack Morgenstein err = mlx4_cmd(dev, mailbox->dma,
1196a130b590SIdo Shamay ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8),
1197a130b590SIdo Shamay MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT,
1198a130b590SIdo Shamay MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
1199111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex));
1200111c6094SJack Morgenstein return err;
1201111c6094SJack Morgenstein }
1202111c6094SJack Morgenstein
1203111c6094SJack Morgenstein
mlx4_reset_roce_gids(struct mlx4_dev * dev,int slave)1204111c6094SJack Morgenstein void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave)
1205111c6094SJack Morgenstein {
1206111c6094SJack Morgenstein struct mlx4_active_ports actv_ports;
1207111c6094SJack Morgenstein struct mlx4_cmd_mailbox *mailbox;
1208111c6094SJack Morgenstein int num_eth_ports, err;
1209111c6094SJack Morgenstein int i;
1210111c6094SJack Morgenstein
1211872bf2fbSYishai Hadas if (slave < 0 || slave > dev->persist->num_vfs)
1212111c6094SJack Morgenstein return;
1213111c6094SJack Morgenstein
1214111c6094SJack Morgenstein actv_ports = mlx4_get_active_ports(dev, slave);
1215111c6094SJack Morgenstein
1216111c6094SJack Morgenstein for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) {
1217111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) {
1218111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
1219111c6094SJack Morgenstein continue;
1220111c6094SJack Morgenstein num_eth_ports++;
1221111c6094SJack Morgenstein }
1222111c6094SJack Morgenstein }
1223111c6094SJack Morgenstein
1224111c6094SJack Morgenstein if (!num_eth_ports)
1225111c6094SJack Morgenstein return;
1226111c6094SJack Morgenstein
1227111c6094SJack Morgenstein /* have ETH ports. Alloc mailbox for SET_PORT command */
1228111c6094SJack Morgenstein mailbox = mlx4_alloc_cmd_mailbox(dev);
1229111c6094SJack Morgenstein if (IS_ERR(mailbox))
1230111c6094SJack Morgenstein return;
1231111c6094SJack Morgenstein
1232111c6094SJack Morgenstein for (i = 0; i < dev->caps.num_ports; i++) {
1233111c6094SJack Morgenstein if (test_bit(i, actv_ports.ports)) {
1234111c6094SJack Morgenstein if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
1235111c6094SJack Morgenstein continue;
1236111c6094SJack Morgenstein err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox);
1237111c6094SJack Morgenstein if (err)
1238111c6094SJack Morgenstein mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n",
1239111c6094SJack Morgenstein slave, i + 1, err);
1240111c6094SJack Morgenstein }
1241111c6094SJack Morgenstein }
1242111c6094SJack Morgenstein
1243111c6094SJack Morgenstein mlx4_free_cmd_mailbox(dev, mailbox);
1244111c6094SJack Morgenstein return;
1245111c6094SJack Morgenstein }
1246111c6094SJack Morgenstein
124740fb4fc1SShaker Daibes static void
mlx4_en_set_port_mtu(struct mlx4_dev * dev,int slave,int port,struct mlx4_set_port_general_context * gen_context)1248bf1f9396SShaker Daibes mlx4_en_set_port_mtu(struct mlx4_dev *dev, int slave, int port,
1249bf1f9396SShaker Daibes struct mlx4_set_port_general_context *gen_context)
1250bf1f9396SShaker Daibes {
1251bf1f9396SShaker Daibes struct mlx4_priv *priv = mlx4_priv(dev);
1252bf1f9396SShaker Daibes struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
1253bf1f9396SShaker Daibes struct mlx4_slave_state *slave_st = &master->slave_state[slave];
1254bf1f9396SShaker Daibes u16 mtu, prev_mtu;
1255bf1f9396SShaker Daibes
1256bf1f9396SShaker Daibes /* Mtu is configured as the max USER_MTU among all
1257bf1f9396SShaker Daibes * the functions on the port.
1258bf1f9396SShaker Daibes */
1259bf1f9396SShaker Daibes mtu = be16_to_cpu(gen_context->mtu);
1260bf1f9396SShaker Daibes mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] +
1261bf1f9396SShaker Daibes ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
1262bf1f9396SShaker Daibes prev_mtu = slave_st->mtu[port];
1263bf1f9396SShaker Daibes slave_st->mtu[port] = mtu;
1264bf1f9396SShaker Daibes if (mtu > master->max_mtu[port])
1265bf1f9396SShaker Daibes master->max_mtu[port] = mtu;
1266bf1f9396SShaker Daibes if (mtu < prev_mtu && prev_mtu == master->max_mtu[port]) {
1267bf1f9396SShaker Daibes int i;
1268bf1f9396SShaker Daibes
1269bf1f9396SShaker Daibes slave_st->mtu[port] = mtu;
1270bf1f9396SShaker Daibes master->max_mtu[port] = mtu;
1271bf1f9396SShaker Daibes for (i = 0; i < dev->num_slaves; i++)
1272bf1f9396SShaker Daibes master->max_mtu[port] =
1273bf1f9396SShaker Daibes max_t(u16, master->max_mtu[port],
1274bf1f9396SShaker Daibes master->slave_state[i].mtu[port]);
1275bf1f9396SShaker Daibes }
1276bf1f9396SShaker Daibes gen_context->mtu = cpu_to_be16(master->max_mtu[port]);
1277bf1f9396SShaker Daibes }
1278bf1f9396SShaker Daibes
1279bf1f9396SShaker Daibes static void
mlx4_en_set_port_user_mtu(struct mlx4_dev * dev,int slave,int port,struct mlx4_set_port_general_context * gen_context)128040fb4fc1SShaker Daibes mlx4_en_set_port_user_mtu(struct mlx4_dev *dev, int slave, int port,
128140fb4fc1SShaker Daibes struct mlx4_set_port_general_context *gen_context)
128240fb4fc1SShaker Daibes {
128340fb4fc1SShaker Daibes struct mlx4_priv *priv = mlx4_priv(dev);
128440fb4fc1SShaker Daibes struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
128540fb4fc1SShaker Daibes struct mlx4_slave_state *slave_st = &master->slave_state[slave];
128640fb4fc1SShaker Daibes u16 user_mtu, prev_user_mtu;
128740fb4fc1SShaker Daibes
128840fb4fc1SShaker Daibes /* User Mtu is configured as the max USER_MTU among all
128940fb4fc1SShaker Daibes * the functions on the port.
129040fb4fc1SShaker Daibes */
129140fb4fc1SShaker Daibes user_mtu = be16_to_cpu(gen_context->user_mtu);
129240fb4fc1SShaker Daibes user_mtu = min_t(int, user_mtu, dev->caps.eth_mtu_cap[port]);
129340fb4fc1SShaker Daibes prev_user_mtu = slave_st->user_mtu[port];
129440fb4fc1SShaker Daibes slave_st->user_mtu[port] = user_mtu;
129540fb4fc1SShaker Daibes if (user_mtu > master->max_user_mtu[port])
129640fb4fc1SShaker Daibes master->max_user_mtu[port] = user_mtu;
129740fb4fc1SShaker Daibes if (user_mtu < prev_user_mtu &&
129840fb4fc1SShaker Daibes prev_user_mtu == master->max_user_mtu[port]) {
129940fb4fc1SShaker Daibes int i;
130040fb4fc1SShaker Daibes
130140fb4fc1SShaker Daibes slave_st->user_mtu[port] = user_mtu;
130240fb4fc1SShaker Daibes master->max_user_mtu[port] = user_mtu;
130340fb4fc1SShaker Daibes for (i = 0; i < dev->num_slaves; i++)
130440fb4fc1SShaker Daibes master->max_user_mtu[port] =
130540fb4fc1SShaker Daibes max_t(u16, master->max_user_mtu[port],
130640fb4fc1SShaker Daibes master->slave_state[i].user_mtu[port]);
130740fb4fc1SShaker Daibes }
130840fb4fc1SShaker Daibes gen_context->user_mtu = cpu_to_be16(master->max_user_mtu[port]);
130940fb4fc1SShaker Daibes }
131040fb4fc1SShaker Daibes
13111f8176f7SShaker Daibes static void
mlx4_en_set_port_global_pause(struct mlx4_dev * dev,int slave,struct mlx4_set_port_general_context * gen_context)13121f8176f7SShaker Daibes mlx4_en_set_port_global_pause(struct mlx4_dev *dev, int slave,
13131f8176f7SShaker Daibes struct mlx4_set_port_general_context *gen_context)
13141f8176f7SShaker Daibes {
13151f8176f7SShaker Daibes struct mlx4_priv *priv = mlx4_priv(dev);
13161f8176f7SShaker Daibes struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
13171f8176f7SShaker Daibes
13181f8176f7SShaker Daibes /* Slave cannot change Global Pause configuration */
13191f8176f7SShaker Daibes if (slave != mlx4_master_func_num(dev) &&
13201f8176f7SShaker Daibes (gen_context->pptx != master->pptx ||
13211f8176f7SShaker Daibes gen_context->pprx != master->pprx)) {
13221f8176f7SShaker Daibes gen_context->pptx = master->pptx;
13231f8176f7SShaker Daibes gen_context->pprx = master->pprx;
13241f8176f7SShaker Daibes mlx4_warn(dev, "denying Global Pause change for slave:%d\n",
13251f8176f7SShaker Daibes slave);
13261f8176f7SShaker Daibes } else {
13271f8176f7SShaker Daibes master->pptx = gen_context->pptx;
13281f8176f7SShaker Daibes master->pprx = gen_context->pprx;
13291f8176f7SShaker Daibes }
13301f8176f7SShaker Daibes }
13311f8176f7SShaker Daibes
mlx4_common_set_port(struct mlx4_dev * dev,int slave,u32 in_mod,u8 op_mod,struct mlx4_cmd_mailbox * inbox)1332ffe455adSEugenia Emantayev static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
1333ffe455adSEugenia Emantayev u8 op_mod, struct mlx4_cmd_mailbox *inbox)
1334ffe455adSEugenia Emantayev {
1335ffe455adSEugenia Emantayev struct mlx4_priv *priv = mlx4_priv(dev);
1336ffe455adSEugenia Emantayev struct mlx4_port_info *port_info;
1337ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *qpn_context;
1338ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *gen_context;
1339b6ffaeffSJack Morgenstein struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1;
1340ffe455adSEugenia Emantayev int reset_qkey_viols;
1341ffe455adSEugenia Emantayev int port;
1342ffe455adSEugenia Emantayev int is_eth;
1343b6ffaeffSJack Morgenstein int num_gids;
1344b6ffaeffSJack Morgenstein int base;
1345ffe455adSEugenia Emantayev u32 in_modifier;
1346ffe455adSEugenia Emantayev u32 promisc;
1347ffe455adSEugenia Emantayev int err;
1348b6ffaeffSJack Morgenstein int i, j;
1349b6ffaeffSJack Morgenstein int offset;
1350ffe455adSEugenia Emantayev __be32 agg_cap_mask;
1351ffe455adSEugenia Emantayev __be32 slave_cap_mask;
1352ffe455adSEugenia Emantayev __be32 new_cap_mask;
1353ffe455adSEugenia Emantayev
1354ffe455adSEugenia Emantayev port = in_mod & 0xff;
1355ffe455adSEugenia Emantayev in_modifier = in_mod >> 8;
1356ffe455adSEugenia Emantayev is_eth = op_mod;
1357ffe455adSEugenia Emantayev port_info = &priv->port[port];
1358ffe455adSEugenia Emantayev
135940fb4fc1SShaker Daibes /* Slaves cannot perform SET_PORT operations,
136040fb4fc1SShaker Daibes * except for changing MTU and USER_MTU.
136140fb4fc1SShaker Daibes */
1362ffe455adSEugenia Emantayev if (is_eth) {
1363ffe455adSEugenia Emantayev if (slave != dev->caps.function &&
13649cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GENERAL &&
13659cd59352SJack Morgenstein in_modifier != MLX4_SET_PORT_GID_TABLE) {
1366ffe455adSEugenia Emantayev mlx4_warn(dev, "denying SET_PORT for slave:%d\n",
1367ffe455adSEugenia Emantayev slave);
1368ffe455adSEugenia Emantayev return -EINVAL;
1369ffe455adSEugenia Emantayev }
1370ffe455adSEugenia Emantayev switch (in_modifier) {
1371ffe455adSEugenia Emantayev case MLX4_SET_PORT_RQP_CALC:
1372ffe455adSEugenia Emantayev qpn_context = inbox->buf;
1373ffe455adSEugenia Emantayev qpn_context->base_qpn =
1374ffe455adSEugenia Emantayev cpu_to_be32(port_info->base_qpn);
1375ffe455adSEugenia Emantayev qpn_context->n_mac = 0x7;
1376ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->promisc) >>
1377ffe455adSEugenia Emantayev SET_PORT_PROMISC_SHIFT;
1378ffe455adSEugenia Emantayev qpn_context->promisc = cpu_to_be32(
1379ffe455adSEugenia Emantayev promisc << SET_PORT_PROMISC_SHIFT |
1380ffe455adSEugenia Emantayev port_info->base_qpn);
1381ffe455adSEugenia Emantayev promisc = be32_to_cpu(qpn_context->mcast) >>
1382ffe455adSEugenia Emantayev SET_PORT_MC_PROMISC_SHIFT;
1383ffe455adSEugenia Emantayev qpn_context->mcast = cpu_to_be32(
1384ffe455adSEugenia Emantayev promisc << SET_PORT_MC_PROMISC_SHIFT |
1385ffe455adSEugenia Emantayev port_info->base_qpn);
1386ffe455adSEugenia Emantayev break;
1387ffe455adSEugenia Emantayev case MLX4_SET_PORT_GENERAL:
1388ffe455adSEugenia Emantayev gen_context = inbox->buf;
1389bf1f9396SShaker Daibes
1390bf1f9396SShaker Daibes if (gen_context->flags & MLX4_FLAG_V_MTU_MASK)
1391bf1f9396SShaker Daibes mlx4_en_set_port_mtu(dev, slave, port,
1392bf1f9396SShaker Daibes gen_context);
139340fb4fc1SShaker Daibes
139440fb4fc1SShaker Daibes if (gen_context->flags2 & MLX4_FLAG2_V_USER_MTU_MASK)
139540fb4fc1SShaker Daibes mlx4_en_set_port_user_mtu(dev, slave, port,
139640fb4fc1SShaker Daibes gen_context);
139740fb4fc1SShaker Daibes
13981f8176f7SShaker Daibes if (gen_context->flags &
139973cfb2a2SDan Carpenter (MLX4_FLAG_V_PPRX_MASK | MLX4_FLAG_V_PPTX_MASK))
14001f8176f7SShaker Daibes mlx4_en_set_port_global_pause(dev, slave,
14011f8176f7SShaker Daibes gen_context);
14021f8176f7SShaker Daibes
1403ffe455adSEugenia Emantayev break;
14049cd59352SJack Morgenstein case MLX4_SET_PORT_GID_TABLE:
1405b6ffaeffSJack Morgenstein /* change to MULTIPLE entries: number of guest's gids
1406b6ffaeffSJack Morgenstein * need a FOR-loop here over number of gids the guest has.
1407b6ffaeffSJack Morgenstein * 1. Check no duplicates in gids passed by slave
1408b6ffaeffSJack Morgenstein */
1409449fc488SMatan Barak num_gids = mlx4_get_slave_num_gids(dev, slave, port);
1410449fc488SMatan Barak base = mlx4_get_base_gid_ix(dev, slave, port);
1411b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1412b6ffaeffSJack Morgenstein for (i = 0; i < num_gids; gid_entry_mbox++, i++) {
1413b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
1414b6ffaeffSJack Morgenstein sizeof(zgid_entry)))
1415b6ffaeffSJack Morgenstein continue;
1416b6ffaeffSJack Morgenstein gid_entry_mb1 = gid_entry_mbox + 1;
1417b6ffaeffSJack Morgenstein for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) {
1418b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw,
1419b6ffaeffSJack Morgenstein zgid_entry.raw, sizeof(zgid_entry)))
1420b6ffaeffSJack Morgenstein continue;
1421b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw,
1422b6ffaeffSJack Morgenstein sizeof(gid_entry_mbox->raw))) {
1423b6ffaeffSJack Morgenstein /* found duplicate */
1424b6ffaeffSJack Morgenstein return -EINVAL;
1425b6ffaeffSJack Morgenstein }
1426b6ffaeffSJack Morgenstein }
1427b6ffaeffSJack Morgenstein }
1428b6ffaeffSJack Morgenstein
1429b6ffaeffSJack Morgenstein /* 2. Check that do not have duplicates in OTHER
1430b6ffaeffSJack Morgenstein * entries in the port GID table
1431b6ffaeffSJack Morgenstein */
1432111c6094SJack Morgenstein
1433111c6094SJack Morgenstein mutex_lock(&(priv->port[port].gid_table.mutex));
14349cd59352SJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
1435b6ffaeffSJack Morgenstein if (i >= base && i < base + num_gids)
1436b6ffaeffSJack Morgenstein continue; /* don't compare to slave's current gids */
1437111c6094SJack Morgenstein gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i];
1438b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry)))
1439b6ffaeffSJack Morgenstein continue;
1440b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1441b6ffaeffSJack Morgenstein for (j = 0; j < num_gids; gid_entry_mbox++, j++) {
1442b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
1443b6ffaeffSJack Morgenstein sizeof(zgid_entry)))
1444b6ffaeffSJack Morgenstein continue;
1445b6ffaeffSJack Morgenstein if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw,
1446b6ffaeffSJack Morgenstein sizeof(gid_entry_tbl->raw))) {
1447b6ffaeffSJack Morgenstein /* found duplicate */
14481a91de28SJoe Perches mlx4_warn(dev, "requested gid entry for slave:%d is a duplicate of gid at index %d\n",
14499cd59352SJack Morgenstein slave, i);
1450111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex));
1451b6ffaeffSJack Morgenstein return -EINVAL;
14529cd59352SJack Morgenstein }
14539cd59352SJack Morgenstein }
14549cd59352SJack Morgenstein }
1455b6ffaeffSJack Morgenstein
1456b6ffaeffSJack Morgenstein /* insert slave GIDs with memcpy, starting at slave's base index */
1457b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1458b6ffaeffSJack Morgenstein for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++)
1459111c6094SJack Morgenstein memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
1460111c6094SJack Morgenstein gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE);
1461b6ffaeffSJack Morgenstein
1462b6ffaeffSJack Morgenstein /* Now, copy roce port gids table to current mailbox for passing to FW */
1463b6ffaeffSJack Morgenstein gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1464b6ffaeffSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
1465111c6094SJack Morgenstein memcpy(gid_entry_mbox->raw,
1466111c6094SJack Morgenstein priv->port[port].gid_table.roce_gids[i].raw,
1467111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE);
1468b6ffaeffSJack Morgenstein
1469111c6094SJack Morgenstein err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
1470111c6094SJack Morgenstein MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1471111c6094SJack Morgenstein MLX4_CMD_NATIVE);
1472111c6094SJack Morgenstein mutex_unlock(&(priv->port[port].gid_table.mutex));
1473111c6094SJack Morgenstein return err;
1474ffe455adSEugenia Emantayev }
1475111c6094SJack Morgenstein
1476111c6094SJack Morgenstein return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
1477ffe455adSEugenia Emantayev MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1478ffe455adSEugenia Emantayev MLX4_CMD_NATIVE);
1479ffe455adSEugenia Emantayev }
1480ffe455adSEugenia Emantayev
148151af33cfSIdo Shamay /* Slaves are not allowed to SET_PORT beacon (LED) blink */
148251af33cfSIdo Shamay if (op_mod == MLX4_SET_PORT_BEACON_OPCODE) {
148351af33cfSIdo Shamay mlx4_warn(dev, "denying SET_PORT Beacon slave:%d\n", slave);
148451af33cfSIdo Shamay return -EPERM;
148551af33cfSIdo Shamay }
148651af33cfSIdo Shamay
1487ffe455adSEugenia Emantayev /* For IB, we only consider:
1488ffe455adSEugenia Emantayev * - The capability mask, which is set to the aggregate of all
1489ffe455adSEugenia Emantayev * slave function capabilities
1490ffe455adSEugenia Emantayev * - The QKey violatin counter - reset according to each request.
1491ffe455adSEugenia Emantayev */
1492ffe455adSEugenia Emantayev
1493ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
1494ffe455adSEugenia Emantayev reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40;
1495ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[2];
1496ffe455adSEugenia Emantayev } else {
1497ffe455adSEugenia Emantayev reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1;
1498ffe455adSEugenia Emantayev new_cap_mask = ((__be32 *) inbox->buf)[1];
1499ffe455adSEugenia Emantayev }
1500ffe455adSEugenia Emantayev
1501efcd235dSJack Morgenstein /* slave may not set the IS_SM capability for the port */
1502efcd235dSJack Morgenstein if (slave != mlx4_master_func_num(dev) &&
1503efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM))
1504efcd235dSJack Morgenstein return -EINVAL;
1505efcd235dSJack Morgenstein
1506efcd235dSJack Morgenstein /* No DEV_MGMT in multifunc mode */
1507efcd235dSJack Morgenstein if (mlx4_is_mfunc(dev) &&
1508efcd235dSJack Morgenstein (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP))
1509efcd235dSJack Morgenstein return -EINVAL;
1510efcd235dSJack Morgenstein
1511ffe455adSEugenia Emantayev agg_cap_mask = 0;
1512ffe455adSEugenia Emantayev slave_cap_mask =
1513ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port];
1514ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask;
1515ffe455adSEugenia Emantayev for (i = 0; i < dev->num_slaves; i++)
1516ffe455adSEugenia Emantayev agg_cap_mask |=
1517ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[i].ib_cap_mask[port];
1518ffe455adSEugenia Emantayev
1519ffe455adSEugenia Emantayev /* only clear mailbox for guests. Master may be setting
1520ffe455adSEugenia Emantayev * MTU or PKEY table size
1521ffe455adSEugenia Emantayev */
1522ffe455adSEugenia Emantayev if (slave != dev->caps.function)
1523ffe455adSEugenia Emantayev memset(inbox->buf, 0, 256);
1524ffe455adSEugenia Emantayev if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
1525edc4a67eSJack Morgenstein *(u8 *) inbox->buf |= !!reset_qkey_viols << 6;
1526ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[2] = agg_cap_mask;
1527ffe455adSEugenia Emantayev } else {
1528edc4a67eSJack Morgenstein ((u8 *) inbox->buf)[3] |= !!reset_qkey_viols;
1529ffe455adSEugenia Emantayev ((__be32 *) inbox->buf)[1] = agg_cap_mask;
1530ffe455adSEugenia Emantayev }
1531ffe455adSEugenia Emantayev
1532ffe455adSEugenia Emantayev err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT,
1533ffe455adSEugenia Emantayev MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
1534ffe455adSEugenia Emantayev if (err)
1535ffe455adSEugenia Emantayev priv->mfunc.master.slave_state[slave].ib_cap_mask[port] =
1536ffe455adSEugenia Emantayev slave_cap_mask;
1537ffe455adSEugenia Emantayev return err;
1538ffe455adSEugenia Emantayev }
1539ffe455adSEugenia Emantayev
mlx4_SET_PORT_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)1540ffe455adSEugenia Emantayev int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave,
1541ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr,
1542ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox,
1543ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox,
1544ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd)
1545ffe455adSEugenia Emantayev {
1546449fc488SMatan Barak int port = mlx4_slave_convert_port(
1547449fc488SMatan Barak dev, slave, vhcr->in_modifier & 0xFF);
1548449fc488SMatan Barak
1549449fc488SMatan Barak if (port < 0)
1550449fc488SMatan Barak return -EINVAL;
1551449fc488SMatan Barak
1552449fc488SMatan Barak vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) |
1553449fc488SMatan Barak (port & 0xFF);
1554449fc488SMatan Barak
1555ffe455adSEugenia Emantayev return mlx4_common_set_port(dev, slave, vhcr->in_modifier,
1556ffe455adSEugenia Emantayev vhcr->op_modifier, inbox);
1557ffe455adSEugenia Emantayev }
1558ffe455adSEugenia Emantayev
1559096335b3SOr Gerlitz /* bit locations for set port command with zero op modifier */
1560096335b3SOr Gerlitz enum {
1561096335b3SOr Gerlitz MLX4_SET_PORT_VL_CAP = 4, /* bits 7:4 */
1562096335b3SOr Gerlitz MLX4_SET_PORT_MTU_CAP = 12, /* bits 15:12 */
15636634961cSJack Morgenstein MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20,
1564096335b3SOr Gerlitz MLX4_CHANGE_PORT_VL_CAP = 21,
1565096335b3SOr Gerlitz MLX4_CHANGE_PORT_MTU_CAP = 22,
1566096335b3SOr Gerlitz };
1567096335b3SOr Gerlitz
mlx4_SET_PORT(struct mlx4_dev * dev,u8 port,int pkey_tbl_sz)15686634961cSJack Morgenstein int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz)
15695a2cc190SJeff Kirsher {
15705a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox;
15716634961cSJack Morgenstein int err, vl_cap, pkey_tbl_flag = 0;
15725a2cc190SJeff Kirsher
15735a2cc190SJeff Kirsher if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
15745a2cc190SJeff Kirsher return 0;
15755a2cc190SJeff Kirsher
15765a2cc190SJeff Kirsher mailbox = mlx4_alloc_cmd_mailbox(dev);
15775a2cc190SJeff Kirsher if (IS_ERR(mailbox))
15785a2cc190SJeff Kirsher return PTR_ERR(mailbox);
15795a2cc190SJeff Kirsher
15805a2cc190SJeff Kirsher ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port];
1581096335b3SOr Gerlitz
15826634961cSJack Morgenstein if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) {
15836634961cSJack Morgenstein pkey_tbl_flag = 1;
15846634961cSJack Morgenstein ((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz);
15856634961cSJack Morgenstein }
15866634961cSJack Morgenstein
1587096335b3SOr Gerlitz /* IB VL CAP enum isn't used by the firmware, just numerical values */
1588096335b3SOr Gerlitz for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) {
1589096335b3SOr Gerlitz ((__be32 *) mailbox->buf)[0] = cpu_to_be32(
1590096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_MTU_CAP) |
1591096335b3SOr Gerlitz (1 << MLX4_CHANGE_PORT_VL_CAP) |
15926634961cSJack Morgenstein (pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) |
1593096335b3SOr Gerlitz (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) |
1594096335b3SOr Gerlitz (vl_cap << MLX4_SET_PORT_VL_CAP));
1595a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, port,
1596a130b590SIdo Shamay MLX4_SET_PORT_IB_OPCODE, MLX4_CMD_SET_PORT,
1597f9baff50SJack Morgenstein MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
1598096335b3SOr Gerlitz if (err != -ENOMEM)
1599096335b3SOr Gerlitz break;
1600096335b3SOr Gerlitz }
16015a2cc190SJeff Kirsher
16025a2cc190SJeff Kirsher mlx4_free_cmd_mailbox(dev, mailbox);
16035a2cc190SJeff Kirsher return err;
16045a2cc190SJeff Kirsher }
1605ffe455adSEugenia Emantayev
16061da494cbSMoni Shoua #define SET_PORT_ROCE_2_FLAGS 0x10
16071da494cbSMoni Shoua #define MLX4_SET_PORT_ROCE_V1_V2 0x2
mlx4_SET_PORT_general(struct mlx4_dev * dev,u8 port,int mtu,u8 pptx,u8 pfctx,u8 pprx,u8 pfcrx)1608cb9ffb76SJoerg Roedel int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
1609ffe455adSEugenia Emantayev u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx)
1610ffe455adSEugenia Emantayev {
1611ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox;
1612ffe455adSEugenia Emantayev struct mlx4_set_port_general_context *context;
1613ffe455adSEugenia Emantayev int err;
1614ffe455adSEugenia Emantayev u32 in_mod;
1615ffe455adSEugenia Emantayev
1616ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev);
1617ffe455adSEugenia Emantayev if (IS_ERR(mailbox))
1618ffe455adSEugenia Emantayev return PTR_ERR(mailbox);
1619ffe455adSEugenia Emantayev context = mailbox->buf;
1620ffe455adSEugenia Emantayev context->flags = SET_PORT_GEN_ALL_VALID;
1621ffe455adSEugenia Emantayev context->mtu = cpu_to_be16(mtu);
1622ffe455adSEugenia Emantayev context->pptx = (pptx * (!pfctx)) << 7;
1623ffe455adSEugenia Emantayev context->pfctx = pfctx;
1624ffe455adSEugenia Emantayev context->pprx = (pprx * (!pfcrx)) << 7;
1625ffe455adSEugenia Emantayev context->pfcrx = pfcrx;
1626ffe455adSEugenia Emantayev
16271da494cbSMoni Shoua if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2) {
16281da494cbSMoni Shoua context->flags |= SET_PORT_ROCE_2_FLAGS;
16291da494cbSMoni Shoua context->roce_mode |=
16301da494cbSMoni Shoua MLX4_SET_PORT_ROCE_V1_V2 << 4;
16311da494cbSMoni Shoua }
1632ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
1633a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1634a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1635a130b590SIdo Shamay MLX4_CMD_WRAPPED);
1636ffe455adSEugenia Emantayev
1637ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox);
1638ffe455adSEugenia Emantayev return err;
1639ffe455adSEugenia Emantayev }
1640ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_general);
1641ffe455adSEugenia Emantayev
mlx4_SET_PORT_qpn_calc(struct mlx4_dev * dev,u8 port,u32 base_qpn,u8 promisc)1642cb9ffb76SJoerg Roedel int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
1643ffe455adSEugenia Emantayev u8 promisc)
1644ffe455adSEugenia Emantayev {
1645ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *mailbox;
1646ffe455adSEugenia Emantayev struct mlx4_set_port_rqp_calc_context *context;
1647ffe455adSEugenia Emantayev int err;
1648ffe455adSEugenia Emantayev u32 in_mod;
1649ffe455adSEugenia Emantayev u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ?
1650ffe455adSEugenia Emantayev MCAST_DIRECT : MCAST_DEFAULT;
1651ffe455adSEugenia Emantayev
1652c96d97f4SHadar Hen Zion if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
1653ffe455adSEugenia Emantayev return 0;
1654ffe455adSEugenia Emantayev
1655ffe455adSEugenia Emantayev mailbox = mlx4_alloc_cmd_mailbox(dev);
1656ffe455adSEugenia Emantayev if (IS_ERR(mailbox))
1657ffe455adSEugenia Emantayev return PTR_ERR(mailbox);
1658ffe455adSEugenia Emantayev context = mailbox->buf;
1659ffe455adSEugenia Emantayev context->base_qpn = cpu_to_be32(base_qpn);
1660ffe455adSEugenia Emantayev context->n_mac = dev->caps.log_num_macs;
1661ffe455adSEugenia Emantayev context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT |
1662ffe455adSEugenia Emantayev base_qpn);
1663ffe455adSEugenia Emantayev context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT |
1664ffe455adSEugenia Emantayev base_qpn);
1665ffe455adSEugenia Emantayev context->intra_no_vlan = 0;
1666ffe455adSEugenia Emantayev context->no_vlan = MLX4_NO_VLAN_IDX;
1667ffe455adSEugenia Emantayev context->intra_vlan_miss = 0;
1668ffe455adSEugenia Emantayev context->vlan_miss = MLX4_VLAN_MISS_IDX;
1669ffe455adSEugenia Emantayev
1670ffe455adSEugenia Emantayev in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port;
1671a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1672a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1673a130b590SIdo Shamay MLX4_CMD_WRAPPED);
1674ffe455adSEugenia Emantayev
1675ffe455adSEugenia Emantayev mlx4_free_cmd_mailbox(dev, mailbox);
1676ffe455adSEugenia Emantayev return err;
1677ffe455adSEugenia Emantayev }
1678ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc);
1679ffe455adSEugenia Emantayev
mlx4_SET_PORT_user_mtu(struct mlx4_dev * dev,u8 port,u16 user_mtu)168040fb4fc1SShaker Daibes int mlx4_SET_PORT_user_mtu(struct mlx4_dev *dev, u8 port, u16 user_mtu)
168140fb4fc1SShaker Daibes {
168240fb4fc1SShaker Daibes struct mlx4_cmd_mailbox *mailbox;
168340fb4fc1SShaker Daibes struct mlx4_set_port_general_context *context;
168440fb4fc1SShaker Daibes u32 in_mod;
168540fb4fc1SShaker Daibes int err;
168640fb4fc1SShaker Daibes
168740fb4fc1SShaker Daibes mailbox = mlx4_alloc_cmd_mailbox(dev);
168840fb4fc1SShaker Daibes if (IS_ERR(mailbox))
168940fb4fc1SShaker Daibes return PTR_ERR(mailbox);
169040fb4fc1SShaker Daibes context = mailbox->buf;
169140fb4fc1SShaker Daibes context->flags2 |= MLX4_FLAG2_V_USER_MTU_MASK;
169240fb4fc1SShaker Daibes context->user_mtu = cpu_to_be16(user_mtu);
169340fb4fc1SShaker Daibes
169440fb4fc1SShaker Daibes in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
169540fb4fc1SShaker Daibes err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
169640fb4fc1SShaker Daibes MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
169740fb4fc1SShaker Daibes MLX4_CMD_WRAPPED);
169840fb4fc1SShaker Daibes
169940fb4fc1SShaker Daibes mlx4_free_cmd_mailbox(dev, mailbox);
170040fb4fc1SShaker Daibes return err;
170140fb4fc1SShaker Daibes }
170240fb4fc1SShaker Daibes EXPORT_SYMBOL(mlx4_SET_PORT_user_mtu);
170340fb4fc1SShaker Daibes
mlx4_SET_PORT_user_mac(struct mlx4_dev * dev,u8 port,u8 * user_mac)1704be599603SMoshe Shemesh int mlx4_SET_PORT_user_mac(struct mlx4_dev *dev, u8 port, u8 *user_mac)
1705be599603SMoshe Shemesh {
1706be599603SMoshe Shemesh struct mlx4_cmd_mailbox *mailbox;
1707be599603SMoshe Shemesh struct mlx4_set_port_general_context *context;
1708be599603SMoshe Shemesh u32 in_mod;
1709be599603SMoshe Shemesh int err;
1710be599603SMoshe Shemesh
1711be599603SMoshe Shemesh mailbox = mlx4_alloc_cmd_mailbox(dev);
1712be599603SMoshe Shemesh if (IS_ERR(mailbox))
1713be599603SMoshe Shemesh return PTR_ERR(mailbox);
1714be599603SMoshe Shemesh context = mailbox->buf;
1715be599603SMoshe Shemesh context->flags2 |= MLX4_FLAG2_V_USER_MAC_MASK;
1716be599603SMoshe Shemesh memcpy(context->user_mac, user_mac, sizeof(context->user_mac));
1717be599603SMoshe Shemesh
1718be599603SMoshe Shemesh in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
1719be599603SMoshe Shemesh err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1720be599603SMoshe Shemesh MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1721be599603SMoshe Shemesh MLX4_CMD_NATIVE);
1722be599603SMoshe Shemesh
1723be599603SMoshe Shemesh mlx4_free_cmd_mailbox(dev, mailbox);
1724be599603SMoshe Shemesh return err;
1725be599603SMoshe Shemesh }
1726be599603SMoshe Shemesh EXPORT_SYMBOL(mlx4_SET_PORT_user_mac);
1727be599603SMoshe Shemesh
mlx4_SET_PORT_fcs_check(struct mlx4_dev * dev,u8 port,u8 ignore_fcs_value)172878500b8cSMuhammad Mahajna int mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, u8 ignore_fcs_value)
172978500b8cSMuhammad Mahajna {
173078500b8cSMuhammad Mahajna struct mlx4_cmd_mailbox *mailbox;
173178500b8cSMuhammad Mahajna struct mlx4_set_port_general_context *context;
173278500b8cSMuhammad Mahajna u32 in_mod;
173378500b8cSMuhammad Mahajna int err;
173478500b8cSMuhammad Mahajna
173578500b8cSMuhammad Mahajna mailbox = mlx4_alloc_cmd_mailbox(dev);
173678500b8cSMuhammad Mahajna if (IS_ERR(mailbox))
173778500b8cSMuhammad Mahajna return PTR_ERR(mailbox);
173878500b8cSMuhammad Mahajna context = mailbox->buf;
173940fb4fc1SShaker Daibes context->flags2 |= MLX4_FLAG2_V_IGNORE_FCS_MASK;
174078500b8cSMuhammad Mahajna if (ignore_fcs_value)
174178500b8cSMuhammad Mahajna context->ignore_fcs |= MLX4_IGNORE_FCS_MASK;
174278500b8cSMuhammad Mahajna else
174378500b8cSMuhammad Mahajna context->ignore_fcs &= ~MLX4_IGNORE_FCS_MASK;
174478500b8cSMuhammad Mahajna
174578500b8cSMuhammad Mahajna in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
174678500b8cSMuhammad Mahajna err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
174778500b8cSMuhammad Mahajna MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
174878500b8cSMuhammad Mahajna
174978500b8cSMuhammad Mahajna mlx4_free_cmd_mailbox(dev, mailbox);
175078500b8cSMuhammad Mahajna return err;
175178500b8cSMuhammad Mahajna }
175278500b8cSMuhammad Mahajna EXPORT_SYMBOL(mlx4_SET_PORT_fcs_check);
175378500b8cSMuhammad Mahajna
17547ffdf726SOr Gerlitz enum {
17557ffdf726SOr Gerlitz VXLAN_ENABLE_MODIFY = 1 << 7,
17567ffdf726SOr Gerlitz VXLAN_STEERING_MODIFY = 1 << 6,
17577ffdf726SOr Gerlitz
17587ffdf726SOr Gerlitz VXLAN_ENABLE = 1 << 7,
17597ffdf726SOr Gerlitz };
17607ffdf726SOr Gerlitz
17617ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context {
17627ffdf726SOr Gerlitz u32 reserved1;
17637ffdf726SOr Gerlitz u8 modify_flags;
17647ffdf726SOr Gerlitz u8 reserved2;
17657ffdf726SOr Gerlitz u8 enable_flags;
17667ffdf726SOr Gerlitz u8 steering;
17677ffdf726SOr Gerlitz };
17687ffdf726SOr Gerlitz
mlx4_SET_PORT_VXLAN(struct mlx4_dev * dev,u8 port,u8 steering,int enable)17691b136de1SOr Gerlitz int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable)
17707ffdf726SOr Gerlitz {
17717ffdf726SOr Gerlitz int err;
17727ffdf726SOr Gerlitz u32 in_mod;
17737ffdf726SOr Gerlitz struct mlx4_cmd_mailbox *mailbox;
17747ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context *context;
17757ffdf726SOr Gerlitz
17767ffdf726SOr Gerlitz mailbox = mlx4_alloc_cmd_mailbox(dev);
17777ffdf726SOr Gerlitz if (IS_ERR(mailbox))
17787ffdf726SOr Gerlitz return PTR_ERR(mailbox);
17797ffdf726SOr Gerlitz context = mailbox->buf;
17807ffdf726SOr Gerlitz memset(context, 0, sizeof(*context));
17817ffdf726SOr Gerlitz
17827ffdf726SOr Gerlitz context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY;
17831b136de1SOr Gerlitz if (enable)
17847ffdf726SOr Gerlitz context->enable_flags = VXLAN_ENABLE;
17857ffdf726SOr Gerlitz context->steering = steering;
17867ffdf726SOr Gerlitz
17877ffdf726SOr Gerlitz in_mod = MLX4_SET_PORT_VXLAN << 8 | port;
1788a130b590SIdo Shamay err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1789a130b590SIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1790a130b590SIdo Shamay MLX4_CMD_NATIVE);
17917ffdf726SOr Gerlitz
17927ffdf726SOr Gerlitz mlx4_free_cmd_mailbox(dev, mailbox);
17937ffdf726SOr Gerlitz return err;
17947ffdf726SOr Gerlitz }
17957ffdf726SOr Gerlitz EXPORT_SYMBOL(mlx4_SET_PORT_VXLAN);
17967ffdf726SOr Gerlitz
mlx4_SET_PORT_BEACON(struct mlx4_dev * dev,u8 port,u16 time)179751af33cfSIdo Shamay int mlx4_SET_PORT_BEACON(struct mlx4_dev *dev, u8 port, u16 time)
179851af33cfSIdo Shamay {
179951af33cfSIdo Shamay int err;
180051af33cfSIdo Shamay struct mlx4_cmd_mailbox *mailbox;
180151af33cfSIdo Shamay
180251af33cfSIdo Shamay mailbox = mlx4_alloc_cmd_mailbox(dev);
180351af33cfSIdo Shamay if (IS_ERR(mailbox))
180451af33cfSIdo Shamay return PTR_ERR(mailbox);
180551af33cfSIdo Shamay
180651af33cfSIdo Shamay *((__be32 *)mailbox->buf) = cpu_to_be32(time);
180751af33cfSIdo Shamay
180851af33cfSIdo Shamay err = mlx4_cmd(dev, mailbox->dma, port, MLX4_SET_PORT_BEACON_OPCODE,
180951af33cfSIdo Shamay MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
181051af33cfSIdo Shamay MLX4_CMD_NATIVE);
181151af33cfSIdo Shamay
181251af33cfSIdo Shamay mlx4_free_cmd_mailbox(dev, mailbox);
181351af33cfSIdo Shamay return err;
181451af33cfSIdo Shamay }
181551af33cfSIdo Shamay EXPORT_SYMBOL(mlx4_SET_PORT_BEACON);
181651af33cfSIdo Shamay
mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)1817ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1818ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr,
1819ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox,
1820ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox,
1821ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd)
1822ffe455adSEugenia Emantayev {
1823ffe455adSEugenia Emantayev int err = 0;
1824ffe455adSEugenia Emantayev
1825ffe455adSEugenia Emantayev return err;
1826ffe455adSEugenia Emantayev }
1827ffe455adSEugenia Emantayev
mlx4_SET_MCAST_FLTR(struct mlx4_dev * dev,u8 port,u64 mac,u64 clear,u8 mode)1828ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port,
1829ffe455adSEugenia Emantayev u64 mac, u64 clear, u8 mode)
1830ffe455adSEugenia Emantayev {
1831ffe455adSEugenia Emantayev return mlx4_cmd(dev, (mac | (clear << 63)), port, mode,
1832ffe455adSEugenia Emantayev MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B,
1833ffe455adSEugenia Emantayev MLX4_CMD_WRAPPED);
1834ffe455adSEugenia Emantayev }
1835ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR);
1836ffe455adSEugenia Emantayev
mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)1837ffe455adSEugenia Emantayev int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1838ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr,
1839ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox,
1840ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox,
1841ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd)
1842ffe455adSEugenia Emantayev {
1843ffe455adSEugenia Emantayev int err = 0;
1844ffe455adSEugenia Emantayev
1845ffe455adSEugenia Emantayev return err;
1846ffe455adSEugenia Emantayev }
1847ffe455adSEugenia Emantayev
mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)1848ffe455adSEugenia Emantayev int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave,
1849ffe455adSEugenia Emantayev struct mlx4_vhcr *vhcr,
1850ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *inbox,
1851ffe455adSEugenia Emantayev struct mlx4_cmd_mailbox *outbox,
1852ffe455adSEugenia Emantayev struct mlx4_cmd_info *cmd)
1853ffe455adSEugenia Emantayev {
185435fb9afbSEugenia Emantayev return 0;
1855ffe455adSEugenia Emantayev }
185693ece0c1SEugenia Emantayev
mlx4_get_slave_from_roce_gid(struct mlx4_dev * dev,int port,u8 * gid,int * slave_id)18579cd59352SJack Morgenstein int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
18589cd59352SJack Morgenstein int *slave_id)
18596ee51a4eSJack Morgenstein {
18606ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev);
18616ee51a4eSJack Morgenstein int i, found_ix = -1;
1862b6ffaeffSJack Morgenstein int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
1863449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport;
1864449fc488SMatan Barak unsigned num_vfs;
1865449fc488SMatan Barak int slave_gid;
18666ee51a4eSJack Morgenstein
18676ee51a4eSJack Morgenstein if (!mlx4_is_mfunc(dev))
18686ee51a4eSJack Morgenstein return -EINVAL;
18696ee51a4eSJack Morgenstein
1870449fc488SMatan Barak slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1871872bf2fbSYishai Hadas num_vfs = bitmap_weight(slaves_pport.slaves,
1872872bf2fbSYishai Hadas dev->persist->num_vfs + 1) - 1;
1873449fc488SMatan Barak
18746ee51a4eSJack Morgenstein for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
1875111c6094SJack Morgenstein if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid,
1876111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE)) {
18776ee51a4eSJack Morgenstein found_ix = i;
18786ee51a4eSJack Morgenstein break;
18796ee51a4eSJack Morgenstein }
18806ee51a4eSJack Morgenstein }
18816ee51a4eSJack Morgenstein
1882b6ffaeffSJack Morgenstein if (found_ix >= 0) {
18830254bc82SMatan Barak /* Calculate a slave_gid which is the slave number in the gid
18840254bc82SMatan Barak * table and not a globally unique slave number.
18850254bc82SMatan Barak */
1886b6ffaeffSJack Morgenstein if (found_ix < MLX4_ROCE_PF_GIDS)
1887449fc488SMatan Barak slave_gid = 0;
1888449fc488SMatan Barak else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) *
1889449fc488SMatan Barak (vf_gids / num_vfs + 1))
1890449fc488SMatan Barak slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) /
1891449fc488SMatan Barak (vf_gids / num_vfs + 1)) + 1;
1892b6ffaeffSJack Morgenstein else
1893449fc488SMatan Barak slave_gid =
1894b6ffaeffSJack Morgenstein ((found_ix - MLX4_ROCE_PF_GIDS -
1895449fc488SMatan Barak ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) /
1896449fc488SMatan Barak (vf_gids / num_vfs)) + vf_gids % num_vfs + 1;
1897449fc488SMatan Barak
18980254bc82SMatan Barak /* Calculate the globally unique slave id */
1899449fc488SMatan Barak if (slave_gid) {
1900449fc488SMatan Barak struct mlx4_active_ports exclusive_ports;
1901449fc488SMatan Barak struct mlx4_active_ports actv_ports;
1902449fc488SMatan Barak struct mlx4_slaves_pport slaves_pport_actv;
1903449fc488SMatan Barak unsigned max_port_p_one;
19040254bc82SMatan Barak int num_vfs_before = 0;
19050254bc82SMatan Barak int candidate_slave_gid;
1906449fc488SMatan Barak
19070254bc82SMatan Barak /* Calculate how many VFs are on the previous port, if exists */
1908449fc488SMatan Barak for (i = 1; i < port; i++) {
1909449fc488SMatan Barak bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
19100254bc82SMatan Barak set_bit(i - 1, exclusive_ports.ports);
1911449fc488SMatan Barak slaves_pport_actv =
1912449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv(
1913449fc488SMatan Barak dev, &exclusive_ports);
19140254bc82SMatan Barak num_vfs_before += bitmap_weight(
1915449fc488SMatan Barak slaves_pport_actv.slaves,
1916872bf2fbSYishai Hadas dev->persist->num_vfs + 1);
1917449fc488SMatan Barak }
1918449fc488SMatan Barak
19190254bc82SMatan Barak /* candidate_slave_gid isn't necessarily the correct slave, but
19200254bc82SMatan Barak * it has the same number of ports and is assigned to the same
19210254bc82SMatan Barak * ports as the real slave we're looking for. On dual port VF,
19220254bc82SMatan Barak * slave_gid = [single port VFs on port <port>] +
19230254bc82SMatan Barak * [offset of the current slave from the first dual port VF] +
19240254bc82SMatan Barak * 1 (for the PF).
19250254bc82SMatan Barak */
19260254bc82SMatan Barak candidate_slave_gid = slave_gid + num_vfs_before;
19270254bc82SMatan Barak
19280254bc82SMatan Barak actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid);
1929449fc488SMatan Barak max_port_p_one = find_first_bit(
1930449fc488SMatan Barak actv_ports.ports, dev->caps.num_ports) +
1931449fc488SMatan Barak bitmap_weight(actv_ports.ports,
1932449fc488SMatan Barak dev->caps.num_ports) + 1;
1933449fc488SMatan Barak
19340254bc82SMatan Barak /* Calculate the real slave number */
1935449fc488SMatan Barak for (i = 1; i < max_port_p_one; i++) {
1936449fc488SMatan Barak if (i == port)
1937449fc488SMatan Barak continue;
1938449fc488SMatan Barak bitmap_zero(exclusive_ports.ports,
1939449fc488SMatan Barak dev->caps.num_ports);
1940449fc488SMatan Barak set_bit(i - 1, exclusive_ports.ports);
1941449fc488SMatan Barak slaves_pport_actv =
1942449fc488SMatan Barak mlx4_phys_to_slaves_pport_actv(
1943449fc488SMatan Barak dev, &exclusive_ports);
1944449fc488SMatan Barak slave_gid += bitmap_weight(
1945449fc488SMatan Barak slaves_pport_actv.slaves,
1946872bf2fbSYishai Hadas dev->persist->num_vfs + 1);
1947449fc488SMatan Barak }
1948449fc488SMatan Barak }
1949449fc488SMatan Barak *slave_id = slave_gid;
1950b6ffaeffSJack Morgenstein }
19516ee51a4eSJack Morgenstein
19526ee51a4eSJack Morgenstein return (found_ix >= 0) ? 0 : -EINVAL;
19536ee51a4eSJack Morgenstein }
19546ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid);
19556ee51a4eSJack Morgenstein
mlx4_get_roce_gid_from_slave(struct mlx4_dev * dev,int port,int slave_id,u8 * gid)19569cd59352SJack Morgenstein int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id,
19579cd59352SJack Morgenstein u8 *gid)
19586ee51a4eSJack Morgenstein {
19596ee51a4eSJack Morgenstein struct mlx4_priv *priv = mlx4_priv(dev);
19606ee51a4eSJack Morgenstein
19616ee51a4eSJack Morgenstein if (!mlx4_is_master(dev))
19626ee51a4eSJack Morgenstein return -EINVAL;
19636ee51a4eSJack Morgenstein
1964111c6094SJack Morgenstein memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw,
1965111c6094SJack Morgenstein MLX4_ROCE_GID_ENTRY_SIZE);
19666ee51a4eSJack Morgenstein return 0;
19676ee51a4eSJack Morgenstein }
19686ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
196932a173c7SSaeed Mahameed
197032a173c7SSaeed Mahameed /* Cable Module Info */
197132a173c7SSaeed Mahameed #define MODULE_INFO_MAX_READ 48
197232a173c7SSaeed Mahameed
197332a173c7SSaeed Mahameed #define I2C_ADDR_LOW 0x50
197432a173c7SSaeed Mahameed #define I2C_ADDR_HIGH 0x51
197532a173c7SSaeed Mahameed #define I2C_PAGE_SIZE 256
1976*db825feeSVladyslav Tarasiuk #define I2C_HIGH_PAGE_SIZE 128
197732a173c7SSaeed Mahameed
197832a173c7SSaeed Mahameed /* Module Info Data */
197932a173c7SSaeed Mahameed struct mlx4_cable_info {
198032a173c7SSaeed Mahameed u8 i2c_addr;
198132a173c7SSaeed Mahameed u8 page_num;
198232a173c7SSaeed Mahameed __be16 dev_mem_address;
198332a173c7SSaeed Mahameed __be16 reserved1;
198432a173c7SSaeed Mahameed __be16 size;
198532a173c7SSaeed Mahameed __be32 reserved2[2];
198632a173c7SSaeed Mahameed u8 data[MODULE_INFO_MAX_READ];
198732a173c7SSaeed Mahameed };
198832a173c7SSaeed Mahameed
198932a173c7SSaeed Mahameed enum cable_info_err {
199032a173c7SSaeed Mahameed CABLE_INF_INV_PORT = 0x1,
199132a173c7SSaeed Mahameed CABLE_INF_OP_NOSUP = 0x2,
199232a173c7SSaeed Mahameed CABLE_INF_NOT_CONN = 0x3,
199332a173c7SSaeed Mahameed CABLE_INF_NO_EEPRM = 0x4,
199432a173c7SSaeed Mahameed CABLE_INF_PAGE_ERR = 0x5,
199532a173c7SSaeed Mahameed CABLE_INF_INV_ADDR = 0x6,
199632a173c7SSaeed Mahameed CABLE_INF_I2C_ADDR = 0x7,
199732a173c7SSaeed Mahameed CABLE_INF_QSFP_VIO = 0x8,
199832a173c7SSaeed Mahameed CABLE_INF_I2C_BUSY = 0x9,
199932a173c7SSaeed Mahameed };
200032a173c7SSaeed Mahameed
200132a173c7SSaeed Mahameed #define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF)
200232a173c7SSaeed Mahameed
cable_info_mad_err_str(u16 mad_status)200332a173c7SSaeed Mahameed static inline const char *cable_info_mad_err_str(u16 mad_status)
200432a173c7SSaeed Mahameed {
200532a173c7SSaeed Mahameed u8 err = MAD_STATUS_2_CABLE_ERR(mad_status);
200632a173c7SSaeed Mahameed
200732a173c7SSaeed Mahameed switch (err) {
200832a173c7SSaeed Mahameed case CABLE_INF_INV_PORT:
200932a173c7SSaeed Mahameed return "invalid port selected";
201032a173c7SSaeed Mahameed case CABLE_INF_OP_NOSUP:
201132a173c7SSaeed Mahameed return "operation not supported for this port (the port is of type CX4 or internal)";
201232a173c7SSaeed Mahameed case CABLE_INF_NOT_CONN:
201332a173c7SSaeed Mahameed return "cable is not connected";
201432a173c7SSaeed Mahameed case CABLE_INF_NO_EEPRM:
201532a173c7SSaeed Mahameed return "the connected cable has no EPROM (passive copper cable)";
201632a173c7SSaeed Mahameed case CABLE_INF_PAGE_ERR:
201732a173c7SSaeed Mahameed return "page number is greater than 15";
201832a173c7SSaeed Mahameed case CABLE_INF_INV_ADDR:
201932a173c7SSaeed Mahameed return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)";
202032a173c7SSaeed Mahameed case CABLE_INF_I2C_ADDR:
202132a173c7SSaeed Mahameed return "invalid I2C slave address";
202232a173c7SSaeed Mahameed case CABLE_INF_QSFP_VIO:
202332a173c7SSaeed Mahameed return "at least one cable violates the QSFP specification and ignores the modsel signal";
202432a173c7SSaeed Mahameed case CABLE_INF_I2C_BUSY:
202532a173c7SSaeed Mahameed return "I2C bus is constantly busy";
202632a173c7SSaeed Mahameed }
202732a173c7SSaeed Mahameed return "Unknown Error";
202832a173c7SSaeed Mahameed }
202932a173c7SSaeed Mahameed
mlx4_get_module_id(struct mlx4_dev * dev,u8 port,u8 * module_id)2030*db825feeSVladyslav Tarasiuk static int mlx4_get_module_id(struct mlx4_dev *dev, u8 port, u8 *module_id)
2031*db825feeSVladyslav Tarasiuk {
2032*db825feeSVladyslav Tarasiuk struct mlx4_cmd_mailbox *inbox, *outbox;
2033*db825feeSVladyslav Tarasiuk struct mlx4_mad_ifc *inmad, *outmad;
2034*db825feeSVladyslav Tarasiuk struct mlx4_cable_info *cable_info;
2035*db825feeSVladyslav Tarasiuk int ret;
2036*db825feeSVladyslav Tarasiuk
2037*db825feeSVladyslav Tarasiuk inbox = mlx4_alloc_cmd_mailbox(dev);
2038*db825feeSVladyslav Tarasiuk if (IS_ERR(inbox))
2039*db825feeSVladyslav Tarasiuk return PTR_ERR(inbox);
2040*db825feeSVladyslav Tarasiuk
2041*db825feeSVladyslav Tarasiuk outbox = mlx4_alloc_cmd_mailbox(dev);
2042*db825feeSVladyslav Tarasiuk if (IS_ERR(outbox)) {
2043*db825feeSVladyslav Tarasiuk mlx4_free_cmd_mailbox(dev, inbox);
2044*db825feeSVladyslav Tarasiuk return PTR_ERR(outbox);
2045*db825feeSVladyslav Tarasiuk }
2046*db825feeSVladyslav Tarasiuk
2047*db825feeSVladyslav Tarasiuk inmad = (struct mlx4_mad_ifc *)(inbox->buf);
2048*db825feeSVladyslav Tarasiuk outmad = (struct mlx4_mad_ifc *)(outbox->buf);
2049*db825feeSVladyslav Tarasiuk
2050*db825feeSVladyslav Tarasiuk inmad->method = 0x1; /* Get */
2051*db825feeSVladyslav Tarasiuk inmad->class_version = 0x1;
2052*db825feeSVladyslav Tarasiuk inmad->mgmt_class = 0x1;
2053*db825feeSVladyslav Tarasiuk inmad->base_version = 0x1;
2054*db825feeSVladyslav Tarasiuk inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */
2055*db825feeSVladyslav Tarasiuk
2056*db825feeSVladyslav Tarasiuk cable_info = (struct mlx4_cable_info *)inmad->data;
2057*db825feeSVladyslav Tarasiuk cable_info->dev_mem_address = 0;
2058*db825feeSVladyslav Tarasiuk cable_info->page_num = 0;
2059*db825feeSVladyslav Tarasiuk cable_info->i2c_addr = I2C_ADDR_LOW;
2060*db825feeSVladyslav Tarasiuk cable_info->size = cpu_to_be16(1);
2061*db825feeSVladyslav Tarasiuk
2062*db825feeSVladyslav Tarasiuk ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
2063*db825feeSVladyslav Tarasiuk MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
2064*db825feeSVladyslav Tarasiuk MLX4_CMD_NATIVE);
2065*db825feeSVladyslav Tarasiuk if (ret)
2066*db825feeSVladyslav Tarasiuk goto out;
2067*db825feeSVladyslav Tarasiuk
2068*db825feeSVladyslav Tarasiuk if (be16_to_cpu(outmad->status)) {
2069*db825feeSVladyslav Tarasiuk /* Mad returned with bad status */
2070*db825feeSVladyslav Tarasiuk ret = be16_to_cpu(outmad->status);
2071*db825feeSVladyslav Tarasiuk mlx4_warn(dev,
2072*db825feeSVladyslav Tarasiuk "MLX4_CMD_MAD_IFC Get Module ID attr(%x) port(%d) i2c_addr(%x) offset(%d) size(%d): Response Mad Status(%x) - %s\n",
2073*db825feeSVladyslav Tarasiuk 0xFF60, port, I2C_ADDR_LOW, 0, 1, ret,
2074*db825feeSVladyslav Tarasiuk cable_info_mad_err_str(ret));
2075*db825feeSVladyslav Tarasiuk ret = -ret;
2076*db825feeSVladyslav Tarasiuk goto out;
2077*db825feeSVladyslav Tarasiuk }
2078*db825feeSVladyslav Tarasiuk cable_info = (struct mlx4_cable_info *)outmad->data;
2079*db825feeSVladyslav Tarasiuk *module_id = cable_info->data[0];
2080*db825feeSVladyslav Tarasiuk out:
2081*db825feeSVladyslav Tarasiuk mlx4_free_cmd_mailbox(dev, inbox);
2082*db825feeSVladyslav Tarasiuk mlx4_free_cmd_mailbox(dev, outbox);
2083*db825feeSVladyslav Tarasiuk return ret;
2084*db825feeSVladyslav Tarasiuk }
2085*db825feeSVladyslav Tarasiuk
mlx4_sfp_eeprom_params_set(u8 * i2c_addr,u8 * page_num,u16 * offset)2086*db825feeSVladyslav Tarasiuk static void mlx4_sfp_eeprom_params_set(u8 *i2c_addr, u8 *page_num, u16 *offset)
2087*db825feeSVladyslav Tarasiuk {
2088*db825feeSVladyslav Tarasiuk *i2c_addr = I2C_ADDR_LOW;
2089*db825feeSVladyslav Tarasiuk *page_num = 0;
2090*db825feeSVladyslav Tarasiuk
2091*db825feeSVladyslav Tarasiuk if (*offset < I2C_PAGE_SIZE)
2092*db825feeSVladyslav Tarasiuk return;
2093*db825feeSVladyslav Tarasiuk
2094*db825feeSVladyslav Tarasiuk *i2c_addr = I2C_ADDR_HIGH;
2095*db825feeSVladyslav Tarasiuk *offset -= I2C_PAGE_SIZE;
2096*db825feeSVladyslav Tarasiuk }
2097*db825feeSVladyslav Tarasiuk
mlx4_qsfp_eeprom_params_set(u8 * i2c_addr,u8 * page_num,u16 * offset)2098*db825feeSVladyslav Tarasiuk static void mlx4_qsfp_eeprom_params_set(u8 *i2c_addr, u8 *page_num, u16 *offset)
2099*db825feeSVladyslav Tarasiuk {
2100*db825feeSVladyslav Tarasiuk /* Offsets 0-255 belong to page 0.
2101*db825feeSVladyslav Tarasiuk * Offsets 256-639 belong to pages 01, 02, 03.
2102*db825feeSVladyslav Tarasiuk * For example, offset 400 is page 02: 1 + (400 - 256) / 128 = 2
2103*db825feeSVladyslav Tarasiuk */
2104*db825feeSVladyslav Tarasiuk if (*offset < I2C_PAGE_SIZE)
2105*db825feeSVladyslav Tarasiuk *page_num = 0;
2106*db825feeSVladyslav Tarasiuk else
2107*db825feeSVladyslav Tarasiuk *page_num = 1 + (*offset - I2C_PAGE_SIZE) / I2C_HIGH_PAGE_SIZE;
2108*db825feeSVladyslav Tarasiuk *i2c_addr = I2C_ADDR_LOW;
2109*db825feeSVladyslav Tarasiuk *offset -= *page_num * I2C_HIGH_PAGE_SIZE;
2110*db825feeSVladyslav Tarasiuk }
2111*db825feeSVladyslav Tarasiuk
211232a173c7SSaeed Mahameed /**
211332a173c7SSaeed Mahameed * mlx4_get_module_info - Read cable module eeprom data
211432a173c7SSaeed Mahameed * @dev: mlx4_dev.
211532a173c7SSaeed Mahameed * @port: port number.
211632a173c7SSaeed Mahameed * @offset: byte offset in eeprom to start reading data from.
211732a173c7SSaeed Mahameed * @size: num of bytes to read.
211832a173c7SSaeed Mahameed * @data: output buffer to put the requested data into.
211932a173c7SSaeed Mahameed *
212032a173c7SSaeed Mahameed * Reads cable module eeprom data, puts the outcome data into
212132a173c7SSaeed Mahameed * data pointer paramer.
212232a173c7SSaeed Mahameed * Returns num of read bytes on success or a negative error
212332a173c7SSaeed Mahameed * code.
212432a173c7SSaeed Mahameed */
mlx4_get_module_info(struct mlx4_dev * dev,u8 port,u16 offset,u16 size,u8 * data)212532a173c7SSaeed Mahameed int mlx4_get_module_info(struct mlx4_dev *dev, u8 port,
212632a173c7SSaeed Mahameed u16 offset, u16 size, u8 *data)
212732a173c7SSaeed Mahameed {
212832a173c7SSaeed Mahameed struct mlx4_cmd_mailbox *inbox, *outbox;
212932a173c7SSaeed Mahameed struct mlx4_mad_ifc *inmad, *outmad;
213032a173c7SSaeed Mahameed struct mlx4_cable_info *cable_info;
2131*db825feeSVladyslav Tarasiuk u8 module_id, i2c_addr, page_num;
213232a173c7SSaeed Mahameed int ret;
213332a173c7SSaeed Mahameed
213432a173c7SSaeed Mahameed if (size > MODULE_INFO_MAX_READ)
213532a173c7SSaeed Mahameed size = MODULE_INFO_MAX_READ;
213632a173c7SSaeed Mahameed
2137*db825feeSVladyslav Tarasiuk ret = mlx4_get_module_id(dev, port, &module_id);
2138*db825feeSVladyslav Tarasiuk if (ret)
2139*db825feeSVladyslav Tarasiuk return ret;
2140*db825feeSVladyslav Tarasiuk
2141*db825feeSVladyslav Tarasiuk switch (module_id) {
2142*db825feeSVladyslav Tarasiuk case MLX4_MODULE_ID_SFP:
2143*db825feeSVladyslav Tarasiuk mlx4_sfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
2144*db825feeSVladyslav Tarasiuk break;
2145*db825feeSVladyslav Tarasiuk case MLX4_MODULE_ID_QSFP:
2146*db825feeSVladyslav Tarasiuk case MLX4_MODULE_ID_QSFP_PLUS:
2147*db825feeSVladyslav Tarasiuk case MLX4_MODULE_ID_QSFP28:
2148*db825feeSVladyslav Tarasiuk mlx4_qsfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
2149*db825feeSVladyslav Tarasiuk break;
2150*db825feeSVladyslav Tarasiuk default:
2151*db825feeSVladyslav Tarasiuk mlx4_err(dev, "Module ID not recognized: %#x\n", module_id);
2152*db825feeSVladyslav Tarasiuk return -EINVAL;
2153*db825feeSVladyslav Tarasiuk }
2154*db825feeSVladyslav Tarasiuk
215532a173c7SSaeed Mahameed inbox = mlx4_alloc_cmd_mailbox(dev);
215632a173c7SSaeed Mahameed if (IS_ERR(inbox))
215732a173c7SSaeed Mahameed return PTR_ERR(inbox);
215832a173c7SSaeed Mahameed
215932a173c7SSaeed Mahameed outbox = mlx4_alloc_cmd_mailbox(dev);
216032a173c7SSaeed Mahameed if (IS_ERR(outbox)) {
216132a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, inbox);
216232a173c7SSaeed Mahameed return PTR_ERR(outbox);
216332a173c7SSaeed Mahameed }
216432a173c7SSaeed Mahameed
216532a173c7SSaeed Mahameed inmad = (struct mlx4_mad_ifc *)(inbox->buf);
216632a173c7SSaeed Mahameed outmad = (struct mlx4_mad_ifc *)(outbox->buf);
216732a173c7SSaeed Mahameed
216832a173c7SSaeed Mahameed inmad->method = 0x1; /* Get */
216932a173c7SSaeed Mahameed inmad->class_version = 0x1;
217032a173c7SSaeed Mahameed inmad->mgmt_class = 0x1;
217132a173c7SSaeed Mahameed inmad->base_version = 0x1;
217232a173c7SSaeed Mahameed inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */
217332a173c7SSaeed Mahameed
217432a173c7SSaeed Mahameed if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE)
217532a173c7SSaeed Mahameed /* Cross pages reads are not allowed
217632a173c7SSaeed Mahameed * read until offset 256 in low page
217732a173c7SSaeed Mahameed */
217832a173c7SSaeed Mahameed size -= offset + size - I2C_PAGE_SIZE;
217932a173c7SSaeed Mahameed
218032a173c7SSaeed Mahameed cable_info = (struct mlx4_cable_info *)inmad->data;
218132a173c7SSaeed Mahameed cable_info->dev_mem_address = cpu_to_be16(offset);
2182*db825feeSVladyslav Tarasiuk cable_info->page_num = page_num;
218332a173c7SSaeed Mahameed cable_info->i2c_addr = i2c_addr;
218432a173c7SSaeed Mahameed cable_info->size = cpu_to_be16(size);
218532a173c7SSaeed Mahameed
218632a173c7SSaeed Mahameed ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
218732a173c7SSaeed Mahameed MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
218832a173c7SSaeed Mahameed MLX4_CMD_NATIVE);
218932a173c7SSaeed Mahameed if (ret)
219032a173c7SSaeed Mahameed goto out;
219132a173c7SSaeed Mahameed
219232a173c7SSaeed Mahameed if (be16_to_cpu(outmad->status)) {
219332a173c7SSaeed Mahameed /* Mad returned with bad status */
219432a173c7SSaeed Mahameed ret = be16_to_cpu(outmad->status);
219532a173c7SSaeed Mahameed mlx4_warn(dev,
219632a173c7SSaeed Mahameed "MLX4_CMD_MAD_IFC Get Module info attr(%x) port(%d) i2c_addr(%x) offset(%d) size(%d): Response Mad Status(%x) - %s\n",
219732a173c7SSaeed Mahameed 0xFF60, port, i2c_addr, offset, size,
219832a173c7SSaeed Mahameed ret, cable_info_mad_err_str(ret));
219932a173c7SSaeed Mahameed
220032a173c7SSaeed Mahameed if (i2c_addr == I2C_ADDR_HIGH &&
220132a173c7SSaeed Mahameed MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR)
220232a173c7SSaeed Mahameed /* Some SFP cables do not support i2c slave
220332a173c7SSaeed Mahameed * address 0x51 (high page), abort silently.
220432a173c7SSaeed Mahameed */
220532a173c7SSaeed Mahameed ret = 0;
220632a173c7SSaeed Mahameed else
220732a173c7SSaeed Mahameed ret = -ret;
220832a173c7SSaeed Mahameed goto out;
220932a173c7SSaeed Mahameed }
221032a173c7SSaeed Mahameed cable_info = (struct mlx4_cable_info *)outmad->data;
221132a173c7SSaeed Mahameed memcpy(data, cable_info->data, size);
221232a173c7SSaeed Mahameed ret = size;
221332a173c7SSaeed Mahameed out:
221432a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, inbox);
221532a173c7SSaeed Mahameed mlx4_free_cmd_mailbox(dev, outbox);
221632a173c7SSaeed Mahameed return ret;
221732a173c7SSaeed Mahameed }
221832a173c7SSaeed Mahameed EXPORT_SYMBOL(mlx4_get_module_info);
2219af7d5185SRana Shahout
mlx4_max_tc(struct mlx4_dev * dev)2220af7d5185SRana Shahout int mlx4_max_tc(struct mlx4_dev *dev)
2221af7d5185SRana Shahout {
2222af7d5185SRana Shahout u8 num_tc = dev->caps.max_tc_eth;
2223af7d5185SRana Shahout
2224af7d5185SRana Shahout if (!num_tc)
2225564ed9b1STariq Toukan num_tc = MLX4_TC_MAX_NUMBER;
2226af7d5185SRana Shahout
2227af7d5185SRana Shahout return num_tc;
2228af7d5185SRana Shahout }
2229af7d5185SRana Shahout EXPORT_SYMBOL(mlx4_max_tc);
2230