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)
55bf1f9396SShaker Daibes #define MLX4_FLAG_V_MTU_MASK			BIT(0)
561f8176f7SShaker Daibes #define MLX4_FLAG_V_PPRX_MASK			BIT(1)
571f8176f7SShaker Daibes #define MLX4_FLAG_V_PPTX_MASK			BIT(2)
5878500b8cSMuhammad Mahajna #define MLX4_IGNORE_FCS_MASK			0x1
59564ed9b1STariq Toukan #define MLX4_TC_MAX_NUMBER			8
6078500b8cSMuhammad Mahajna 
615a2cc190SJeff Kirsher void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table)
625a2cc190SJeff Kirsher {
635a2cc190SJeff Kirsher 	int i;
645a2cc190SJeff Kirsher 
655a2cc190SJeff Kirsher 	mutex_init(&table->mutex);
665a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
675a2cc190SJeff Kirsher 		table->entries[i] = 0;
685a2cc190SJeff Kirsher 		table->refs[i]	 = 0;
695f61385dSMoni Shoua 		table->is_dup[i] = false;
705a2cc190SJeff Kirsher 	}
715a2cc190SJeff Kirsher 	table->max   = 1 << dev->caps.log_num_macs;
725a2cc190SJeff Kirsher 	table->total = 0;
735a2cc190SJeff Kirsher }
745a2cc190SJeff Kirsher 
755a2cc190SJeff Kirsher void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
765a2cc190SJeff Kirsher {
775a2cc190SJeff Kirsher 	int i;
785a2cc190SJeff Kirsher 
795a2cc190SJeff Kirsher 	mutex_init(&table->mutex);
805a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
815a2cc190SJeff Kirsher 		table->entries[i] = 0;
825a2cc190SJeff Kirsher 		table->refs[i]	 = 0;
835f61385dSMoni Shoua 		table->is_dup[i] = false;
845a2cc190SJeff Kirsher 	}
85e72ebf5aSYevgeny Petrilin 	table->max   = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR;
865a2cc190SJeff Kirsher 	table->total = 0;
875a2cc190SJeff Kirsher }
885a2cc190SJeff Kirsher 
89111c6094SJack Morgenstein void mlx4_init_roce_gid_table(struct mlx4_dev *dev,
90111c6094SJack Morgenstein 			      struct mlx4_roce_gid_table *table)
91111c6094SJack Morgenstein {
92111c6094SJack Morgenstein 	int i;
93111c6094SJack Morgenstein 
94111c6094SJack Morgenstein 	mutex_init(&table->mutex);
95111c6094SJack Morgenstein 	for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++)
96111c6094SJack Morgenstein 		memset(table->roce_gids[i].raw, 0, MLX4_ROCE_GID_ENTRY_SIZE);
97111c6094SJack Morgenstein }
98111c6094SJack Morgenstein 
995a2cc190SJeff Kirsher static int validate_index(struct mlx4_dev *dev,
1005a2cc190SJeff Kirsher 			  struct mlx4_mac_table *table, int index)
1015a2cc190SJeff Kirsher {
1025a2cc190SJeff Kirsher 	int err = 0;
1035a2cc190SJeff Kirsher 
1045a2cc190SJeff Kirsher 	if (index < 0 || index >= table->max || !table->entries[index]) {
1055a2cc190SJeff Kirsher 		mlx4_warn(dev, "No valid Mac entry for the given index\n");
1065a2cc190SJeff Kirsher 		err = -EINVAL;
1075a2cc190SJeff Kirsher 	}
1085a2cc190SJeff Kirsher 	return err;
1095a2cc190SJeff Kirsher }
1105a2cc190SJeff Kirsher 
1115a2cc190SJeff Kirsher static int find_index(struct mlx4_dev *dev,
1125a2cc190SJeff Kirsher 		      struct mlx4_mac_table *table, u64 mac)
1135a2cc190SJeff Kirsher {
1145a2cc190SJeff Kirsher 	int i;
115ffe455adSEugenia Emantayev 
1165a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
117f4fd40b2SJack Morgenstein 		if (table->refs[i] &&
118f4fd40b2SJack Morgenstein 		    (MLX4_MAC_MASK & mac) ==
119ffe455adSEugenia Emantayev 		    (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))
1205a2cc190SJeff Kirsher 			return i;
1215a2cc190SJeff Kirsher 	}
1225a2cc190SJeff Kirsher 	/* Mac not found */
1235a2cc190SJeff Kirsher 	return -EINVAL;
1245a2cc190SJeff Kirsher }
1255a2cc190SJeff Kirsher 
126ffe455adSEugenia Emantayev static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
127ffe455adSEugenia Emantayev 				   __be64 *entries)
128ffe455adSEugenia Emantayev {
129ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
130ffe455adSEugenia Emantayev 	u32 in_mod;
131ffe455adSEugenia Emantayev 	int err;
132ffe455adSEugenia Emantayev 
133ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
134ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
135ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
136ffe455adSEugenia Emantayev 
137ffe455adSEugenia Emantayev 	memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE);
138ffe455adSEugenia Emantayev 
139ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port;
140ffe455adSEugenia Emantayev 
141a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
142a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
143a130b590SIdo Shamay 		       MLX4_CMD_NATIVE);
144ffe455adSEugenia Emantayev 
145ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
146ffe455adSEugenia Emantayev 	return err;
147ffe455adSEugenia Emantayev }
148ffe455adSEugenia Emantayev 
149297e0dadSMoni Shoua int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx)
150297e0dadSMoni Shoua {
151297e0dadSMoni Shoua 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
152297e0dadSMoni Shoua 	struct mlx4_mac_table *table = &info->mac_table;
153297e0dadSMoni Shoua 	int i;
154297e0dadSMoni Shoua 
155297e0dadSMoni Shoua 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
156297e0dadSMoni Shoua 		if (!table->refs[i])
157297e0dadSMoni Shoua 			continue;
158297e0dadSMoni Shoua 
159297e0dadSMoni Shoua 		if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
160297e0dadSMoni Shoua 			*idx = i;
161297e0dadSMoni Shoua 			return 0;
162297e0dadSMoni Shoua 		}
163297e0dadSMoni Shoua 	}
164297e0dadSMoni Shoua 
165297e0dadSMoni Shoua 	return -ENOENT;
166297e0dadSMoni Shoua }
167297e0dadSMoni Shoua EXPORT_SYMBOL_GPL(mlx4_find_cached_mac);
168297e0dadSMoni Shoua 
1695f61385dSMoni Shoua static bool mlx4_need_mf_bond(struct mlx4_dev *dev)
1705f61385dSMoni Shoua {
1715f61385dSMoni Shoua 	int i, num_eth_ports = 0;
1725f61385dSMoni Shoua 
1735f61385dSMoni Shoua 	if (!mlx4_is_mfunc(dev))
1745f61385dSMoni Shoua 		return false;
1755f61385dSMoni Shoua 	mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
1765f61385dSMoni Shoua 		++num_eth_ports;
1775f61385dSMoni Shoua 
1785f61385dSMoni Shoua 	return (num_eth_ports ==  2) ? true : false;
1795f61385dSMoni Shoua }
1805f61385dSMoni Shoua 
181ffe455adSEugenia Emantayev int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
182ffe455adSEugenia Emantayev {
183ffe455adSEugenia Emantayev 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
184ffe455adSEugenia Emantayev 	struct mlx4_mac_table *table = &info->mac_table;
185ffe455adSEugenia Emantayev 	int i, err = 0;
186ffe455adSEugenia Emantayev 	int free = -1;
1875f61385dSMoni Shoua 	int free_for_dup = -1;
1885f61385dSMoni Shoua 	bool dup = mlx4_is_mf_bonded(dev);
1895f61385dSMoni Shoua 	u8 dup_port = (port == 1) ? 2 : 1;
1905f61385dSMoni Shoua 	struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
1915f61385dSMoni Shoua 	bool need_mf_bond = mlx4_need_mf_bond(dev);
1925f61385dSMoni Shoua 	bool can_mf_bond = true;
193ffe455adSEugenia Emantayev 
1945f61385dSMoni Shoua 	mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d %s duplicate\n",
1955f61385dSMoni Shoua 		 (unsigned long long)mac, port,
1965f61385dSMoni Shoua 		 dup ? "with" : "without");
197ffe455adSEugenia Emantayev 
1985f61385dSMoni Shoua 	if (need_mf_bond) {
1995f61385dSMoni Shoua 		if (port == 1) {
200ffe455adSEugenia Emantayev 			mutex_lock(&table->mutex);
20103a79f31SJack Morgenstein 			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
2025f61385dSMoni Shoua 		} else {
2035f61385dSMoni Shoua 			mutex_lock(&dup_table->mutex);
20403a79f31SJack Morgenstein 			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
2055f61385dSMoni Shoua 		}
2065f61385dSMoni Shoua 	} else {
2075f61385dSMoni Shoua 		mutex_lock(&table->mutex);
2085f61385dSMoni Shoua 	}
2095f61385dSMoni Shoua 
2105f61385dSMoni Shoua 	if (need_mf_bond) {
2115f61385dSMoni Shoua 		int index_at_port = -1;
2125f61385dSMoni Shoua 		int index_at_dup_port = -1;
2135f61385dSMoni Shoua 
2145f61385dSMoni Shoua 		for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
2155f61385dSMoni Shoua 			if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))))
2165f61385dSMoni Shoua 				index_at_port = i;
2175f61385dSMoni Shoua 			if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]))))
2185f61385dSMoni Shoua 				index_at_dup_port = i;
2195f61385dSMoni Shoua 		}
2205f61385dSMoni Shoua 
2215f61385dSMoni Shoua 		/* check that same mac is not in the tables at different indices */
2225f61385dSMoni Shoua 		if ((index_at_port != index_at_dup_port) &&
2235f61385dSMoni Shoua 		    (index_at_port >= 0) &&
2245f61385dSMoni Shoua 		    (index_at_dup_port >= 0))
2255f61385dSMoni Shoua 			can_mf_bond = false;
2265f61385dSMoni Shoua 
2275f61385dSMoni Shoua 		/* If the mac is already in the primary table, the slot must be
2285f61385dSMoni Shoua 		 * available in the duplicate table as well.
2295f61385dSMoni Shoua 		 */
2305f61385dSMoni Shoua 		if (index_at_port >= 0 && index_at_dup_port < 0 &&
2315f61385dSMoni Shoua 		    dup_table->refs[index_at_port]) {
2325f61385dSMoni Shoua 			can_mf_bond = false;
2335f61385dSMoni Shoua 		}
2345f61385dSMoni Shoua 		/* If the mac is already in the duplicate table, check that the
2355f61385dSMoni Shoua 		 * corresponding index is not occupied in the primary table, or
2365f61385dSMoni Shoua 		 * the primary table already contains the mac at the same index.
2375f61385dSMoni Shoua 		 * Otherwise, you cannot bond (primary contains a different mac
2385f61385dSMoni Shoua 		 * at that index).
2395f61385dSMoni Shoua 		 */
2405f61385dSMoni Shoua 		if (index_at_dup_port >= 0) {
2415f61385dSMoni Shoua 			if (!table->refs[index_at_dup_port] ||
2425f61385dSMoni Shoua 			    ((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[index_at_dup_port]))))
2435f61385dSMoni Shoua 				free_for_dup = index_at_dup_port;
2445f61385dSMoni Shoua 			else
2455f61385dSMoni Shoua 				can_mf_bond = false;
2465f61385dSMoni Shoua 		}
2475f61385dSMoni Shoua 	}
2485f61385dSMoni Shoua 
249ffe455adSEugenia Emantayev 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
250f4fd40b2SJack Morgenstein 		if (!table->refs[i]) {
251f4fd40b2SJack Morgenstein 			if (free < 0)
252ffe455adSEugenia Emantayev 				free = i;
2535f61385dSMoni Shoua 			if (free_for_dup < 0 && need_mf_bond && can_mf_bond) {
2545f61385dSMoni Shoua 				if (!dup_table->refs[i])
2555f61385dSMoni Shoua 					free_for_dup = i;
2565f61385dSMoni Shoua 			}
257ffe455adSEugenia Emantayev 			continue;
258ffe455adSEugenia Emantayev 		}
259ffe455adSEugenia Emantayev 
260f4fd40b2SJack Morgenstein 		if ((MLX4_MAC_MASK & mac) ==
261f4fd40b2SJack Morgenstein 		     (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
2626ce71acdSRony Efraim 			/* MAC already registered, increment ref count */
2636ce71acdSRony Efraim 			err = i;
2646ce71acdSRony Efraim 			++table->refs[i];
2655f61385dSMoni Shoua 			if (dup) {
2665f61385dSMoni Shoua 				u64 dup_mac = MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]);
2675f61385dSMoni Shoua 
2685f61385dSMoni Shoua 				if (dup_mac != mac || !dup_table->is_dup[i]) {
2695f61385dSMoni Shoua 					mlx4_warn(dev, "register mac: expect duplicate mac 0x%llx on port %d index %d\n",
2705f61385dSMoni Shoua 						  mac, dup_port, i);
2715f61385dSMoni Shoua 				}
2725f61385dSMoni Shoua 			}
273ffe455adSEugenia Emantayev 			goto out;
274ffe455adSEugenia Emantayev 		}
275ffe455adSEugenia Emantayev 	}
276ffe455adSEugenia Emantayev 
2775f61385dSMoni Shoua 	if (need_mf_bond && (free_for_dup < 0)) {
2785f61385dSMoni Shoua 		if (dup) {
2795f61385dSMoni Shoua 			mlx4_warn(dev, "Fail to allocate duplicate MAC table entry\n");
2805f61385dSMoni Shoua 			mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n");
2815f61385dSMoni Shoua 			dup = false;
2825f61385dSMoni Shoua 		}
2835f61385dSMoni Shoua 		can_mf_bond = false;
2845f61385dSMoni Shoua 	}
2855f61385dSMoni Shoua 
2865f61385dSMoni Shoua 	if (need_mf_bond && can_mf_bond)
2875f61385dSMoni Shoua 		free = free_for_dup;
2885f61385dSMoni Shoua 
289ffe455adSEugenia Emantayev 	mlx4_dbg(dev, "Free MAC index is %d\n", free);
290ffe455adSEugenia Emantayev 
291ffe455adSEugenia Emantayev 	if (table->total == table->max) {
292ffe455adSEugenia Emantayev 		/* No free mac entries */
293ffe455adSEugenia Emantayev 		err = -ENOSPC;
294ffe455adSEugenia Emantayev 		goto out;
295ffe455adSEugenia Emantayev 	}
296ffe455adSEugenia Emantayev 
297ffe455adSEugenia Emantayev 	/* Register new MAC */
298ffe455adSEugenia Emantayev 	table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
299ffe455adSEugenia Emantayev 
300ffe455adSEugenia Emantayev 	err = mlx4_set_port_mac_table(dev, port, table->entries);
301ffe455adSEugenia Emantayev 	if (unlikely(err)) {
302ffe455adSEugenia Emantayev 		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
303ffe455adSEugenia Emantayev 			 (unsigned long long) mac);
304ffe455adSEugenia Emantayev 		table->entries[free] = 0;
305ffe455adSEugenia Emantayev 		goto out;
306ffe455adSEugenia Emantayev 	}
3076ce71acdSRony Efraim 	table->refs[free] = 1;
3085f61385dSMoni Shoua 	table->is_dup[free] = false;
309ffe455adSEugenia Emantayev 	++table->total;
3105f61385dSMoni Shoua 	if (dup) {
3115f61385dSMoni Shoua 		dup_table->refs[free] = 0;
3125f61385dSMoni Shoua 		dup_table->is_dup[free] = true;
3135f61385dSMoni Shoua 		dup_table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
3145f61385dSMoni Shoua 
3155f61385dSMoni Shoua 		err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries);
3165f61385dSMoni Shoua 		if (unlikely(err)) {
3175f61385dSMoni Shoua 			mlx4_warn(dev, "Failed adding duplicate mac: 0x%llx\n", mac);
3185f61385dSMoni Shoua 			dup_table->is_dup[free] = false;
3195f61385dSMoni Shoua 			dup_table->entries[free] = 0;
3205f61385dSMoni Shoua 			goto out;
3215f61385dSMoni Shoua 		}
3225f61385dSMoni Shoua 		++dup_table->total;
3235f61385dSMoni Shoua 	}
3245f61385dSMoni Shoua 	err = free;
325ffe455adSEugenia Emantayev out:
3265f61385dSMoni Shoua 	if (need_mf_bond) {
3275f61385dSMoni Shoua 		if (port == 2) {
328ffe455adSEugenia Emantayev 			mutex_unlock(&table->mutex);
3295f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
3305f61385dSMoni Shoua 		} else {
3315f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
3325f61385dSMoni Shoua 			mutex_unlock(&table->mutex);
3335f61385dSMoni Shoua 		}
3345f61385dSMoni Shoua 	} else {
3355f61385dSMoni Shoua 		mutex_unlock(&table->mutex);
3365f61385dSMoni Shoua 	}
337ffe455adSEugenia Emantayev 	return err;
338ffe455adSEugenia Emantayev }
339ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_register_mac);
340ffe455adSEugenia Emantayev 
341ffe455adSEugenia Emantayev int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
342ffe455adSEugenia Emantayev {
343e7dbeba8SJack Morgenstein 	u64 out_param = 0;
344acddd5ddSJack Morgenstein 	int err = -EINVAL;
345ffe455adSEugenia Emantayev 
346ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
347acddd5ddSJack Morgenstein 		if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) {
348acddd5ddSJack Morgenstein 			err = mlx4_cmd_imm(dev, mac, &out_param,
349acddd5ddSJack Morgenstein 					   ((u32) port) << 8 | (u32) RES_MAC,
350acddd5ddSJack Morgenstein 					   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
351acddd5ddSJack Morgenstein 					   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
352acddd5ddSJack Morgenstein 		}
353acddd5ddSJack Morgenstein 		if (err && err == -EINVAL && mlx4_is_slave(dev)) {
354acddd5ddSJack Morgenstein 			/* retry using old REG_MAC format */
355ffe455adSEugenia Emantayev 			set_param_l(&out_param, port);
356ffe455adSEugenia Emantayev 			err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC,
357ffe455adSEugenia Emantayev 					   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
358ffe455adSEugenia Emantayev 					   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
359acddd5ddSJack Morgenstein 			if (!err)
360acddd5ddSJack Morgenstein 				dev->flags |= MLX4_FLAG_OLD_REG_MAC;
361acddd5ddSJack Morgenstein 		}
362ffe455adSEugenia Emantayev 		if (err)
363ffe455adSEugenia Emantayev 			return err;
364ffe455adSEugenia Emantayev 
365ffe455adSEugenia Emantayev 		return get_param_l(&out_param);
366ffe455adSEugenia Emantayev 	}
367ffe455adSEugenia Emantayev 	return __mlx4_register_mac(dev, port, mac);
368ffe455adSEugenia Emantayev }
369ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(mlx4_register_mac);
370ffe455adSEugenia Emantayev 
37116a10ffdSYan Burman int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port)
37216a10ffdSYan Burman {
37316a10ffdSYan Burman 	return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
37416a10ffdSYan Burman 			(port - 1) * (1 << dev->caps.log_num_macs);
37516a10ffdSYan Burman }
37616a10ffdSYan Burman EXPORT_SYMBOL_GPL(mlx4_get_base_qpn);
377ffe455adSEugenia Emantayev 
378ffe455adSEugenia Emantayev void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
379ffe455adSEugenia Emantayev {
380143b3efbSEugenia Emantayev 	struct mlx4_port_info *info;
381143b3efbSEugenia Emantayev 	struct mlx4_mac_table *table;
382ffe455adSEugenia Emantayev 	int index;
3835f61385dSMoni Shoua 	bool dup = mlx4_is_mf_bonded(dev);
3845f61385dSMoni Shoua 	u8 dup_port = (port == 1) ? 2 : 1;
3855f61385dSMoni Shoua 	struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
386ffe455adSEugenia Emantayev 
387143b3efbSEugenia Emantayev 	if (port < 1 || port > dev->caps.num_ports) {
388143b3efbSEugenia Emantayev 		mlx4_warn(dev, "invalid port number (%d), aborting...\n", port);
389143b3efbSEugenia Emantayev 		return;
390143b3efbSEugenia Emantayev 	}
391143b3efbSEugenia Emantayev 	info = &mlx4_priv(dev)->port[port];
392143b3efbSEugenia Emantayev 	table = &info->mac_table;
3935f61385dSMoni Shoua 
3945f61385dSMoni Shoua 	if (dup) {
3955f61385dSMoni Shoua 		if (port == 1) {
3965a2cc190SJeff Kirsher 			mutex_lock(&table->mutex);
39703a79f31SJack Morgenstein 			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
3985f61385dSMoni Shoua 		} else {
3995f61385dSMoni Shoua 			mutex_lock(&dup_table->mutex);
40003a79f31SJack Morgenstein 			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
4015f61385dSMoni Shoua 		}
4025f61385dSMoni Shoua 	} else {
4035f61385dSMoni Shoua 		mutex_lock(&table->mutex);
4045f61385dSMoni Shoua 	}
4055f61385dSMoni Shoua 
4066ce71acdSRony Efraim 	index = find_index(dev, table, mac);
4075a2cc190SJeff Kirsher 
4085a2cc190SJeff Kirsher 	if (validate_index(dev, table, index))
4095a2cc190SJeff Kirsher 		goto out;
4105f61385dSMoni Shoua 
4115f61385dSMoni Shoua 	if (--table->refs[index] || table->is_dup[index]) {
4121a91de28SJoe Perches 		mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n",
4131a91de28SJoe Perches 			 index);
4145f61385dSMoni Shoua 		if (!table->refs[index])
4155f61385dSMoni Shoua 			dup_table->is_dup[index] = false;
4166ce71acdSRony Efraim 		goto out;
4176ce71acdSRony Efraim 	}
4185a2cc190SJeff Kirsher 
4195a2cc190SJeff Kirsher 	table->entries[index] = 0;
4205f61385dSMoni Shoua 	if (mlx4_set_port_mac_table(dev, port, table->entries))
4215f61385dSMoni Shoua 		mlx4_warn(dev, "Fail to set mac in port %d during unregister\n", port);
4225a2cc190SJeff Kirsher 	--table->total;
4235f61385dSMoni Shoua 
4245f61385dSMoni Shoua 	if (dup) {
4255f61385dSMoni Shoua 		dup_table->is_dup[index] = false;
4265f61385dSMoni Shoua 		if (dup_table->refs[index])
4275f61385dSMoni Shoua 			goto out;
4285f61385dSMoni Shoua 		dup_table->entries[index] = 0;
4295f61385dSMoni Shoua 		if (mlx4_set_port_mac_table(dev, dup_port, dup_table->entries))
4305f61385dSMoni Shoua 			mlx4_warn(dev, "Fail to set mac in duplicate port %d during unregister\n", dup_port);
4315f61385dSMoni Shoua 
4325f61385dSMoni Shoua 		--table->total;
4335f61385dSMoni Shoua 	}
4345a2cc190SJeff Kirsher out:
4355f61385dSMoni Shoua 	if (dup) {
4365f61385dSMoni Shoua 		if (port == 2) {
4375a2cc190SJeff Kirsher 			mutex_unlock(&table->mutex);
4385f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
4395f61385dSMoni Shoua 		} else {
4405f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
4415f61385dSMoni Shoua 			mutex_unlock(&table->mutex);
4425f61385dSMoni Shoua 		}
4435f61385dSMoni Shoua 	} else {
4445f61385dSMoni Shoua 		mutex_unlock(&table->mutex);
4455f61385dSMoni Shoua 	}
4465a2cc190SJeff Kirsher }
447ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_unregister_mac);
448ffe455adSEugenia Emantayev 
449ffe455adSEugenia Emantayev void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
450ffe455adSEugenia Emantayev {
451e7dbeba8SJack Morgenstein 	u64 out_param = 0;
452ffe455adSEugenia Emantayev 
453ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
454acddd5ddSJack Morgenstein 		if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) {
455acddd5ddSJack Morgenstein 			(void) mlx4_cmd_imm(dev, mac, &out_param,
456acddd5ddSJack Morgenstein 					    ((u32) port) << 8 | (u32) RES_MAC,
457acddd5ddSJack Morgenstein 					    RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
458acddd5ddSJack Morgenstein 					    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
459acddd5ddSJack Morgenstein 		} else {
460acddd5ddSJack Morgenstein 			/* use old unregister mac format */
461ffe455adSEugenia Emantayev 			set_param_l(&out_param, port);
462162344edSOr Gerlitz 			(void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC,
463ffe455adSEugenia Emantayev 					    RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
464ffe455adSEugenia Emantayev 					    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
465acddd5ddSJack Morgenstein 		}
466ffe455adSEugenia Emantayev 		return;
467ffe455adSEugenia Emantayev 	}
468ffe455adSEugenia Emantayev 	__mlx4_unregister_mac(dev, port, mac);
469ffe455adSEugenia Emantayev 	return;
470ffe455adSEugenia Emantayev }
4715a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
4725a2cc190SJeff Kirsher 
47316a10ffdSYan Burman int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
4745a2cc190SJeff Kirsher {
4755a2cc190SJeff Kirsher 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
4765a2cc190SJeff Kirsher 	struct mlx4_mac_table *table = &info->mac_table;
477ffe455adSEugenia Emantayev 	int index = qpn - info->base_qpn;
478ffe455adSEugenia Emantayev 	int err = 0;
4795f61385dSMoni Shoua 	bool dup = mlx4_is_mf_bonded(dev);
4805f61385dSMoni Shoua 	u8 dup_port = (port == 1) ? 2 : 1;
4815f61385dSMoni Shoua 	struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
4825a2cc190SJeff Kirsher 
483ffe455adSEugenia Emantayev 	/* CX1 doesn't support multi-functions */
4845f61385dSMoni Shoua 	if (dup) {
4855f61385dSMoni Shoua 		if (port == 1) {
4865a2cc190SJeff Kirsher 			mutex_lock(&table->mutex);
48703a79f31SJack Morgenstein 			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
4885f61385dSMoni Shoua 		} else {
4895f61385dSMoni Shoua 			mutex_lock(&dup_table->mutex);
49003a79f31SJack Morgenstein 			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
4915f61385dSMoni Shoua 		}
4925f61385dSMoni Shoua 	} else {
4935f61385dSMoni Shoua 		mutex_lock(&table->mutex);
4945f61385dSMoni Shoua 	}
4955a2cc190SJeff Kirsher 
4965a2cc190SJeff Kirsher 	err = validate_index(dev, table, index);
4975a2cc190SJeff Kirsher 	if (err)
4985a2cc190SJeff Kirsher 		goto out;
4995a2cc190SJeff Kirsher 
5005a2cc190SJeff Kirsher 	table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
5015a2cc190SJeff Kirsher 
5025a2cc190SJeff Kirsher 	err = mlx4_set_port_mac_table(dev, port, table->entries);
5035a2cc190SJeff Kirsher 	if (unlikely(err)) {
504ffe455adSEugenia Emantayev 		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
505ffe455adSEugenia Emantayev 			 (unsigned long long) new_mac);
5065a2cc190SJeff Kirsher 		table->entries[index] = 0;
5075f61385dSMoni Shoua 	} else {
5085f61385dSMoni Shoua 		if (dup) {
5095f61385dSMoni Shoua 			dup_table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
5105f61385dSMoni Shoua 
5115f61385dSMoni Shoua 			err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries);
5125f61385dSMoni Shoua 			if (unlikely(err)) {
5135f61385dSMoni Shoua 				mlx4_err(dev, "Failed adding duplicate MAC: 0x%llx\n",
5145f61385dSMoni Shoua 					 (unsigned long long)new_mac);
5155f61385dSMoni Shoua 				dup_table->entries[index] = 0;
5165f61385dSMoni Shoua 			}
5175f61385dSMoni Shoua 		}
5185a2cc190SJeff Kirsher 	}
5195a2cc190SJeff Kirsher out:
5205f61385dSMoni Shoua 	if (dup) {
5215f61385dSMoni Shoua 		if (port == 2) {
5225a2cc190SJeff Kirsher 			mutex_unlock(&table->mutex);
5235f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
5245f61385dSMoni Shoua 		} else {
5255f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
5265f61385dSMoni Shoua 			mutex_unlock(&table->mutex);
5275f61385dSMoni Shoua 		}
5285f61385dSMoni Shoua 	} else {
5295f61385dSMoni Shoua 		mutex_unlock(&table->mutex);
5305f61385dSMoni Shoua 	}
5315a2cc190SJeff Kirsher 	return err;
5325a2cc190SJeff Kirsher }
53316a10ffdSYan Burman EXPORT_SYMBOL_GPL(__mlx4_replace_mac);
534ffe455adSEugenia Emantayev 
5355a2cc190SJeff Kirsher static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
5365a2cc190SJeff Kirsher 				    __be32 *entries)
5375a2cc190SJeff Kirsher {
5385a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *mailbox;
5395a2cc190SJeff Kirsher 	u32 in_mod;
5405a2cc190SJeff Kirsher 	int err;
5415a2cc190SJeff Kirsher 
5425a2cc190SJeff Kirsher 	mailbox = mlx4_alloc_cmd_mailbox(dev);
5435a2cc190SJeff Kirsher 	if (IS_ERR(mailbox))
5445a2cc190SJeff Kirsher 		return PTR_ERR(mailbox);
5455a2cc190SJeff Kirsher 
5465a2cc190SJeff Kirsher 	memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE);
5475a2cc190SJeff Kirsher 	in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port;
548a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
549a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
550a130b590SIdo Shamay 		       MLX4_CMD_NATIVE);
5515a2cc190SJeff Kirsher 
5525a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, mailbox);
5535a2cc190SJeff Kirsher 
5545a2cc190SJeff Kirsher 	return err;
5555a2cc190SJeff Kirsher }
5565a2cc190SJeff Kirsher 
5575a2cc190SJeff Kirsher int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
5585a2cc190SJeff Kirsher {
5595a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
5605a2cc190SJeff Kirsher 	int i;
5615a2cc190SJeff Kirsher 
5625a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) {
5635a2cc190SJeff Kirsher 		if (table->refs[i] &&
5645a2cc190SJeff Kirsher 		    (vid == (MLX4_VLAN_MASK &
5655a2cc190SJeff Kirsher 			      be32_to_cpu(table->entries[i])))) {
5665a2cc190SJeff Kirsher 			/* VLAN already registered, increase reference count */
5675a2cc190SJeff Kirsher 			*idx = i;
5685a2cc190SJeff Kirsher 			return 0;
5695a2cc190SJeff Kirsher 		}
5705a2cc190SJeff Kirsher 	}
5715a2cc190SJeff Kirsher 
5725a2cc190SJeff Kirsher 	return -ENOENT;
5735a2cc190SJeff Kirsher }
5745a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
5755a2cc190SJeff Kirsher 
5763f7fb021SRony Efraim int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
577ffe455adSEugenia Emantayev 				int *index)
5785a2cc190SJeff Kirsher {
5795a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
5805a2cc190SJeff Kirsher 	int i, err = 0;
5815a2cc190SJeff Kirsher 	int free = -1;
5825f61385dSMoni Shoua 	int free_for_dup = -1;
5835f61385dSMoni Shoua 	bool dup = mlx4_is_mf_bonded(dev);
5845f61385dSMoni Shoua 	u8 dup_port = (port == 1) ? 2 : 1;
5855f61385dSMoni Shoua 	struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table;
5865f61385dSMoni Shoua 	bool need_mf_bond = mlx4_need_mf_bond(dev);
5875f61385dSMoni Shoua 	bool can_mf_bond = true;
5885a2cc190SJeff Kirsher 
5895f61385dSMoni Shoua 	mlx4_dbg(dev, "Registering VLAN: %d for port %d %s duplicate\n",
5905f61385dSMoni Shoua 		 vlan, port,
5915f61385dSMoni Shoua 		 dup ? "with" : "without");
5925f61385dSMoni Shoua 
5935f61385dSMoni Shoua 	if (need_mf_bond) {
5945f61385dSMoni Shoua 		if (port == 1) {
5955a2cc190SJeff Kirsher 			mutex_lock(&table->mutex);
59603a79f31SJack Morgenstein 			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
5975f61385dSMoni Shoua 		} else {
5985f61385dSMoni Shoua 			mutex_lock(&dup_table->mutex);
59903a79f31SJack Morgenstein 			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
6005f61385dSMoni Shoua 		}
6015f61385dSMoni Shoua 	} else {
6025f61385dSMoni Shoua 		mutex_lock(&table->mutex);
6035f61385dSMoni Shoua 	}
604e72ebf5aSYevgeny Petrilin 
605e72ebf5aSYevgeny Petrilin 	if (table->total == table->max) {
606e72ebf5aSYevgeny Petrilin 		/* No free vlan entries */
607e72ebf5aSYevgeny Petrilin 		err = -ENOSPC;
608e72ebf5aSYevgeny Petrilin 		goto out;
609e72ebf5aSYevgeny Petrilin 	}
610e72ebf5aSYevgeny Petrilin 
6115f61385dSMoni Shoua 	if (need_mf_bond) {
6125f61385dSMoni Shoua 		int index_at_port = -1;
6135f61385dSMoni Shoua 		int index_at_dup_port = -1;
6145f61385dSMoni Shoua 
6155a2cc190SJeff Kirsher 		for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
6165f61385dSMoni Shoua 			if ((vlan == (MLX4_VLAN_MASK & be32_to_cpu(table->entries[i]))))
6175f61385dSMoni Shoua 				index_at_port = i;
6185f61385dSMoni Shoua 			if ((vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i]))))
6195f61385dSMoni Shoua 				index_at_dup_port = i;
6205f61385dSMoni Shoua 		}
6215f61385dSMoni Shoua 		/* check that same vlan is not in the tables at different indices */
6225f61385dSMoni Shoua 		if ((index_at_port != index_at_dup_port) &&
6235f61385dSMoni Shoua 		    (index_at_port >= 0) &&
6245f61385dSMoni Shoua 		    (index_at_dup_port >= 0))
6255f61385dSMoni Shoua 			can_mf_bond = false;
6265f61385dSMoni Shoua 
6275f61385dSMoni Shoua 		/* If the vlan is already in the primary table, the slot must be
6285f61385dSMoni Shoua 		 * available in the duplicate table as well.
6295f61385dSMoni Shoua 		 */
6305f61385dSMoni Shoua 		if (index_at_port >= 0 && index_at_dup_port < 0 &&
6315f61385dSMoni Shoua 		    dup_table->refs[index_at_port]) {
6325f61385dSMoni Shoua 			can_mf_bond = false;
6335f61385dSMoni Shoua 		}
6345f61385dSMoni Shoua 		/* If the vlan is already in the duplicate table, check that the
6355f61385dSMoni Shoua 		 * corresponding index is not occupied in the primary table, or
6365f61385dSMoni Shoua 		 * the primary table already contains the vlan at the same index.
6375f61385dSMoni Shoua 		 * Otherwise, you cannot bond (primary contains a different vlan
6385f61385dSMoni Shoua 		 * at that index).
6395f61385dSMoni Shoua 		 */
6405f61385dSMoni Shoua 		if (index_at_dup_port >= 0) {
6415f61385dSMoni Shoua 			if (!table->refs[index_at_dup_port] ||
6425f61385dSMoni Shoua 			    (vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[index_at_dup_port]))))
6435f61385dSMoni Shoua 				free_for_dup = index_at_dup_port;
6445f61385dSMoni Shoua 			else
6455f61385dSMoni Shoua 				can_mf_bond = false;
6465f61385dSMoni Shoua 		}
6475a2cc190SJeff Kirsher 	}
6485a2cc190SJeff Kirsher 
6495f61385dSMoni Shoua 	for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
6505f61385dSMoni Shoua 		if (!table->refs[i]) {
6515f61385dSMoni Shoua 			if (free < 0)
6525f61385dSMoni Shoua 				free = i;
6535f61385dSMoni Shoua 			if (free_for_dup < 0 && need_mf_bond && can_mf_bond) {
6545f61385dSMoni Shoua 				if (!dup_table->refs[i])
6555f61385dSMoni Shoua 					free_for_dup = i;
6565f61385dSMoni Shoua 			}
6575f61385dSMoni Shoua 		}
6585f61385dSMoni Shoua 
6595f61385dSMoni Shoua 		if ((table->refs[i] || table->is_dup[i]) &&
6605a2cc190SJeff Kirsher 		    (vlan == (MLX4_VLAN_MASK &
6615a2cc190SJeff Kirsher 			      be32_to_cpu(table->entries[i])))) {
6625a2cc190SJeff Kirsher 			/* Vlan already registered, increase references count */
6635f61385dSMoni Shoua 			mlx4_dbg(dev, "vlan %u is already registered.\n", vlan);
6645a2cc190SJeff Kirsher 			*index = i;
6655a2cc190SJeff Kirsher 			++table->refs[i];
6665f61385dSMoni Shoua 			if (dup) {
6675f61385dSMoni Shoua 				u16 dup_vlan = MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i]);
6685f61385dSMoni Shoua 
6695f61385dSMoni Shoua 				if (dup_vlan != vlan || !dup_table->is_dup[i]) {
6705f61385dSMoni Shoua 					mlx4_warn(dev, "register vlan: expected duplicate vlan %u on port %d index %d\n",
6715f61385dSMoni Shoua 						  vlan, dup_port, i);
6725f61385dSMoni Shoua 				}
6735f61385dSMoni Shoua 			}
6745a2cc190SJeff Kirsher 			goto out;
6755a2cc190SJeff Kirsher 		}
6765a2cc190SJeff Kirsher 	}
6775a2cc190SJeff Kirsher 
6785f61385dSMoni Shoua 	if (need_mf_bond && (free_for_dup < 0)) {
6795f61385dSMoni Shoua 		if (dup) {
6805f61385dSMoni Shoua 			mlx4_warn(dev, "Fail to allocate duplicate VLAN table entry\n");
6815f61385dSMoni Shoua 			mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n");
6825f61385dSMoni Shoua 			dup = false;
6835f61385dSMoni Shoua 		}
6845f61385dSMoni Shoua 		can_mf_bond = false;
6855f61385dSMoni Shoua 	}
6865f61385dSMoni Shoua 
6875f61385dSMoni Shoua 	if (need_mf_bond && can_mf_bond)
6885f61385dSMoni Shoua 		free = free_for_dup;
6895f61385dSMoni Shoua 
6905a2cc190SJeff Kirsher 	if (free < 0) {
6915a2cc190SJeff Kirsher 		err = -ENOMEM;
6925a2cc190SJeff Kirsher 		goto out;
6935a2cc190SJeff Kirsher 	}
6945a2cc190SJeff Kirsher 
695ffe455adSEugenia Emantayev 	/* Register new VLAN */
6965a2cc190SJeff Kirsher 	table->refs[free] = 1;
6975f61385dSMoni Shoua 	table->is_dup[free] = false;
6985a2cc190SJeff Kirsher 	table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
6995a2cc190SJeff Kirsher 
7005a2cc190SJeff Kirsher 	err = mlx4_set_port_vlan_table(dev, port, table->entries);
7015a2cc190SJeff Kirsher 	if (unlikely(err)) {
7025a2cc190SJeff Kirsher 		mlx4_warn(dev, "Failed adding vlan: %u\n", vlan);
7035a2cc190SJeff Kirsher 		table->refs[free] = 0;
7045a2cc190SJeff Kirsher 		table->entries[free] = 0;
7055a2cc190SJeff Kirsher 		goto out;
7065a2cc190SJeff Kirsher 	}
7075f61385dSMoni Shoua 	++table->total;
7085f61385dSMoni Shoua 	if (dup) {
7095f61385dSMoni Shoua 		dup_table->refs[free] = 0;
7105f61385dSMoni Shoua 		dup_table->is_dup[free] = true;
7115f61385dSMoni Shoua 		dup_table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
7125f61385dSMoni Shoua 
7135f61385dSMoni Shoua 		err = mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries);
7145f61385dSMoni Shoua 		if (unlikely(err)) {
7155f61385dSMoni Shoua 			mlx4_warn(dev, "Failed adding duplicate vlan: %u\n", vlan);
7165f61385dSMoni Shoua 			dup_table->is_dup[free] = false;
7175f61385dSMoni Shoua 			dup_table->entries[free] = 0;
7185f61385dSMoni Shoua 			goto out;
7195f61385dSMoni Shoua 		}
7205f61385dSMoni Shoua 		++dup_table->total;
7215f61385dSMoni Shoua 	}
7225a2cc190SJeff Kirsher 
7235a2cc190SJeff Kirsher 	*index = free;
7245a2cc190SJeff Kirsher out:
7255f61385dSMoni Shoua 	if (need_mf_bond) {
7265f61385dSMoni Shoua 		if (port == 2) {
7275a2cc190SJeff Kirsher 			mutex_unlock(&table->mutex);
7285f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
7295f61385dSMoni Shoua 		} else {
7305f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
7315f61385dSMoni Shoua 			mutex_unlock(&table->mutex);
7325f61385dSMoni Shoua 		}
7335f61385dSMoni Shoua 	} else {
7345f61385dSMoni Shoua 		mutex_unlock(&table->mutex);
7355f61385dSMoni Shoua 	}
7365a2cc190SJeff Kirsher 	return err;
7375a2cc190SJeff Kirsher }
738ffe455adSEugenia Emantayev 
739ffe455adSEugenia Emantayev int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
740ffe455adSEugenia Emantayev {
741e7dbeba8SJack Morgenstein 	u64 out_param = 0;
742ffe455adSEugenia Emantayev 	int err;
743ffe455adSEugenia Emantayev 
744162226a1SJack Morgenstein 	if (vlan > 4095)
745162226a1SJack Morgenstein 		return -EINVAL;
746162226a1SJack Morgenstein 
747ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
748acddd5ddSJack Morgenstein 		err = mlx4_cmd_imm(dev, vlan, &out_param,
749acddd5ddSJack Morgenstein 				   ((u32) port) << 8 | (u32) RES_VLAN,
750ffe455adSEugenia Emantayev 				   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
751ffe455adSEugenia Emantayev 				   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
752ffe455adSEugenia Emantayev 		if (!err)
753ffe455adSEugenia Emantayev 			*index = get_param_l(&out_param);
754ffe455adSEugenia Emantayev 
755ffe455adSEugenia Emantayev 		return err;
756ffe455adSEugenia Emantayev 	}
757ffe455adSEugenia Emantayev 	return __mlx4_register_vlan(dev, port, vlan, index);
758ffe455adSEugenia Emantayev }
7595a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_register_vlan);
7605a2cc190SJeff Kirsher 
7612009d005SJack Morgenstein void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
7625a2cc190SJeff Kirsher {
7635a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
7642009d005SJack Morgenstein 	int index;
7655f61385dSMoni Shoua 	bool dup = mlx4_is_mf_bonded(dev);
7665f61385dSMoni Shoua 	u8 dup_port = (port == 1) ? 2 : 1;
7675f61385dSMoni Shoua 	struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table;
7682009d005SJack Morgenstein 
7695f61385dSMoni Shoua 	if (dup) {
7705f61385dSMoni Shoua 		if (port == 1) {
7712009d005SJack Morgenstein 			mutex_lock(&table->mutex);
77203a79f31SJack Morgenstein 			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
7735f61385dSMoni Shoua 		} else {
7745f61385dSMoni Shoua 			mutex_lock(&dup_table->mutex);
77503a79f31SJack Morgenstein 			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
7765f61385dSMoni Shoua 		}
7775f61385dSMoni Shoua 	} else {
7785f61385dSMoni Shoua 		mutex_lock(&table->mutex);
7795f61385dSMoni Shoua 	}
7805f61385dSMoni Shoua 
7812009d005SJack Morgenstein 	if (mlx4_find_cached_vlan(dev, port, vlan, &index)) {
7822009d005SJack Morgenstein 		mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan);
7832009d005SJack Morgenstein 		goto out;
7842009d005SJack Morgenstein 	}
7855a2cc190SJeff Kirsher 
7865a2cc190SJeff Kirsher 	if (index < MLX4_VLAN_REGULAR) {
7875a2cc190SJeff Kirsher 		mlx4_warn(dev, "Trying to free special vlan index %d\n", index);
7885a2cc190SJeff Kirsher 		goto out;
7895a2cc190SJeff Kirsher 	}
7902009d005SJack Morgenstein 
7915f61385dSMoni Shoua 	if (--table->refs[index] || table->is_dup[index]) {
7921a91de28SJoe Perches 		mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n",
7931a91de28SJoe Perches 			 table->refs[index], index);
7945f61385dSMoni Shoua 		if (!table->refs[index])
7955f61385dSMoni Shoua 			dup_table->is_dup[index] = false;
7965a2cc190SJeff Kirsher 		goto out;
7975a2cc190SJeff Kirsher 	}
7985a2cc190SJeff Kirsher 	table->entries[index] = 0;
7995f61385dSMoni Shoua 	if (mlx4_set_port_vlan_table(dev, port, table->entries))
8005f61385dSMoni Shoua 		mlx4_warn(dev, "Fail to set vlan in port %d during unregister\n", port);
8015a2cc190SJeff Kirsher 	--table->total;
8025f61385dSMoni Shoua 	if (dup) {
8035f61385dSMoni Shoua 		dup_table->is_dup[index] = false;
8045f61385dSMoni Shoua 		if (dup_table->refs[index])
8055f61385dSMoni Shoua 			goto out;
8065f61385dSMoni Shoua 		dup_table->entries[index] = 0;
8075f61385dSMoni Shoua 		if (mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries))
8085f61385dSMoni Shoua 			mlx4_warn(dev, "Fail to set vlan in duplicate port %d during unregister\n", dup_port);
8095f61385dSMoni Shoua 		--dup_table->total;
8105f61385dSMoni Shoua 	}
8115a2cc190SJeff Kirsher out:
8125f61385dSMoni Shoua 	if (dup) {
8135f61385dSMoni Shoua 		if (port == 2) {
8145a2cc190SJeff Kirsher 			mutex_unlock(&table->mutex);
8155f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
8165f61385dSMoni Shoua 		} else {
8175f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
8185f61385dSMoni Shoua 			mutex_unlock(&table->mutex);
8195f61385dSMoni Shoua 		}
8205f61385dSMoni Shoua 	} else {
8215f61385dSMoni Shoua 		mutex_unlock(&table->mutex);
8225f61385dSMoni Shoua 	}
8235a2cc190SJeff Kirsher }
824ffe455adSEugenia Emantayev 
8252009d005SJack Morgenstein void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
826ffe455adSEugenia Emantayev {
827162226a1SJack Morgenstein 	u64 out_param = 0;
828ffe455adSEugenia Emantayev 
829ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
8302009d005SJack Morgenstein 		(void) mlx4_cmd_imm(dev, vlan, &out_param,
831acddd5ddSJack Morgenstein 				    ((u32) port) << 8 | (u32) RES_VLAN,
832162226a1SJack Morgenstein 				    RES_OP_RESERVE_AND_MAP,
833ffe455adSEugenia Emantayev 				    MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A,
834ffe455adSEugenia Emantayev 				    MLX4_CMD_WRAPPED);
835ffe455adSEugenia Emantayev 		return;
836ffe455adSEugenia Emantayev 	}
8372009d005SJack Morgenstein 	__mlx4_unregister_vlan(dev, port, vlan);
838ffe455adSEugenia Emantayev }
8395a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_vlan);
8405a2cc190SJeff Kirsher 
8415f61385dSMoni Shoua int mlx4_bond_mac_table(struct mlx4_dev *dev)
8425f61385dSMoni Shoua {
8435f61385dSMoni Shoua 	struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table;
8445f61385dSMoni Shoua 	struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table;
8455f61385dSMoni Shoua 	int ret = 0;
8465f61385dSMoni Shoua 	int i;
8475f61385dSMoni Shoua 	bool update1 = false;
8485f61385dSMoni Shoua 	bool update2 = false;
8495f61385dSMoni Shoua 
8505f61385dSMoni Shoua 	mutex_lock(&t1->mutex);
8515f61385dSMoni Shoua 	mutex_lock(&t2->mutex);
8525f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
8535f61385dSMoni Shoua 		if ((t1->entries[i] != t2->entries[i]) &&
8545f61385dSMoni Shoua 		    t1->entries[i] && t2->entries[i]) {
8555f61385dSMoni Shoua 			mlx4_warn(dev, "can't duplicate entry %d in mac table\n", i);
8565f61385dSMoni Shoua 			ret = -EINVAL;
8575f61385dSMoni Shoua 			goto unlock;
8585f61385dSMoni Shoua 		}
8595f61385dSMoni Shoua 	}
8605f61385dSMoni Shoua 
8615f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
8625f61385dSMoni Shoua 		if (t1->entries[i] && !t2->entries[i]) {
8635f61385dSMoni Shoua 			t2->entries[i] = t1->entries[i];
8645f61385dSMoni Shoua 			t2->is_dup[i] = true;
8655f61385dSMoni Shoua 			update2 = true;
8665f61385dSMoni Shoua 		} else if (!t1->entries[i] && t2->entries[i]) {
8675f61385dSMoni Shoua 			t1->entries[i] = t2->entries[i];
8685f61385dSMoni Shoua 			t1->is_dup[i] = true;
8695f61385dSMoni Shoua 			update1 = true;
8705f61385dSMoni Shoua 		} else if (t1->entries[i] && t2->entries[i]) {
8715f61385dSMoni Shoua 			t1->is_dup[i] = true;
8725f61385dSMoni Shoua 			t2->is_dup[i] = true;
8735f61385dSMoni Shoua 		}
8745f61385dSMoni Shoua 	}
8755f61385dSMoni Shoua 
8765f61385dSMoni Shoua 	if (update1) {
8775f61385dSMoni Shoua 		ret = mlx4_set_port_mac_table(dev, 1, t1->entries);
8785f61385dSMoni Shoua 		if (ret)
8795f61385dSMoni Shoua 			mlx4_warn(dev, "failed to set MAC table for port 1 (%d)\n", ret);
8805f61385dSMoni Shoua 	}
8815f61385dSMoni Shoua 	if (!ret && update2) {
8825f61385dSMoni Shoua 		ret = mlx4_set_port_mac_table(dev, 2, t2->entries);
8835f61385dSMoni Shoua 		if (ret)
8845f61385dSMoni Shoua 			mlx4_warn(dev, "failed to set MAC table for port 2 (%d)\n", ret);
8855f61385dSMoni Shoua 	}
8865f61385dSMoni Shoua 
8875f61385dSMoni Shoua 	if (ret)
8885f61385dSMoni Shoua 		mlx4_warn(dev, "failed to create mirror MAC tables\n");
8895f61385dSMoni Shoua unlock:
8905f61385dSMoni Shoua 	mutex_unlock(&t2->mutex);
8915f61385dSMoni Shoua 	mutex_unlock(&t1->mutex);
8925f61385dSMoni Shoua 	return ret;
8935f61385dSMoni Shoua }
8945f61385dSMoni Shoua 
8955f61385dSMoni Shoua int mlx4_unbond_mac_table(struct mlx4_dev *dev)
8965f61385dSMoni Shoua {
8975f61385dSMoni Shoua 	struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table;
8985f61385dSMoni Shoua 	struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table;
8995f61385dSMoni Shoua 	int ret = 0;
9005f61385dSMoni Shoua 	int ret1;
9015f61385dSMoni Shoua 	int i;
9025f61385dSMoni Shoua 	bool update1 = false;
9035f61385dSMoni Shoua 	bool update2 = false;
9045f61385dSMoni Shoua 
9055f61385dSMoni Shoua 	mutex_lock(&t1->mutex);
9065f61385dSMoni Shoua 	mutex_lock(&t2->mutex);
9075f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
9085f61385dSMoni Shoua 		if (t1->entries[i] != t2->entries[i]) {
9095f61385dSMoni Shoua 			mlx4_warn(dev, "mac table is in an unexpected state when trying to unbond\n");
9105f61385dSMoni Shoua 			ret = -EINVAL;
9115f61385dSMoni Shoua 			goto unlock;
9125f61385dSMoni Shoua 		}
9135f61385dSMoni Shoua 	}
9145f61385dSMoni Shoua 
9155f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
9165f61385dSMoni Shoua 		if (!t1->entries[i])
9175f61385dSMoni Shoua 			continue;
9185f61385dSMoni Shoua 		t1->is_dup[i] = false;
9195f61385dSMoni Shoua 		if (!t1->refs[i]) {
9205f61385dSMoni Shoua 			t1->entries[i] = 0;
9215f61385dSMoni Shoua 			update1 = true;
9225f61385dSMoni Shoua 		}
9235f61385dSMoni Shoua 		t2->is_dup[i] = false;
9245f61385dSMoni Shoua 		if (!t2->refs[i]) {
9255f61385dSMoni Shoua 			t2->entries[i] = 0;
9265f61385dSMoni Shoua 			update2 = true;
9275f61385dSMoni Shoua 		}
9285f61385dSMoni Shoua 	}
9295f61385dSMoni Shoua 
9305f61385dSMoni Shoua 	if (update1) {
9315f61385dSMoni Shoua 		ret = mlx4_set_port_mac_table(dev, 1, t1->entries);
9325f61385dSMoni Shoua 		if (ret)
9335f61385dSMoni Shoua 			mlx4_warn(dev, "failed to unmirror MAC tables for port 1(%d)\n", ret);
9345f61385dSMoni Shoua 	}
9355f61385dSMoni Shoua 	if (update2) {
9365f61385dSMoni Shoua 		ret1 = mlx4_set_port_mac_table(dev, 2, t2->entries);
9375f61385dSMoni Shoua 		if (ret1) {
9385f61385dSMoni Shoua 			mlx4_warn(dev, "failed to unmirror MAC tables for port 2(%d)\n", ret1);
9395f61385dSMoni Shoua 			ret = ret1;
9405f61385dSMoni Shoua 		}
9415f61385dSMoni Shoua 	}
9425f61385dSMoni Shoua unlock:
9435f61385dSMoni Shoua 	mutex_unlock(&t2->mutex);
9445f61385dSMoni Shoua 	mutex_unlock(&t1->mutex);
9455f61385dSMoni Shoua 	return ret;
9465f61385dSMoni Shoua }
9475f61385dSMoni Shoua 
9485f61385dSMoni Shoua int mlx4_bond_vlan_table(struct mlx4_dev *dev)
9495f61385dSMoni Shoua {
9505f61385dSMoni Shoua 	struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table;
9515f61385dSMoni Shoua 	struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table;
9525f61385dSMoni Shoua 	int ret = 0;
9535f61385dSMoni Shoua 	int i;
9545f61385dSMoni Shoua 	bool update1 = false;
9555f61385dSMoni Shoua 	bool update2 = false;
9565f61385dSMoni Shoua 
9575f61385dSMoni Shoua 	mutex_lock(&t1->mutex);
9585f61385dSMoni Shoua 	mutex_lock(&t2->mutex);
9595f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
9605f61385dSMoni Shoua 		if ((t1->entries[i] != t2->entries[i]) &&
9615f61385dSMoni Shoua 		    t1->entries[i] && t2->entries[i]) {
9625f61385dSMoni Shoua 			mlx4_warn(dev, "can't duplicate entry %d in vlan table\n", i);
9635f61385dSMoni Shoua 			ret = -EINVAL;
9645f61385dSMoni Shoua 			goto unlock;
9655f61385dSMoni Shoua 		}
9665f61385dSMoni Shoua 	}
9675f61385dSMoni Shoua 
9685f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
9695f61385dSMoni Shoua 		if (t1->entries[i] && !t2->entries[i]) {
9705f61385dSMoni Shoua 			t2->entries[i] = t1->entries[i];
9715f61385dSMoni Shoua 			t2->is_dup[i] = true;
9725f61385dSMoni Shoua 			update2 = true;
9735f61385dSMoni Shoua 		} else if (!t1->entries[i] && t2->entries[i]) {
9745f61385dSMoni Shoua 			t1->entries[i] = t2->entries[i];
9755f61385dSMoni Shoua 			t1->is_dup[i] = true;
9765f61385dSMoni Shoua 			update1 = true;
9775f61385dSMoni Shoua 		} else if (t1->entries[i] && t2->entries[i]) {
9785f61385dSMoni Shoua 			t1->is_dup[i] = true;
9795f61385dSMoni Shoua 			t2->is_dup[i] = true;
9805f61385dSMoni Shoua 		}
9815f61385dSMoni Shoua 	}
9825f61385dSMoni Shoua 
9835f61385dSMoni Shoua 	if (update1) {
9845f61385dSMoni Shoua 		ret = mlx4_set_port_vlan_table(dev, 1, t1->entries);
9855f61385dSMoni Shoua 		if (ret)
9865f61385dSMoni Shoua 			mlx4_warn(dev, "failed to set VLAN table for port 1 (%d)\n", ret);
9875f61385dSMoni Shoua 	}
9885f61385dSMoni Shoua 	if (!ret && update2) {
9895f61385dSMoni Shoua 		ret = mlx4_set_port_vlan_table(dev, 2, t2->entries);
9905f61385dSMoni Shoua 		if (ret)
9915f61385dSMoni Shoua 			mlx4_warn(dev, "failed to set VLAN table for port 2 (%d)\n", ret);
9925f61385dSMoni Shoua 	}
9935f61385dSMoni Shoua 
9945f61385dSMoni Shoua 	if (ret)
9955f61385dSMoni Shoua 		mlx4_warn(dev, "failed to create mirror VLAN tables\n");
9965f61385dSMoni Shoua unlock:
9975f61385dSMoni Shoua 	mutex_unlock(&t2->mutex);
9985f61385dSMoni Shoua 	mutex_unlock(&t1->mutex);
9995f61385dSMoni Shoua 	return ret;
10005f61385dSMoni Shoua }
10015f61385dSMoni Shoua 
10025f61385dSMoni Shoua int mlx4_unbond_vlan_table(struct mlx4_dev *dev)
10035f61385dSMoni Shoua {
10045f61385dSMoni Shoua 	struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table;
10055f61385dSMoni Shoua 	struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table;
10065f61385dSMoni Shoua 	int ret = 0;
10075f61385dSMoni Shoua 	int ret1;
10085f61385dSMoni Shoua 	int i;
10095f61385dSMoni Shoua 	bool update1 = false;
10105f61385dSMoni Shoua 	bool update2 = false;
10115f61385dSMoni Shoua 
10125f61385dSMoni Shoua 	mutex_lock(&t1->mutex);
10135f61385dSMoni Shoua 	mutex_lock(&t2->mutex);
10145f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
10155f61385dSMoni Shoua 		if (t1->entries[i] != t2->entries[i]) {
10165f61385dSMoni Shoua 			mlx4_warn(dev, "vlan table is in an unexpected state when trying to unbond\n");
10175f61385dSMoni Shoua 			ret = -EINVAL;
10185f61385dSMoni Shoua 			goto unlock;
10195f61385dSMoni Shoua 		}
10205f61385dSMoni Shoua 	}
10215f61385dSMoni Shoua 
10225f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
10235f61385dSMoni Shoua 		if (!t1->entries[i])
10245f61385dSMoni Shoua 			continue;
10255f61385dSMoni Shoua 		t1->is_dup[i] = false;
10265f61385dSMoni Shoua 		if (!t1->refs[i]) {
10275f61385dSMoni Shoua 			t1->entries[i] = 0;
10285f61385dSMoni Shoua 			update1 = true;
10295f61385dSMoni Shoua 		}
10305f61385dSMoni Shoua 		t2->is_dup[i] = false;
10315f61385dSMoni Shoua 		if (!t2->refs[i]) {
10325f61385dSMoni Shoua 			t2->entries[i] = 0;
10335f61385dSMoni Shoua 			update2 = true;
10345f61385dSMoni Shoua 		}
10355f61385dSMoni Shoua 	}
10365f61385dSMoni Shoua 
10375f61385dSMoni Shoua 	if (update1) {
10385f61385dSMoni Shoua 		ret = mlx4_set_port_vlan_table(dev, 1, t1->entries);
10395f61385dSMoni Shoua 		if (ret)
10405f61385dSMoni Shoua 			mlx4_warn(dev, "failed to unmirror VLAN tables for port 1(%d)\n", ret);
10415f61385dSMoni Shoua 	}
10425f61385dSMoni Shoua 	if (update2) {
10435f61385dSMoni Shoua 		ret1 = mlx4_set_port_vlan_table(dev, 2, t2->entries);
10445f61385dSMoni Shoua 		if (ret1) {
10455f61385dSMoni Shoua 			mlx4_warn(dev, "failed to unmirror VLAN tables for port 2(%d)\n", ret1);
10465f61385dSMoni Shoua 			ret = ret1;
10475f61385dSMoni Shoua 		}
10485f61385dSMoni Shoua 	}
10495f61385dSMoni Shoua unlock:
10505f61385dSMoni Shoua 	mutex_unlock(&t2->mutex);
10515f61385dSMoni Shoua 	mutex_unlock(&t1->mutex);
10525f61385dSMoni Shoua 	return ret;
10535f61385dSMoni Shoua }
10545f61385dSMoni Shoua 
10555a2cc190SJeff Kirsher int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
10565a2cc190SJeff Kirsher {
10575a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
10585a2cc190SJeff Kirsher 	u8 *inbuf, *outbuf;
10595a2cc190SJeff Kirsher 	int err;
10605a2cc190SJeff Kirsher 
10615a2cc190SJeff Kirsher 	inmailbox = mlx4_alloc_cmd_mailbox(dev);
10625a2cc190SJeff Kirsher 	if (IS_ERR(inmailbox))
10635a2cc190SJeff Kirsher 		return PTR_ERR(inmailbox);
10645a2cc190SJeff Kirsher 
10655a2cc190SJeff Kirsher 	outmailbox = mlx4_alloc_cmd_mailbox(dev);
10665a2cc190SJeff Kirsher 	if (IS_ERR(outmailbox)) {
10675a2cc190SJeff Kirsher 		mlx4_free_cmd_mailbox(dev, inmailbox);
10685a2cc190SJeff Kirsher 		return PTR_ERR(outmailbox);
10695a2cc190SJeff Kirsher 	}
10705a2cc190SJeff Kirsher 
10715a2cc190SJeff Kirsher 	inbuf = inmailbox->buf;
10725a2cc190SJeff Kirsher 	outbuf = outmailbox->buf;
10735a2cc190SJeff Kirsher 	inbuf[0] = 1;
10745a2cc190SJeff Kirsher 	inbuf[1] = 1;
10755a2cc190SJeff Kirsher 	inbuf[2] = 1;
10765a2cc190SJeff Kirsher 	inbuf[3] = 1;
10775a2cc190SJeff Kirsher 	*(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015);
10785a2cc190SJeff Kirsher 	*(__be32 *) (&inbuf[20]) = cpu_to_be32(port);
10795a2cc190SJeff Kirsher 
10805a2cc190SJeff Kirsher 	err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3,
1081f9baff50SJack Morgenstein 			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
1082f9baff50SJack Morgenstein 			   MLX4_CMD_NATIVE);
10835a2cc190SJeff Kirsher 	if (!err)
10845a2cc190SJeff Kirsher 		*caps = *(__be32 *) (outbuf + 84);
10855a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, inmailbox);
10865a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, outmailbox);
10875a2cc190SJeff Kirsher 	return err;
10885a2cc190SJeff Kirsher }
10899cd59352SJack Morgenstein static struct mlx4_roce_gid_entry zgid_entry;
10905a2cc190SJeff Kirsher 
1091449fc488SMatan Barak int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port)
1092b6ffaeffSJack Morgenstein {
1093449fc488SMatan Barak 	int vfs;
1094449fc488SMatan Barak 	int slave_gid = slave;
1095449fc488SMatan Barak 	unsigned i;
1096449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
1097449fc488SMatan Barak 	struct mlx4_active_ports actv_ports;
1098449fc488SMatan Barak 	unsigned max_port_p_one;
1099449fc488SMatan Barak 
1100b6ffaeffSJack Morgenstein 	if (slave == 0)
1101b6ffaeffSJack Morgenstein 		return MLX4_ROCE_PF_GIDS;
1102449fc488SMatan Barak 
1103449fc488SMatan Barak 	/* Slave is a VF */
1104449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1105449fc488SMatan Barak 	actv_ports = mlx4_get_active_ports(dev, slave);
1106449fc488SMatan Barak 	max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
1107449fc488SMatan Barak 		bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
1108449fc488SMatan Barak 
1109449fc488SMatan Barak 	for (i = 1; i < max_port_p_one; i++) {
1110449fc488SMatan Barak 		struct mlx4_active_ports exclusive_ports;
1111449fc488SMatan Barak 		struct mlx4_slaves_pport slaves_pport_actv;
1112449fc488SMatan Barak 		bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
1113449fc488SMatan Barak 		set_bit(i - 1, exclusive_ports.ports);
1114449fc488SMatan Barak 		if (i == port)
1115449fc488SMatan Barak 			continue;
1116449fc488SMatan Barak 		slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
1117449fc488SMatan Barak 				    dev, &exclusive_ports);
1118449fc488SMatan Barak 		slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
1119872bf2fbSYishai Hadas 					   dev->persist->num_vfs + 1);
1120449fc488SMatan Barak 	}
1121872bf2fbSYishai Hadas 	vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1;
1122449fc488SMatan Barak 	if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs))
1123449fc488SMatan Barak 		return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1;
1124449fc488SMatan Barak 	return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs;
1125b6ffaeffSJack Morgenstein }
1126b6ffaeffSJack Morgenstein 
1127449fc488SMatan Barak int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port)
1128b6ffaeffSJack Morgenstein {
1129b6ffaeffSJack Morgenstein 	int gids;
1130449fc488SMatan Barak 	unsigned i;
1131449fc488SMatan Barak 	int slave_gid = slave;
1132b6ffaeffSJack Morgenstein 	int vfs;
1133b6ffaeffSJack Morgenstein 
1134449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
1135449fc488SMatan Barak 	struct mlx4_active_ports actv_ports;
1136449fc488SMatan Barak 	unsigned max_port_p_one;
1137b6ffaeffSJack Morgenstein 
1138b6ffaeffSJack Morgenstein 	if (slave == 0)
1139b6ffaeffSJack Morgenstein 		return 0;
1140b6ffaeffSJack Morgenstein 
1141449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1142449fc488SMatan Barak 	actv_ports = mlx4_get_active_ports(dev, slave);
1143449fc488SMatan Barak 	max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
1144449fc488SMatan Barak 		bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
1145449fc488SMatan Barak 
1146449fc488SMatan Barak 	for (i = 1; i < max_port_p_one; i++) {
1147449fc488SMatan Barak 		struct mlx4_active_ports exclusive_ports;
1148449fc488SMatan Barak 		struct mlx4_slaves_pport slaves_pport_actv;
1149449fc488SMatan Barak 		bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
1150449fc488SMatan Barak 		set_bit(i - 1, exclusive_ports.ports);
1151449fc488SMatan Barak 		if (i == port)
1152449fc488SMatan Barak 			continue;
1153449fc488SMatan Barak 		slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
1154449fc488SMatan Barak 				    dev, &exclusive_ports);
1155449fc488SMatan Barak 		slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
1156872bf2fbSYishai Hadas 					   dev->persist->num_vfs + 1);
1157b6ffaeffSJack Morgenstein 	}
1158449fc488SMatan Barak 	gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
1159872bf2fbSYishai Hadas 	vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1;
1160449fc488SMatan Barak 	if (slave_gid <= gids % vfs)
1161449fc488SMatan Barak 		return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1);
1162449fc488SMatan Barak 
1163449fc488SMatan Barak 	return MLX4_ROCE_PF_GIDS + (gids % vfs) +
1164449fc488SMatan Barak 		((gids / vfs) * (slave_gid - 1));
1165449fc488SMatan Barak }
1166449fc488SMatan Barak EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix);
1167b6ffaeffSJack Morgenstein 
1168111c6094SJack Morgenstein static int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave,
1169111c6094SJack Morgenstein 				     int port, struct mlx4_cmd_mailbox *mailbox)
1170111c6094SJack Morgenstein {
1171111c6094SJack Morgenstein 	struct mlx4_roce_gid_entry *gid_entry_mbox;
1172111c6094SJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
1173111c6094SJack Morgenstein 	int num_gids, base, offset;
1174111c6094SJack Morgenstein 	int i, err;
1175111c6094SJack Morgenstein 
1176111c6094SJack Morgenstein 	num_gids = mlx4_get_slave_num_gids(dev, slave, port);
1177111c6094SJack Morgenstein 	base = mlx4_get_base_gid_ix(dev, slave, port);
1178111c6094SJack Morgenstein 
1179111c6094SJack Morgenstein 	memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE);
1180111c6094SJack Morgenstein 
1181111c6094SJack Morgenstein 	mutex_lock(&(priv->port[port].gid_table.mutex));
1182111c6094SJack Morgenstein 	/* Zero-out gids belonging to that slave in the port GID table */
1183111c6094SJack Morgenstein 	for (i = 0, offset = base; i < num_gids; offset++, i++)
1184111c6094SJack Morgenstein 		memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
1185111c6094SJack Morgenstein 		       zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE);
1186111c6094SJack Morgenstein 
1187111c6094SJack Morgenstein 	/* Now, copy roce port gids table to mailbox for passing to FW */
1188111c6094SJack Morgenstein 	gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf;
1189111c6094SJack Morgenstein 	for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
1190111c6094SJack Morgenstein 		memcpy(gid_entry_mbox->raw,
1191111c6094SJack Morgenstein 		       priv->port[port].gid_table.roce_gids[i].raw,
1192111c6094SJack Morgenstein 		       MLX4_ROCE_GID_ENTRY_SIZE);
1193111c6094SJack Morgenstein 
1194111c6094SJack Morgenstein 	err = mlx4_cmd(dev, mailbox->dma,
1195a130b590SIdo Shamay 		       ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8),
1196a130b590SIdo Shamay 		       MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT,
1197a130b590SIdo Shamay 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
1198111c6094SJack Morgenstein 	mutex_unlock(&(priv->port[port].gid_table.mutex));
1199111c6094SJack Morgenstein 	return err;
1200111c6094SJack Morgenstein }
1201111c6094SJack Morgenstein 
1202111c6094SJack Morgenstein 
1203111c6094SJack Morgenstein void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave)
1204111c6094SJack Morgenstein {
1205111c6094SJack Morgenstein 	struct mlx4_active_ports actv_ports;
1206111c6094SJack Morgenstein 	struct mlx4_cmd_mailbox *mailbox;
1207111c6094SJack Morgenstein 	int num_eth_ports, err;
1208111c6094SJack Morgenstein 	int i;
1209111c6094SJack Morgenstein 
1210872bf2fbSYishai Hadas 	if (slave < 0 || slave > dev->persist->num_vfs)
1211111c6094SJack Morgenstein 		return;
1212111c6094SJack Morgenstein 
1213111c6094SJack Morgenstein 	actv_ports = mlx4_get_active_ports(dev, slave);
1214111c6094SJack Morgenstein 
1215111c6094SJack Morgenstein 	for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) {
1216111c6094SJack Morgenstein 		if (test_bit(i, actv_ports.ports)) {
1217111c6094SJack Morgenstein 			if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
1218111c6094SJack Morgenstein 				continue;
1219111c6094SJack Morgenstein 			num_eth_ports++;
1220111c6094SJack Morgenstein 		}
1221111c6094SJack Morgenstein 	}
1222111c6094SJack Morgenstein 
1223111c6094SJack Morgenstein 	if (!num_eth_ports)
1224111c6094SJack Morgenstein 		return;
1225111c6094SJack Morgenstein 
1226111c6094SJack Morgenstein 	/* have ETH ports.  Alloc mailbox for SET_PORT command */
1227111c6094SJack Morgenstein 	mailbox = mlx4_alloc_cmd_mailbox(dev);
1228111c6094SJack Morgenstein 	if (IS_ERR(mailbox))
1229111c6094SJack Morgenstein 		return;
1230111c6094SJack Morgenstein 
1231111c6094SJack Morgenstein 	for (i = 0; i < dev->caps.num_ports; i++) {
1232111c6094SJack Morgenstein 		if (test_bit(i, actv_ports.ports)) {
1233111c6094SJack Morgenstein 			if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
1234111c6094SJack Morgenstein 				continue;
1235111c6094SJack Morgenstein 			err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox);
1236111c6094SJack Morgenstein 			if (err)
1237111c6094SJack Morgenstein 				mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n",
1238111c6094SJack Morgenstein 					  slave, i + 1, err);
1239111c6094SJack Morgenstein 		}
1240111c6094SJack Morgenstein 	}
1241111c6094SJack Morgenstein 
1242111c6094SJack Morgenstein 	mlx4_free_cmd_mailbox(dev, mailbox);
1243111c6094SJack Morgenstein 	return;
1244111c6094SJack Morgenstein }
1245111c6094SJack Morgenstein 
124640fb4fc1SShaker Daibes static void
1247bf1f9396SShaker Daibes mlx4_en_set_port_mtu(struct mlx4_dev *dev, int slave, int port,
1248bf1f9396SShaker Daibes 		     struct mlx4_set_port_general_context *gen_context)
1249bf1f9396SShaker Daibes {
1250bf1f9396SShaker Daibes 	struct mlx4_priv *priv = mlx4_priv(dev);
1251bf1f9396SShaker Daibes 	struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
1252bf1f9396SShaker Daibes 	struct mlx4_slave_state *slave_st = &master->slave_state[slave];
1253bf1f9396SShaker Daibes 	u16 mtu, prev_mtu;
1254bf1f9396SShaker Daibes 
1255bf1f9396SShaker Daibes 	/* Mtu is configured as the max USER_MTU among all
1256bf1f9396SShaker Daibes 	 * the functions on the port.
1257bf1f9396SShaker Daibes 	 */
1258bf1f9396SShaker Daibes 	mtu = be16_to_cpu(gen_context->mtu);
1259bf1f9396SShaker Daibes 	mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] +
1260bf1f9396SShaker Daibes 		    ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
1261bf1f9396SShaker Daibes 	prev_mtu = slave_st->mtu[port];
1262bf1f9396SShaker Daibes 	slave_st->mtu[port] = mtu;
1263bf1f9396SShaker Daibes 	if (mtu > master->max_mtu[port])
1264bf1f9396SShaker Daibes 		master->max_mtu[port] = mtu;
1265bf1f9396SShaker Daibes 	if (mtu < prev_mtu && prev_mtu == master->max_mtu[port]) {
1266bf1f9396SShaker Daibes 		int i;
1267bf1f9396SShaker Daibes 
1268bf1f9396SShaker Daibes 		slave_st->mtu[port] = mtu;
1269bf1f9396SShaker Daibes 		master->max_mtu[port] = mtu;
1270bf1f9396SShaker Daibes 		for (i = 0; i < dev->num_slaves; i++)
1271bf1f9396SShaker Daibes 			master->max_mtu[port] =
1272bf1f9396SShaker Daibes 				max_t(u16, master->max_mtu[port],
1273bf1f9396SShaker Daibes 				      master->slave_state[i].mtu[port]);
1274bf1f9396SShaker Daibes 	}
1275bf1f9396SShaker Daibes 	gen_context->mtu = cpu_to_be16(master->max_mtu[port]);
1276bf1f9396SShaker Daibes }
1277bf1f9396SShaker Daibes 
1278bf1f9396SShaker Daibes static void
127940fb4fc1SShaker Daibes mlx4_en_set_port_user_mtu(struct mlx4_dev *dev, int slave, int port,
128040fb4fc1SShaker Daibes 			  struct mlx4_set_port_general_context *gen_context)
128140fb4fc1SShaker Daibes {
128240fb4fc1SShaker Daibes 	struct mlx4_priv *priv = mlx4_priv(dev);
128340fb4fc1SShaker Daibes 	struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
128440fb4fc1SShaker Daibes 	struct mlx4_slave_state *slave_st = &master->slave_state[slave];
128540fb4fc1SShaker Daibes 	u16 user_mtu, prev_user_mtu;
128640fb4fc1SShaker Daibes 
128740fb4fc1SShaker Daibes 	/* User Mtu is configured as the max USER_MTU among all
128840fb4fc1SShaker Daibes 	 * the functions on the port.
128940fb4fc1SShaker Daibes 	 */
129040fb4fc1SShaker Daibes 	user_mtu = be16_to_cpu(gen_context->user_mtu);
129140fb4fc1SShaker Daibes 	user_mtu = min_t(int, user_mtu, dev->caps.eth_mtu_cap[port]);
129240fb4fc1SShaker Daibes 	prev_user_mtu = slave_st->user_mtu[port];
129340fb4fc1SShaker Daibes 	slave_st->user_mtu[port] = user_mtu;
129440fb4fc1SShaker Daibes 	if (user_mtu > master->max_user_mtu[port])
129540fb4fc1SShaker Daibes 		master->max_user_mtu[port] = user_mtu;
129640fb4fc1SShaker Daibes 	if (user_mtu < prev_user_mtu &&
129740fb4fc1SShaker Daibes 	    prev_user_mtu == master->max_user_mtu[port]) {
129840fb4fc1SShaker Daibes 		int i;
129940fb4fc1SShaker Daibes 
130040fb4fc1SShaker Daibes 		slave_st->user_mtu[port] = user_mtu;
130140fb4fc1SShaker Daibes 		master->max_user_mtu[port] = user_mtu;
130240fb4fc1SShaker Daibes 		for (i = 0; i < dev->num_slaves; i++)
130340fb4fc1SShaker Daibes 			master->max_user_mtu[port] =
130440fb4fc1SShaker Daibes 				max_t(u16, master->max_user_mtu[port],
130540fb4fc1SShaker Daibes 				      master->slave_state[i].user_mtu[port]);
130640fb4fc1SShaker Daibes 	}
130740fb4fc1SShaker Daibes 	gen_context->user_mtu = cpu_to_be16(master->max_user_mtu[port]);
130840fb4fc1SShaker Daibes }
130940fb4fc1SShaker Daibes 
13101f8176f7SShaker Daibes static void
13111f8176f7SShaker Daibes mlx4_en_set_port_global_pause(struct mlx4_dev *dev, int slave,
13121f8176f7SShaker Daibes 			      struct mlx4_set_port_general_context *gen_context)
13131f8176f7SShaker Daibes {
13141f8176f7SShaker Daibes 	struct mlx4_priv *priv = mlx4_priv(dev);
13151f8176f7SShaker Daibes 	struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
13161f8176f7SShaker Daibes 
13171f8176f7SShaker Daibes 	/* Slave cannot change Global Pause configuration */
13181f8176f7SShaker Daibes 	if (slave != mlx4_master_func_num(dev) &&
13191f8176f7SShaker Daibes 	    (gen_context->pptx != master->pptx ||
13201f8176f7SShaker Daibes 	     gen_context->pprx != master->pprx)) {
13211f8176f7SShaker Daibes 		gen_context->pptx = master->pptx;
13221f8176f7SShaker Daibes 		gen_context->pprx = master->pprx;
13231f8176f7SShaker Daibes 		mlx4_warn(dev, "denying Global Pause change for slave:%d\n",
13241f8176f7SShaker Daibes 			  slave);
13251f8176f7SShaker Daibes 	} else {
13261f8176f7SShaker Daibes 		master->pptx = gen_context->pptx;
13271f8176f7SShaker Daibes 		master->pprx = gen_context->pprx;
13281f8176f7SShaker Daibes 	}
13291f8176f7SShaker Daibes }
13301f8176f7SShaker Daibes 
1331ffe455adSEugenia Emantayev static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
1332ffe455adSEugenia Emantayev 				u8 op_mod, struct mlx4_cmd_mailbox *inbox)
1333ffe455adSEugenia Emantayev {
1334ffe455adSEugenia Emantayev 	struct mlx4_priv *priv = mlx4_priv(dev);
1335ffe455adSEugenia Emantayev 	struct mlx4_port_info *port_info;
1336ffe455adSEugenia Emantayev 	struct mlx4_set_port_rqp_calc_context *qpn_context;
1337ffe455adSEugenia Emantayev 	struct mlx4_set_port_general_context *gen_context;
1338b6ffaeffSJack Morgenstein 	struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1;
1339ffe455adSEugenia Emantayev 	int reset_qkey_viols;
1340ffe455adSEugenia Emantayev 	int port;
1341ffe455adSEugenia Emantayev 	int is_eth;
1342b6ffaeffSJack Morgenstein 	int num_gids;
1343b6ffaeffSJack Morgenstein 	int base;
1344ffe455adSEugenia Emantayev 	u32 in_modifier;
1345ffe455adSEugenia Emantayev 	u32 promisc;
1346ffe455adSEugenia Emantayev 	int err;
1347b6ffaeffSJack Morgenstein 	int i, j;
1348b6ffaeffSJack Morgenstein 	int offset;
1349ffe455adSEugenia Emantayev 	__be32 agg_cap_mask;
1350ffe455adSEugenia Emantayev 	__be32 slave_cap_mask;
1351ffe455adSEugenia Emantayev 	__be32 new_cap_mask;
1352ffe455adSEugenia Emantayev 
1353ffe455adSEugenia Emantayev 	port = in_mod & 0xff;
1354ffe455adSEugenia Emantayev 	in_modifier = in_mod >> 8;
1355ffe455adSEugenia Emantayev 	is_eth = op_mod;
1356ffe455adSEugenia Emantayev 	port_info = &priv->port[port];
1357ffe455adSEugenia Emantayev 
135840fb4fc1SShaker Daibes 	/* Slaves cannot perform SET_PORT operations,
135940fb4fc1SShaker Daibes 	 * except for changing MTU and USER_MTU.
136040fb4fc1SShaker Daibes 	 */
1361ffe455adSEugenia Emantayev 	if (is_eth) {
1362ffe455adSEugenia Emantayev 		if (slave != dev->caps.function &&
13639cd59352SJack Morgenstein 		    in_modifier != MLX4_SET_PORT_GENERAL &&
13649cd59352SJack Morgenstein 		    in_modifier != MLX4_SET_PORT_GID_TABLE) {
1365ffe455adSEugenia Emantayev 			mlx4_warn(dev, "denying SET_PORT for slave:%d\n",
1366ffe455adSEugenia Emantayev 					slave);
1367ffe455adSEugenia Emantayev 			return -EINVAL;
1368ffe455adSEugenia Emantayev 		}
1369ffe455adSEugenia Emantayev 		switch (in_modifier) {
1370ffe455adSEugenia Emantayev 		case MLX4_SET_PORT_RQP_CALC:
1371ffe455adSEugenia Emantayev 			qpn_context = inbox->buf;
1372ffe455adSEugenia Emantayev 			qpn_context->base_qpn =
1373ffe455adSEugenia Emantayev 				cpu_to_be32(port_info->base_qpn);
1374ffe455adSEugenia Emantayev 			qpn_context->n_mac = 0x7;
1375ffe455adSEugenia Emantayev 			promisc = be32_to_cpu(qpn_context->promisc) >>
1376ffe455adSEugenia Emantayev 				SET_PORT_PROMISC_SHIFT;
1377ffe455adSEugenia Emantayev 			qpn_context->promisc = cpu_to_be32(
1378ffe455adSEugenia Emantayev 				promisc << SET_PORT_PROMISC_SHIFT |
1379ffe455adSEugenia Emantayev 				port_info->base_qpn);
1380ffe455adSEugenia Emantayev 			promisc = be32_to_cpu(qpn_context->mcast) >>
1381ffe455adSEugenia Emantayev 				SET_PORT_MC_PROMISC_SHIFT;
1382ffe455adSEugenia Emantayev 			qpn_context->mcast = cpu_to_be32(
1383ffe455adSEugenia Emantayev 				promisc << SET_PORT_MC_PROMISC_SHIFT |
1384ffe455adSEugenia Emantayev 				port_info->base_qpn);
1385ffe455adSEugenia Emantayev 			break;
1386ffe455adSEugenia Emantayev 		case MLX4_SET_PORT_GENERAL:
1387ffe455adSEugenia Emantayev 			gen_context = inbox->buf;
1388bf1f9396SShaker Daibes 
1389bf1f9396SShaker Daibes 			if (gen_context->flags & MLX4_FLAG_V_MTU_MASK)
1390bf1f9396SShaker Daibes 				mlx4_en_set_port_mtu(dev, slave, port,
1391bf1f9396SShaker Daibes 						     gen_context);
139240fb4fc1SShaker Daibes 
139340fb4fc1SShaker Daibes 			if (gen_context->flags2 & MLX4_FLAG2_V_USER_MTU_MASK)
139440fb4fc1SShaker Daibes 				mlx4_en_set_port_user_mtu(dev, slave, port,
139540fb4fc1SShaker Daibes 							  gen_context);
139640fb4fc1SShaker Daibes 
13971f8176f7SShaker Daibes 			if (gen_context->flags &
139873cfb2a2SDan Carpenter 			    (MLX4_FLAG_V_PPRX_MASK | MLX4_FLAG_V_PPTX_MASK))
13991f8176f7SShaker Daibes 				mlx4_en_set_port_global_pause(dev, slave,
14001f8176f7SShaker Daibes 							      gen_context);
14011f8176f7SShaker Daibes 
1402ffe455adSEugenia Emantayev 			break;
14039cd59352SJack Morgenstein 		case MLX4_SET_PORT_GID_TABLE:
1404b6ffaeffSJack Morgenstein 			/* change to MULTIPLE entries: number of guest's gids
1405b6ffaeffSJack Morgenstein 			 * need a FOR-loop here over number of gids the guest has.
1406b6ffaeffSJack Morgenstein 			 * 1. Check no duplicates in gids passed by slave
1407b6ffaeffSJack Morgenstein 			 */
1408449fc488SMatan Barak 			num_gids = mlx4_get_slave_num_gids(dev, slave, port);
1409449fc488SMatan Barak 			base = mlx4_get_base_gid_ix(dev, slave, port);
1410b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1411b6ffaeffSJack Morgenstein 			for (i = 0; i < num_gids; gid_entry_mbox++, i++) {
1412b6ffaeffSJack Morgenstein 				if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
1413b6ffaeffSJack Morgenstein 					    sizeof(zgid_entry)))
1414b6ffaeffSJack Morgenstein 					continue;
1415b6ffaeffSJack Morgenstein 				gid_entry_mb1 = gid_entry_mbox + 1;
1416b6ffaeffSJack Morgenstein 				for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) {
1417b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mb1->raw,
1418b6ffaeffSJack Morgenstein 						    zgid_entry.raw, sizeof(zgid_entry)))
1419b6ffaeffSJack Morgenstein 						continue;
1420b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw,
1421b6ffaeffSJack Morgenstein 						    sizeof(gid_entry_mbox->raw))) {
1422b6ffaeffSJack Morgenstein 						/* found duplicate */
1423b6ffaeffSJack Morgenstein 						return -EINVAL;
1424b6ffaeffSJack Morgenstein 					}
1425b6ffaeffSJack Morgenstein 				}
1426b6ffaeffSJack Morgenstein 			}
1427b6ffaeffSJack Morgenstein 
1428b6ffaeffSJack Morgenstein 			/* 2. Check that do not have duplicates in OTHER
1429b6ffaeffSJack Morgenstein 			 *    entries in the port GID table
1430b6ffaeffSJack Morgenstein 			 */
1431111c6094SJack Morgenstein 
1432111c6094SJack Morgenstein 			mutex_lock(&(priv->port[port].gid_table.mutex));
14339cd59352SJack Morgenstein 			for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
1434b6ffaeffSJack Morgenstein 				if (i >= base && i < base + num_gids)
1435b6ffaeffSJack Morgenstein 					continue; /* don't compare to slave's current gids */
1436111c6094SJack Morgenstein 				gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i];
1437b6ffaeffSJack Morgenstein 				if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry)))
1438b6ffaeffSJack Morgenstein 					continue;
1439b6ffaeffSJack Morgenstein 				gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1440b6ffaeffSJack Morgenstein 				for (j = 0; j < num_gids; gid_entry_mbox++, j++) {
1441b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
1442b6ffaeffSJack Morgenstein 						    sizeof(zgid_entry)))
1443b6ffaeffSJack Morgenstein 						continue;
1444b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw,
1445b6ffaeffSJack Morgenstein 						    sizeof(gid_entry_tbl->raw))) {
1446b6ffaeffSJack Morgenstein 						/* found duplicate */
14471a91de28SJoe Perches 						mlx4_warn(dev, "requested gid entry for slave:%d is a duplicate of gid at index %d\n",
14489cd59352SJack Morgenstein 							  slave, i);
1449111c6094SJack Morgenstein 						mutex_unlock(&(priv->port[port].gid_table.mutex));
1450b6ffaeffSJack Morgenstein 						return -EINVAL;
14519cd59352SJack Morgenstein 					}
14529cd59352SJack Morgenstein 				}
14539cd59352SJack Morgenstein 			}
1454b6ffaeffSJack Morgenstein 
1455b6ffaeffSJack Morgenstein 			/* insert slave GIDs with memcpy, starting at slave's base index */
1456b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1457b6ffaeffSJack Morgenstein 			for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++)
1458111c6094SJack Morgenstein 				memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
1459111c6094SJack Morgenstein 				       gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE);
1460b6ffaeffSJack Morgenstein 
1461b6ffaeffSJack Morgenstein 			/* Now, copy roce port gids table to current mailbox for passing to FW */
1462b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1463b6ffaeffSJack Morgenstein 			for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
1464111c6094SJack Morgenstein 				memcpy(gid_entry_mbox->raw,
1465111c6094SJack Morgenstein 				       priv->port[port].gid_table.roce_gids[i].raw,
1466111c6094SJack Morgenstein 				       MLX4_ROCE_GID_ENTRY_SIZE);
1467b6ffaeffSJack Morgenstein 
1468111c6094SJack Morgenstein 			err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
1469111c6094SJack Morgenstein 				       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1470111c6094SJack Morgenstein 				       MLX4_CMD_NATIVE);
1471111c6094SJack Morgenstein 			mutex_unlock(&(priv->port[port].gid_table.mutex));
1472111c6094SJack Morgenstein 			return err;
1473ffe455adSEugenia Emantayev 		}
1474111c6094SJack Morgenstein 
1475111c6094SJack Morgenstein 		return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
1476ffe455adSEugenia Emantayev 				MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1477ffe455adSEugenia Emantayev 				MLX4_CMD_NATIVE);
1478ffe455adSEugenia Emantayev 	}
1479ffe455adSEugenia Emantayev 
148051af33cfSIdo Shamay 	/* Slaves are not allowed to SET_PORT beacon (LED) blink */
148151af33cfSIdo Shamay 	if (op_mod == MLX4_SET_PORT_BEACON_OPCODE) {
148251af33cfSIdo Shamay 		mlx4_warn(dev, "denying SET_PORT Beacon slave:%d\n", slave);
148351af33cfSIdo Shamay 		return -EPERM;
148451af33cfSIdo Shamay 	}
148551af33cfSIdo Shamay 
1486ffe455adSEugenia Emantayev 	/* For IB, we only consider:
1487ffe455adSEugenia Emantayev 	 * - The capability mask, which is set to the aggregate of all
1488ffe455adSEugenia Emantayev 	 *   slave function capabilities
1489ffe455adSEugenia Emantayev 	 * - The QKey violatin counter - reset according to each request.
1490ffe455adSEugenia Emantayev 	 */
1491ffe455adSEugenia Emantayev 
1492ffe455adSEugenia Emantayev 	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
1493ffe455adSEugenia Emantayev 		reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40;
1494ffe455adSEugenia Emantayev 		new_cap_mask = ((__be32 *) inbox->buf)[2];
1495ffe455adSEugenia Emantayev 	} else {
1496ffe455adSEugenia Emantayev 		reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1;
1497ffe455adSEugenia Emantayev 		new_cap_mask = ((__be32 *) inbox->buf)[1];
1498ffe455adSEugenia Emantayev 	}
1499ffe455adSEugenia Emantayev 
1500efcd235dSJack Morgenstein 	/* slave may not set the IS_SM capability for the port */
1501efcd235dSJack Morgenstein 	if (slave != mlx4_master_func_num(dev) &&
1502efcd235dSJack Morgenstein 	    (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM))
1503efcd235dSJack Morgenstein 		return -EINVAL;
1504efcd235dSJack Morgenstein 
1505efcd235dSJack Morgenstein 	/* No DEV_MGMT in multifunc mode */
1506efcd235dSJack Morgenstein 	if (mlx4_is_mfunc(dev) &&
1507efcd235dSJack Morgenstein 	    (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP))
1508efcd235dSJack Morgenstein 		return -EINVAL;
1509efcd235dSJack Morgenstein 
1510ffe455adSEugenia Emantayev 	agg_cap_mask = 0;
1511ffe455adSEugenia Emantayev 	slave_cap_mask =
1512ffe455adSEugenia Emantayev 		priv->mfunc.master.slave_state[slave].ib_cap_mask[port];
1513ffe455adSEugenia Emantayev 	priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask;
1514ffe455adSEugenia Emantayev 	for (i = 0; i < dev->num_slaves; i++)
1515ffe455adSEugenia Emantayev 		agg_cap_mask |=
1516ffe455adSEugenia Emantayev 			priv->mfunc.master.slave_state[i].ib_cap_mask[port];
1517ffe455adSEugenia Emantayev 
1518ffe455adSEugenia Emantayev 	/* only clear mailbox for guests.  Master may be setting
1519ffe455adSEugenia Emantayev 	* MTU or PKEY table size
1520ffe455adSEugenia Emantayev 	*/
1521ffe455adSEugenia Emantayev 	if (slave != dev->caps.function)
1522ffe455adSEugenia Emantayev 		memset(inbox->buf, 0, 256);
1523ffe455adSEugenia Emantayev 	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
1524edc4a67eSJack Morgenstein 		*(u8 *) inbox->buf	   |= !!reset_qkey_viols << 6;
1525ffe455adSEugenia Emantayev 		((__be32 *) inbox->buf)[2] = agg_cap_mask;
1526ffe455adSEugenia Emantayev 	} else {
1527edc4a67eSJack Morgenstein 		((u8 *) inbox->buf)[3]     |= !!reset_qkey_viols;
1528ffe455adSEugenia Emantayev 		((__be32 *) inbox->buf)[1] = agg_cap_mask;
1529ffe455adSEugenia Emantayev 	}
1530ffe455adSEugenia Emantayev 
1531ffe455adSEugenia Emantayev 	err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT,
1532ffe455adSEugenia Emantayev 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
1533ffe455adSEugenia Emantayev 	if (err)
1534ffe455adSEugenia Emantayev 		priv->mfunc.master.slave_state[slave].ib_cap_mask[port] =
1535ffe455adSEugenia Emantayev 			slave_cap_mask;
1536ffe455adSEugenia Emantayev 	return err;
1537ffe455adSEugenia Emantayev }
1538ffe455adSEugenia Emantayev 
1539ffe455adSEugenia Emantayev int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave,
1540ffe455adSEugenia Emantayev 			  struct mlx4_vhcr *vhcr,
1541ffe455adSEugenia Emantayev 			  struct mlx4_cmd_mailbox *inbox,
1542ffe455adSEugenia Emantayev 			  struct mlx4_cmd_mailbox *outbox,
1543ffe455adSEugenia Emantayev 			  struct mlx4_cmd_info *cmd)
1544ffe455adSEugenia Emantayev {
1545449fc488SMatan Barak 	int port = mlx4_slave_convert_port(
1546449fc488SMatan Barak 			dev, slave, vhcr->in_modifier & 0xFF);
1547449fc488SMatan Barak 
1548449fc488SMatan Barak 	if (port < 0)
1549449fc488SMatan Barak 		return -EINVAL;
1550449fc488SMatan Barak 
1551449fc488SMatan Barak 	vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) |
1552449fc488SMatan Barak 			    (port & 0xFF);
1553449fc488SMatan Barak 
1554ffe455adSEugenia Emantayev 	return mlx4_common_set_port(dev, slave, vhcr->in_modifier,
1555ffe455adSEugenia Emantayev 				    vhcr->op_modifier, inbox);
1556ffe455adSEugenia Emantayev }
1557ffe455adSEugenia Emantayev 
1558096335b3SOr Gerlitz /* bit locations for set port command with zero op modifier */
1559096335b3SOr Gerlitz enum {
1560096335b3SOr Gerlitz 	MLX4_SET_PORT_VL_CAP	 = 4, /* bits 7:4 */
1561096335b3SOr Gerlitz 	MLX4_SET_PORT_MTU_CAP	 = 12, /* bits 15:12 */
15626634961cSJack Morgenstein 	MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20,
1563096335b3SOr Gerlitz 	MLX4_CHANGE_PORT_VL_CAP	 = 21,
1564096335b3SOr Gerlitz 	MLX4_CHANGE_PORT_MTU_CAP = 22,
1565096335b3SOr Gerlitz };
1566096335b3SOr Gerlitz 
15676634961cSJack Morgenstein int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz)
15685a2cc190SJeff Kirsher {
15695a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *mailbox;
15706634961cSJack Morgenstein 	int err, vl_cap, pkey_tbl_flag = 0;
15715a2cc190SJeff Kirsher 
15725a2cc190SJeff Kirsher 	if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
15735a2cc190SJeff Kirsher 		return 0;
15745a2cc190SJeff Kirsher 
15755a2cc190SJeff Kirsher 	mailbox = mlx4_alloc_cmd_mailbox(dev);
15765a2cc190SJeff Kirsher 	if (IS_ERR(mailbox))
15775a2cc190SJeff Kirsher 		return PTR_ERR(mailbox);
15785a2cc190SJeff Kirsher 
15795a2cc190SJeff Kirsher 	((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port];
1580096335b3SOr Gerlitz 
15816634961cSJack Morgenstein 	if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) {
15826634961cSJack Morgenstein 		pkey_tbl_flag = 1;
15836634961cSJack Morgenstein 		((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz);
15846634961cSJack Morgenstein 	}
15856634961cSJack Morgenstein 
1586096335b3SOr Gerlitz 	/* IB VL CAP enum isn't used by the firmware, just numerical values */
1587096335b3SOr Gerlitz 	for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) {
1588096335b3SOr Gerlitz 		((__be32 *) mailbox->buf)[0] = cpu_to_be32(
1589096335b3SOr Gerlitz 			(1 << MLX4_CHANGE_PORT_MTU_CAP) |
1590096335b3SOr Gerlitz 			(1 << MLX4_CHANGE_PORT_VL_CAP)  |
15916634961cSJack Morgenstein 			(pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) |
1592096335b3SOr Gerlitz 			(dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) |
1593096335b3SOr Gerlitz 			(vl_cap << MLX4_SET_PORT_VL_CAP));
1594a130b590SIdo Shamay 		err = mlx4_cmd(dev, mailbox->dma, port,
1595a130b590SIdo Shamay 			       MLX4_SET_PORT_IB_OPCODE, MLX4_CMD_SET_PORT,
1596f9baff50SJack Morgenstein 			       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
1597096335b3SOr Gerlitz 		if (err != -ENOMEM)
1598096335b3SOr Gerlitz 			break;
1599096335b3SOr Gerlitz 	}
16005a2cc190SJeff Kirsher 
16015a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, mailbox);
16025a2cc190SJeff Kirsher 	return err;
16035a2cc190SJeff Kirsher }
1604ffe455adSEugenia Emantayev 
16051da494cbSMoni Shoua #define SET_PORT_ROCE_2_FLAGS          0x10
16061da494cbSMoni Shoua #define MLX4_SET_PORT_ROCE_V1_V2       0x2
1607cb9ffb76SJoerg Roedel int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
1608ffe455adSEugenia Emantayev 			  u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx)
1609ffe455adSEugenia Emantayev {
1610ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
1611ffe455adSEugenia Emantayev 	struct mlx4_set_port_general_context *context;
1612ffe455adSEugenia Emantayev 	int err;
1613ffe455adSEugenia Emantayev 	u32 in_mod;
1614ffe455adSEugenia Emantayev 
1615ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
1616ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
1617ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
1618ffe455adSEugenia Emantayev 	context = mailbox->buf;
1619ffe455adSEugenia Emantayev 	context->flags = SET_PORT_GEN_ALL_VALID;
1620ffe455adSEugenia Emantayev 	context->mtu = cpu_to_be16(mtu);
1621ffe455adSEugenia Emantayev 	context->pptx = (pptx * (!pfctx)) << 7;
1622ffe455adSEugenia Emantayev 	context->pfctx = pfctx;
1623ffe455adSEugenia Emantayev 	context->pprx = (pprx * (!pfcrx)) << 7;
1624ffe455adSEugenia Emantayev 	context->pfcrx = pfcrx;
1625ffe455adSEugenia Emantayev 
16261da494cbSMoni Shoua 	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2) {
16271da494cbSMoni Shoua 		context->flags |= SET_PORT_ROCE_2_FLAGS;
16281da494cbSMoni Shoua 		context->roce_mode |=
16291da494cbSMoni Shoua 			MLX4_SET_PORT_ROCE_V1_V2 << 4;
16301da494cbSMoni Shoua 	}
1631ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
1632a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1633a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1634a130b590SIdo Shamay 		       MLX4_CMD_WRAPPED);
1635ffe455adSEugenia Emantayev 
1636ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
1637ffe455adSEugenia Emantayev 	return err;
1638ffe455adSEugenia Emantayev }
1639ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_general);
1640ffe455adSEugenia Emantayev 
1641cb9ffb76SJoerg Roedel int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
1642ffe455adSEugenia Emantayev 			   u8 promisc)
1643ffe455adSEugenia Emantayev {
1644ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
1645ffe455adSEugenia Emantayev 	struct mlx4_set_port_rqp_calc_context *context;
1646ffe455adSEugenia Emantayev 	int err;
1647ffe455adSEugenia Emantayev 	u32 in_mod;
1648ffe455adSEugenia Emantayev 	u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ?
1649ffe455adSEugenia Emantayev 		MCAST_DIRECT : MCAST_DEFAULT;
1650ffe455adSEugenia Emantayev 
1651c96d97f4SHadar Hen Zion 	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
1652ffe455adSEugenia Emantayev 		return 0;
1653ffe455adSEugenia Emantayev 
1654ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
1655ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
1656ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
1657ffe455adSEugenia Emantayev 	context = mailbox->buf;
1658ffe455adSEugenia Emantayev 	context->base_qpn = cpu_to_be32(base_qpn);
1659ffe455adSEugenia Emantayev 	context->n_mac = dev->caps.log_num_macs;
1660ffe455adSEugenia Emantayev 	context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT |
1661ffe455adSEugenia Emantayev 				       base_qpn);
1662ffe455adSEugenia Emantayev 	context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT |
1663ffe455adSEugenia Emantayev 				     base_qpn);
1664ffe455adSEugenia Emantayev 	context->intra_no_vlan = 0;
1665ffe455adSEugenia Emantayev 	context->no_vlan = MLX4_NO_VLAN_IDX;
1666ffe455adSEugenia Emantayev 	context->intra_vlan_miss = 0;
1667ffe455adSEugenia Emantayev 	context->vlan_miss = MLX4_VLAN_MISS_IDX;
1668ffe455adSEugenia Emantayev 
1669ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port;
1670a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1671a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1672a130b590SIdo Shamay 		       MLX4_CMD_WRAPPED);
1673ffe455adSEugenia Emantayev 
1674ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
1675ffe455adSEugenia Emantayev 	return err;
1676ffe455adSEugenia Emantayev }
1677ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc);
1678ffe455adSEugenia Emantayev 
167940fb4fc1SShaker Daibes int mlx4_SET_PORT_user_mtu(struct mlx4_dev *dev, u8 port, u16 user_mtu)
168040fb4fc1SShaker Daibes {
168140fb4fc1SShaker Daibes 	struct mlx4_cmd_mailbox *mailbox;
168240fb4fc1SShaker Daibes 	struct mlx4_set_port_general_context *context;
168340fb4fc1SShaker Daibes 	u32 in_mod;
168440fb4fc1SShaker Daibes 	int err;
168540fb4fc1SShaker Daibes 
168640fb4fc1SShaker Daibes 	mailbox = mlx4_alloc_cmd_mailbox(dev);
168740fb4fc1SShaker Daibes 	if (IS_ERR(mailbox))
168840fb4fc1SShaker Daibes 		return PTR_ERR(mailbox);
168940fb4fc1SShaker Daibes 	context = mailbox->buf;
169040fb4fc1SShaker Daibes 	context->flags2 |= MLX4_FLAG2_V_USER_MTU_MASK;
169140fb4fc1SShaker Daibes 	context->user_mtu = cpu_to_be16(user_mtu);
169240fb4fc1SShaker Daibes 
169340fb4fc1SShaker Daibes 	in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
169440fb4fc1SShaker Daibes 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
169540fb4fc1SShaker Daibes 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
169640fb4fc1SShaker Daibes 		       MLX4_CMD_WRAPPED);
169740fb4fc1SShaker Daibes 
169840fb4fc1SShaker Daibes 	mlx4_free_cmd_mailbox(dev, mailbox);
169940fb4fc1SShaker Daibes 	return err;
170040fb4fc1SShaker Daibes }
170140fb4fc1SShaker Daibes EXPORT_SYMBOL(mlx4_SET_PORT_user_mtu);
170240fb4fc1SShaker Daibes 
170378500b8cSMuhammad Mahajna int mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, u8 ignore_fcs_value)
170478500b8cSMuhammad Mahajna {
170578500b8cSMuhammad Mahajna 	struct mlx4_cmd_mailbox *mailbox;
170678500b8cSMuhammad Mahajna 	struct mlx4_set_port_general_context *context;
170778500b8cSMuhammad Mahajna 	u32 in_mod;
170878500b8cSMuhammad Mahajna 	int err;
170978500b8cSMuhammad Mahajna 
171078500b8cSMuhammad Mahajna 	mailbox = mlx4_alloc_cmd_mailbox(dev);
171178500b8cSMuhammad Mahajna 	if (IS_ERR(mailbox))
171278500b8cSMuhammad Mahajna 		return PTR_ERR(mailbox);
171378500b8cSMuhammad Mahajna 	context = mailbox->buf;
171440fb4fc1SShaker Daibes 	context->flags2 |= MLX4_FLAG2_V_IGNORE_FCS_MASK;
171578500b8cSMuhammad Mahajna 	if (ignore_fcs_value)
171678500b8cSMuhammad Mahajna 		context->ignore_fcs |= MLX4_IGNORE_FCS_MASK;
171778500b8cSMuhammad Mahajna 	else
171878500b8cSMuhammad Mahajna 		context->ignore_fcs &= ~MLX4_IGNORE_FCS_MASK;
171978500b8cSMuhammad Mahajna 
172078500b8cSMuhammad Mahajna 	in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
172178500b8cSMuhammad Mahajna 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
172278500b8cSMuhammad Mahajna 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
172378500b8cSMuhammad Mahajna 
172478500b8cSMuhammad Mahajna 	mlx4_free_cmd_mailbox(dev, mailbox);
172578500b8cSMuhammad Mahajna 	return err;
172678500b8cSMuhammad Mahajna }
172778500b8cSMuhammad Mahajna EXPORT_SYMBOL(mlx4_SET_PORT_fcs_check);
172878500b8cSMuhammad Mahajna 
17297ffdf726SOr Gerlitz enum {
17307ffdf726SOr Gerlitz 	VXLAN_ENABLE_MODIFY	= 1 << 7,
17317ffdf726SOr Gerlitz 	VXLAN_STEERING_MODIFY	= 1 << 6,
17327ffdf726SOr Gerlitz 
17337ffdf726SOr Gerlitz 	VXLAN_ENABLE		= 1 << 7,
17347ffdf726SOr Gerlitz };
17357ffdf726SOr Gerlitz 
17367ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context {
17377ffdf726SOr Gerlitz 	u32	reserved1;
17387ffdf726SOr Gerlitz 	u8	modify_flags;
17397ffdf726SOr Gerlitz 	u8	reserved2;
17407ffdf726SOr Gerlitz 	u8	enable_flags;
17417ffdf726SOr Gerlitz 	u8	steering;
17427ffdf726SOr Gerlitz };
17437ffdf726SOr Gerlitz 
17441b136de1SOr Gerlitz int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable)
17457ffdf726SOr Gerlitz {
17467ffdf726SOr Gerlitz 	int err;
17477ffdf726SOr Gerlitz 	u32 in_mod;
17487ffdf726SOr Gerlitz 	struct mlx4_cmd_mailbox *mailbox;
17497ffdf726SOr Gerlitz 	struct mlx4_set_port_vxlan_context  *context;
17507ffdf726SOr Gerlitz 
17517ffdf726SOr Gerlitz 	mailbox = mlx4_alloc_cmd_mailbox(dev);
17527ffdf726SOr Gerlitz 	if (IS_ERR(mailbox))
17537ffdf726SOr Gerlitz 		return PTR_ERR(mailbox);
17547ffdf726SOr Gerlitz 	context = mailbox->buf;
17557ffdf726SOr Gerlitz 	memset(context, 0, sizeof(*context));
17567ffdf726SOr Gerlitz 
17577ffdf726SOr Gerlitz 	context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY;
17581b136de1SOr Gerlitz 	if (enable)
17597ffdf726SOr Gerlitz 		context->enable_flags = VXLAN_ENABLE;
17607ffdf726SOr Gerlitz 	context->steering  = steering;
17617ffdf726SOr Gerlitz 
17627ffdf726SOr Gerlitz 	in_mod = MLX4_SET_PORT_VXLAN << 8 | port;
1763a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1764a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1765a130b590SIdo Shamay 		       MLX4_CMD_NATIVE);
17667ffdf726SOr Gerlitz 
17677ffdf726SOr Gerlitz 	mlx4_free_cmd_mailbox(dev, mailbox);
17687ffdf726SOr Gerlitz 	return err;
17697ffdf726SOr Gerlitz }
17707ffdf726SOr Gerlitz EXPORT_SYMBOL(mlx4_SET_PORT_VXLAN);
17717ffdf726SOr Gerlitz 
177251af33cfSIdo Shamay int mlx4_SET_PORT_BEACON(struct mlx4_dev *dev, u8 port, u16 time)
177351af33cfSIdo Shamay {
177451af33cfSIdo Shamay 	int err;
177551af33cfSIdo Shamay 	struct mlx4_cmd_mailbox *mailbox;
177651af33cfSIdo Shamay 
177751af33cfSIdo Shamay 	mailbox = mlx4_alloc_cmd_mailbox(dev);
177851af33cfSIdo Shamay 	if (IS_ERR(mailbox))
177951af33cfSIdo Shamay 		return PTR_ERR(mailbox);
178051af33cfSIdo Shamay 
178151af33cfSIdo Shamay 	*((__be32 *)mailbox->buf) = cpu_to_be32(time);
178251af33cfSIdo Shamay 
178351af33cfSIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, port, MLX4_SET_PORT_BEACON_OPCODE,
178451af33cfSIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
178551af33cfSIdo Shamay 		       MLX4_CMD_NATIVE);
178651af33cfSIdo Shamay 
178751af33cfSIdo Shamay 	mlx4_free_cmd_mailbox(dev, mailbox);
178851af33cfSIdo Shamay 	return err;
178951af33cfSIdo Shamay }
179051af33cfSIdo Shamay EXPORT_SYMBOL(mlx4_SET_PORT_BEACON);
179151af33cfSIdo Shamay 
1792ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1793ffe455adSEugenia Emantayev 				struct mlx4_vhcr *vhcr,
1794ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *inbox,
1795ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *outbox,
1796ffe455adSEugenia Emantayev 				struct mlx4_cmd_info *cmd)
1797ffe455adSEugenia Emantayev {
1798ffe455adSEugenia Emantayev 	int err = 0;
1799ffe455adSEugenia Emantayev 
1800ffe455adSEugenia Emantayev 	return err;
1801ffe455adSEugenia Emantayev }
1802ffe455adSEugenia Emantayev 
1803ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port,
1804ffe455adSEugenia Emantayev 			u64 mac, u64 clear, u8 mode)
1805ffe455adSEugenia Emantayev {
1806ffe455adSEugenia Emantayev 	return mlx4_cmd(dev, (mac | (clear << 63)), port, mode,
1807ffe455adSEugenia Emantayev 			MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B,
1808ffe455adSEugenia Emantayev 			MLX4_CMD_WRAPPED);
1809ffe455adSEugenia Emantayev }
1810ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR);
1811ffe455adSEugenia Emantayev 
1812ffe455adSEugenia Emantayev int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1813ffe455adSEugenia Emantayev 			       struct mlx4_vhcr *vhcr,
1814ffe455adSEugenia Emantayev 			       struct mlx4_cmd_mailbox *inbox,
1815ffe455adSEugenia Emantayev 			       struct mlx4_cmd_mailbox *outbox,
1816ffe455adSEugenia Emantayev 			       struct mlx4_cmd_info *cmd)
1817ffe455adSEugenia Emantayev {
1818ffe455adSEugenia Emantayev 	int err = 0;
1819ffe455adSEugenia Emantayev 
1820ffe455adSEugenia Emantayev 	return err;
1821ffe455adSEugenia Emantayev }
1822ffe455adSEugenia Emantayev 
1823ffe455adSEugenia Emantayev int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave,
1824ffe455adSEugenia Emantayev 				struct mlx4_vhcr *vhcr,
1825ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *inbox,
1826ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *outbox,
1827ffe455adSEugenia Emantayev 				struct mlx4_cmd_info *cmd)
1828ffe455adSEugenia Emantayev {
182935fb9afbSEugenia Emantayev 	return 0;
1830ffe455adSEugenia Emantayev }
183193ece0c1SEugenia Emantayev 
18329cd59352SJack Morgenstein int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
18339cd59352SJack Morgenstein 				 int *slave_id)
18346ee51a4eSJack Morgenstein {
18356ee51a4eSJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
18366ee51a4eSJack Morgenstein 	int i, found_ix = -1;
1837b6ffaeffSJack Morgenstein 	int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
1838449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
1839449fc488SMatan Barak 	unsigned num_vfs;
1840449fc488SMatan Barak 	int slave_gid;
18416ee51a4eSJack Morgenstein 
18426ee51a4eSJack Morgenstein 	if (!mlx4_is_mfunc(dev))
18436ee51a4eSJack Morgenstein 		return -EINVAL;
18446ee51a4eSJack Morgenstein 
1845449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1846872bf2fbSYishai Hadas 	num_vfs = bitmap_weight(slaves_pport.slaves,
1847872bf2fbSYishai Hadas 				dev->persist->num_vfs + 1) - 1;
1848449fc488SMatan Barak 
18496ee51a4eSJack Morgenstein 	for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
1850111c6094SJack Morgenstein 		if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid,
1851111c6094SJack Morgenstein 			    MLX4_ROCE_GID_ENTRY_SIZE)) {
18526ee51a4eSJack Morgenstein 			found_ix = i;
18536ee51a4eSJack Morgenstein 			break;
18546ee51a4eSJack Morgenstein 		}
18556ee51a4eSJack Morgenstein 	}
18566ee51a4eSJack Morgenstein 
1857b6ffaeffSJack Morgenstein 	if (found_ix >= 0) {
18580254bc82SMatan Barak 		/* Calculate a slave_gid which is the slave number in the gid
18590254bc82SMatan Barak 		 * table and not a globally unique slave number.
18600254bc82SMatan Barak 		 */
1861b6ffaeffSJack Morgenstein 		if (found_ix < MLX4_ROCE_PF_GIDS)
1862449fc488SMatan Barak 			slave_gid = 0;
1863449fc488SMatan Barak 		else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) *
1864449fc488SMatan Barak 			 (vf_gids / num_vfs + 1))
1865449fc488SMatan Barak 			slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) /
1866449fc488SMatan Barak 				     (vf_gids / num_vfs + 1)) + 1;
1867b6ffaeffSJack Morgenstein 		else
1868449fc488SMatan Barak 			slave_gid =
1869b6ffaeffSJack Morgenstein 			((found_ix - MLX4_ROCE_PF_GIDS -
1870449fc488SMatan Barak 			  ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) /
1871449fc488SMatan Barak 			 (vf_gids / num_vfs)) + vf_gids % num_vfs + 1;
1872449fc488SMatan Barak 
18730254bc82SMatan Barak 		/* Calculate the globally unique slave id */
1874449fc488SMatan Barak 		if (slave_gid) {
1875449fc488SMatan Barak 			struct mlx4_active_ports exclusive_ports;
1876449fc488SMatan Barak 			struct mlx4_active_ports actv_ports;
1877449fc488SMatan Barak 			struct mlx4_slaves_pport slaves_pport_actv;
1878449fc488SMatan Barak 			unsigned max_port_p_one;
18790254bc82SMatan Barak 			int num_vfs_before = 0;
18800254bc82SMatan Barak 			int candidate_slave_gid;
1881449fc488SMatan Barak 
18820254bc82SMatan Barak 			/* Calculate how many VFs are on the previous port, if exists */
1883449fc488SMatan Barak 			for (i = 1; i < port; i++) {
1884449fc488SMatan Barak 				bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
18850254bc82SMatan Barak 				set_bit(i - 1, exclusive_ports.ports);
1886449fc488SMatan Barak 				slaves_pport_actv =
1887449fc488SMatan Barak 					mlx4_phys_to_slaves_pport_actv(
1888449fc488SMatan Barak 							dev, &exclusive_ports);
18890254bc82SMatan Barak 				num_vfs_before += bitmap_weight(
1890449fc488SMatan Barak 						slaves_pport_actv.slaves,
1891872bf2fbSYishai Hadas 						dev->persist->num_vfs + 1);
1892449fc488SMatan Barak 			}
1893449fc488SMatan Barak 
18940254bc82SMatan Barak 			/* candidate_slave_gid isn't necessarily the correct slave, but
18950254bc82SMatan Barak 			 * it has the same number of ports and is assigned to the same
18960254bc82SMatan Barak 			 * ports as the real slave we're looking for. On dual port VF,
18970254bc82SMatan Barak 			 * slave_gid = [single port VFs on port <port>] +
18980254bc82SMatan Barak 			 * [offset of the current slave from the first dual port VF] +
18990254bc82SMatan Barak 			 * 1 (for the PF).
19000254bc82SMatan Barak 			 */
19010254bc82SMatan Barak 			candidate_slave_gid = slave_gid + num_vfs_before;
19020254bc82SMatan Barak 
19030254bc82SMatan Barak 			actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid);
1904449fc488SMatan Barak 			max_port_p_one = find_first_bit(
1905449fc488SMatan Barak 				actv_ports.ports, dev->caps.num_ports) +
1906449fc488SMatan Barak 				bitmap_weight(actv_ports.ports,
1907449fc488SMatan Barak 					      dev->caps.num_ports) + 1;
1908449fc488SMatan Barak 
19090254bc82SMatan Barak 			/* Calculate the real slave number */
1910449fc488SMatan Barak 			for (i = 1; i < max_port_p_one; i++) {
1911449fc488SMatan Barak 				if (i == port)
1912449fc488SMatan Barak 					continue;
1913449fc488SMatan Barak 				bitmap_zero(exclusive_ports.ports,
1914449fc488SMatan Barak 					    dev->caps.num_ports);
1915449fc488SMatan Barak 				set_bit(i - 1, exclusive_ports.ports);
1916449fc488SMatan Barak 				slaves_pport_actv =
1917449fc488SMatan Barak 					mlx4_phys_to_slaves_pport_actv(
1918449fc488SMatan Barak 						dev, &exclusive_ports);
1919449fc488SMatan Barak 				slave_gid += bitmap_weight(
1920449fc488SMatan Barak 						slaves_pport_actv.slaves,
1921872bf2fbSYishai Hadas 						dev->persist->num_vfs + 1);
1922449fc488SMatan Barak 			}
1923449fc488SMatan Barak 		}
1924449fc488SMatan Barak 		*slave_id = slave_gid;
1925b6ffaeffSJack Morgenstein 	}
19266ee51a4eSJack Morgenstein 
19276ee51a4eSJack Morgenstein 	return (found_ix >= 0) ? 0 : -EINVAL;
19286ee51a4eSJack Morgenstein }
19296ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid);
19306ee51a4eSJack Morgenstein 
19319cd59352SJack Morgenstein int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id,
19329cd59352SJack Morgenstein 				 u8 *gid)
19336ee51a4eSJack Morgenstein {
19346ee51a4eSJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
19356ee51a4eSJack Morgenstein 
19366ee51a4eSJack Morgenstein 	if (!mlx4_is_master(dev))
19376ee51a4eSJack Morgenstein 		return -EINVAL;
19386ee51a4eSJack Morgenstein 
1939111c6094SJack Morgenstein 	memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw,
1940111c6094SJack Morgenstein 	       MLX4_ROCE_GID_ENTRY_SIZE);
19416ee51a4eSJack Morgenstein 	return 0;
19426ee51a4eSJack Morgenstein }
19436ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
194432a173c7SSaeed Mahameed 
194532a173c7SSaeed Mahameed /* Cable Module Info */
194632a173c7SSaeed Mahameed #define MODULE_INFO_MAX_READ 48
194732a173c7SSaeed Mahameed 
194832a173c7SSaeed Mahameed #define I2C_ADDR_LOW  0x50
194932a173c7SSaeed Mahameed #define I2C_ADDR_HIGH 0x51
195032a173c7SSaeed Mahameed #define I2C_PAGE_SIZE 256
195132a173c7SSaeed Mahameed 
195232a173c7SSaeed Mahameed /* Module Info Data */
195332a173c7SSaeed Mahameed struct mlx4_cable_info {
195432a173c7SSaeed Mahameed 	u8	i2c_addr;
195532a173c7SSaeed Mahameed 	u8	page_num;
195632a173c7SSaeed Mahameed 	__be16	dev_mem_address;
195732a173c7SSaeed Mahameed 	__be16	reserved1;
195832a173c7SSaeed Mahameed 	__be16	size;
195932a173c7SSaeed Mahameed 	__be32	reserved2[2];
196032a173c7SSaeed Mahameed 	u8	data[MODULE_INFO_MAX_READ];
196132a173c7SSaeed Mahameed };
196232a173c7SSaeed Mahameed 
196332a173c7SSaeed Mahameed enum cable_info_err {
196432a173c7SSaeed Mahameed 	 CABLE_INF_INV_PORT      = 0x1,
196532a173c7SSaeed Mahameed 	 CABLE_INF_OP_NOSUP      = 0x2,
196632a173c7SSaeed Mahameed 	 CABLE_INF_NOT_CONN      = 0x3,
196732a173c7SSaeed Mahameed 	 CABLE_INF_NO_EEPRM      = 0x4,
196832a173c7SSaeed Mahameed 	 CABLE_INF_PAGE_ERR      = 0x5,
196932a173c7SSaeed Mahameed 	 CABLE_INF_INV_ADDR      = 0x6,
197032a173c7SSaeed Mahameed 	 CABLE_INF_I2C_ADDR      = 0x7,
197132a173c7SSaeed Mahameed 	 CABLE_INF_QSFP_VIO      = 0x8,
197232a173c7SSaeed Mahameed 	 CABLE_INF_I2C_BUSY      = 0x9,
197332a173c7SSaeed Mahameed };
197432a173c7SSaeed Mahameed 
197532a173c7SSaeed Mahameed #define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF)
197632a173c7SSaeed Mahameed 
197732a173c7SSaeed Mahameed static inline const char *cable_info_mad_err_str(u16 mad_status)
197832a173c7SSaeed Mahameed {
197932a173c7SSaeed Mahameed 	u8 err = MAD_STATUS_2_CABLE_ERR(mad_status);
198032a173c7SSaeed Mahameed 
198132a173c7SSaeed Mahameed 	switch (err) {
198232a173c7SSaeed Mahameed 	case CABLE_INF_INV_PORT:
198332a173c7SSaeed Mahameed 		return "invalid port selected";
198432a173c7SSaeed Mahameed 	case CABLE_INF_OP_NOSUP:
198532a173c7SSaeed Mahameed 		return "operation not supported for this port (the port is of type CX4 or internal)";
198632a173c7SSaeed Mahameed 	case CABLE_INF_NOT_CONN:
198732a173c7SSaeed Mahameed 		return "cable is not connected";
198832a173c7SSaeed Mahameed 	case CABLE_INF_NO_EEPRM:
198932a173c7SSaeed Mahameed 		return "the connected cable has no EPROM (passive copper cable)";
199032a173c7SSaeed Mahameed 	case CABLE_INF_PAGE_ERR:
199132a173c7SSaeed Mahameed 		return "page number is greater than 15";
199232a173c7SSaeed Mahameed 	case CABLE_INF_INV_ADDR:
199332a173c7SSaeed Mahameed 		return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)";
199432a173c7SSaeed Mahameed 	case CABLE_INF_I2C_ADDR:
199532a173c7SSaeed Mahameed 		return "invalid I2C slave address";
199632a173c7SSaeed Mahameed 	case CABLE_INF_QSFP_VIO:
199732a173c7SSaeed Mahameed 		return "at least one cable violates the QSFP specification and ignores the modsel signal";
199832a173c7SSaeed Mahameed 	case CABLE_INF_I2C_BUSY:
199932a173c7SSaeed Mahameed 		return "I2C bus is constantly busy";
200032a173c7SSaeed Mahameed 	}
200132a173c7SSaeed Mahameed 	return "Unknown Error";
200232a173c7SSaeed Mahameed }
200332a173c7SSaeed Mahameed 
200432a173c7SSaeed Mahameed /**
200532a173c7SSaeed Mahameed  * mlx4_get_module_info - Read cable module eeprom data
200632a173c7SSaeed Mahameed  * @dev: mlx4_dev.
200732a173c7SSaeed Mahameed  * @port: port number.
200832a173c7SSaeed Mahameed  * @offset: byte offset in eeprom to start reading data from.
200932a173c7SSaeed Mahameed  * @size: num of bytes to read.
201032a173c7SSaeed Mahameed  * @data: output buffer to put the requested data into.
201132a173c7SSaeed Mahameed  *
201232a173c7SSaeed Mahameed  * Reads cable module eeprom data, puts the outcome data into
201332a173c7SSaeed Mahameed  * data pointer paramer.
201432a173c7SSaeed Mahameed  * Returns num of read bytes on success or a negative error
201532a173c7SSaeed Mahameed  * code.
201632a173c7SSaeed Mahameed  */
201732a173c7SSaeed Mahameed int mlx4_get_module_info(struct mlx4_dev *dev, u8 port,
201832a173c7SSaeed Mahameed 			 u16 offset, u16 size, u8 *data)
201932a173c7SSaeed Mahameed {
202032a173c7SSaeed Mahameed 	struct mlx4_cmd_mailbox *inbox, *outbox;
202132a173c7SSaeed Mahameed 	struct mlx4_mad_ifc *inmad, *outmad;
202232a173c7SSaeed Mahameed 	struct mlx4_cable_info *cable_info;
202332a173c7SSaeed Mahameed 	u16 i2c_addr;
202432a173c7SSaeed Mahameed 	int ret;
202532a173c7SSaeed Mahameed 
202632a173c7SSaeed Mahameed 	if (size > MODULE_INFO_MAX_READ)
202732a173c7SSaeed Mahameed 		size = MODULE_INFO_MAX_READ;
202832a173c7SSaeed Mahameed 
202932a173c7SSaeed Mahameed 	inbox = mlx4_alloc_cmd_mailbox(dev);
203032a173c7SSaeed Mahameed 	if (IS_ERR(inbox))
203132a173c7SSaeed Mahameed 		return PTR_ERR(inbox);
203232a173c7SSaeed Mahameed 
203332a173c7SSaeed Mahameed 	outbox = mlx4_alloc_cmd_mailbox(dev);
203432a173c7SSaeed Mahameed 	if (IS_ERR(outbox)) {
203532a173c7SSaeed Mahameed 		mlx4_free_cmd_mailbox(dev, inbox);
203632a173c7SSaeed Mahameed 		return PTR_ERR(outbox);
203732a173c7SSaeed Mahameed 	}
203832a173c7SSaeed Mahameed 
203932a173c7SSaeed Mahameed 	inmad = (struct mlx4_mad_ifc *)(inbox->buf);
204032a173c7SSaeed Mahameed 	outmad = (struct mlx4_mad_ifc *)(outbox->buf);
204132a173c7SSaeed Mahameed 
204232a173c7SSaeed Mahameed 	inmad->method = 0x1; /* Get */
204332a173c7SSaeed Mahameed 	inmad->class_version = 0x1;
204432a173c7SSaeed Mahameed 	inmad->mgmt_class = 0x1;
204532a173c7SSaeed Mahameed 	inmad->base_version = 0x1;
204632a173c7SSaeed Mahameed 	inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */
204732a173c7SSaeed Mahameed 
204832a173c7SSaeed Mahameed 	if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE)
204932a173c7SSaeed Mahameed 		/* Cross pages reads are not allowed
205032a173c7SSaeed Mahameed 		 * read until offset 256 in low page
205132a173c7SSaeed Mahameed 		 */
205232a173c7SSaeed Mahameed 		size -= offset + size - I2C_PAGE_SIZE;
205332a173c7SSaeed Mahameed 
205432a173c7SSaeed Mahameed 	i2c_addr = I2C_ADDR_LOW;
205532a173c7SSaeed Mahameed 	if (offset >= I2C_PAGE_SIZE) {
205632a173c7SSaeed Mahameed 		/* Reset offset to high page */
205732a173c7SSaeed Mahameed 		i2c_addr = I2C_ADDR_HIGH;
205832a173c7SSaeed Mahameed 		offset -= I2C_PAGE_SIZE;
205932a173c7SSaeed Mahameed 	}
206032a173c7SSaeed Mahameed 
206132a173c7SSaeed Mahameed 	cable_info = (struct mlx4_cable_info *)inmad->data;
206232a173c7SSaeed Mahameed 	cable_info->dev_mem_address = cpu_to_be16(offset);
206332a173c7SSaeed Mahameed 	cable_info->page_num = 0;
206432a173c7SSaeed Mahameed 	cable_info->i2c_addr = i2c_addr;
206532a173c7SSaeed Mahameed 	cable_info->size = cpu_to_be16(size);
206632a173c7SSaeed Mahameed 
206732a173c7SSaeed Mahameed 	ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
206832a173c7SSaeed Mahameed 			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
206932a173c7SSaeed Mahameed 			   MLX4_CMD_NATIVE);
207032a173c7SSaeed Mahameed 	if (ret)
207132a173c7SSaeed Mahameed 		goto out;
207232a173c7SSaeed Mahameed 
207332a173c7SSaeed Mahameed 	if (be16_to_cpu(outmad->status)) {
207432a173c7SSaeed Mahameed 		/* Mad returned with bad status */
207532a173c7SSaeed Mahameed 		ret = be16_to_cpu(outmad->status);
207632a173c7SSaeed Mahameed 		mlx4_warn(dev,
207732a173c7SSaeed 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",
207832a173c7SSaeed Mahameed 			  0xFF60, port, i2c_addr, offset, size,
207932a173c7SSaeed Mahameed 			  ret, cable_info_mad_err_str(ret));
208032a173c7SSaeed Mahameed 
208132a173c7SSaeed Mahameed 		if (i2c_addr == I2C_ADDR_HIGH &&
208232a173c7SSaeed Mahameed 		    MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR)
208332a173c7SSaeed Mahameed 			/* Some SFP cables do not support i2c slave
208432a173c7SSaeed Mahameed 			 * address 0x51 (high page), abort silently.
208532a173c7SSaeed Mahameed 			 */
208632a173c7SSaeed Mahameed 			ret = 0;
208732a173c7SSaeed Mahameed 		else
208832a173c7SSaeed Mahameed 			ret = -ret;
208932a173c7SSaeed Mahameed 		goto out;
209032a173c7SSaeed Mahameed 	}
209132a173c7SSaeed Mahameed 	cable_info = (struct mlx4_cable_info *)outmad->data;
209232a173c7SSaeed Mahameed 	memcpy(data, cable_info->data, size);
209332a173c7SSaeed Mahameed 	ret = size;
209432a173c7SSaeed Mahameed out:
209532a173c7SSaeed Mahameed 	mlx4_free_cmd_mailbox(dev, inbox);
209632a173c7SSaeed Mahameed 	mlx4_free_cmd_mailbox(dev, outbox);
209732a173c7SSaeed Mahameed 	return ret;
209832a173c7SSaeed Mahameed }
209932a173c7SSaeed Mahameed EXPORT_SYMBOL(mlx4_get_module_info);
2100af7d5185SRana Shahout 
2101af7d5185SRana Shahout int mlx4_max_tc(struct mlx4_dev *dev)
2102af7d5185SRana Shahout {
2103af7d5185SRana Shahout 	u8 num_tc = dev->caps.max_tc_eth;
2104af7d5185SRana Shahout 
2105af7d5185SRana Shahout 	if (!num_tc)
2106564ed9b1STariq Toukan 		num_tc = MLX4_TC_MAX_NUMBER;
2107af7d5185SRana Shahout 
2108af7d5185SRana Shahout 	return num_tc;
2109af7d5185SRana Shahout }
2110af7d5185SRana Shahout EXPORT_SYMBOL(mlx4_max_tc);
2111