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 
5378500b8cSMuhammad Mahajna #define MLX4_FLAG_V_IGNORE_FCS_MASK		0x2
5478500b8cSMuhammad Mahajna #define MLX4_IGNORE_FCS_MASK			0x1
55af7d5185SRana Shahout #define MLNX4_TX_MAX_NUMBER			8
5678500b8cSMuhammad Mahajna 
575a2cc190SJeff Kirsher void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table)
585a2cc190SJeff Kirsher {
595a2cc190SJeff Kirsher 	int i;
605a2cc190SJeff Kirsher 
615a2cc190SJeff Kirsher 	mutex_init(&table->mutex);
625a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
635a2cc190SJeff Kirsher 		table->entries[i] = 0;
645a2cc190SJeff Kirsher 		table->refs[i]	 = 0;
655f61385dSMoni Shoua 		table->is_dup[i] = false;
665a2cc190SJeff Kirsher 	}
675a2cc190SJeff Kirsher 	table->max   = 1 << dev->caps.log_num_macs;
685a2cc190SJeff Kirsher 	table->total = 0;
695a2cc190SJeff Kirsher }
705a2cc190SJeff Kirsher 
715a2cc190SJeff Kirsher void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
725a2cc190SJeff Kirsher {
735a2cc190SJeff Kirsher 	int i;
745a2cc190SJeff Kirsher 
755a2cc190SJeff Kirsher 	mutex_init(&table->mutex);
765a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
775a2cc190SJeff Kirsher 		table->entries[i] = 0;
785a2cc190SJeff Kirsher 		table->refs[i]	 = 0;
795f61385dSMoni Shoua 		table->is_dup[i] = false;
805a2cc190SJeff Kirsher 	}
81e72ebf5aSYevgeny Petrilin 	table->max   = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR;
825a2cc190SJeff Kirsher 	table->total = 0;
835a2cc190SJeff Kirsher }
845a2cc190SJeff Kirsher 
85111c6094SJack Morgenstein void mlx4_init_roce_gid_table(struct mlx4_dev *dev,
86111c6094SJack Morgenstein 			      struct mlx4_roce_gid_table *table)
87111c6094SJack Morgenstein {
88111c6094SJack Morgenstein 	int i;
89111c6094SJack Morgenstein 
90111c6094SJack Morgenstein 	mutex_init(&table->mutex);
91111c6094SJack Morgenstein 	for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++)
92111c6094SJack Morgenstein 		memset(table->roce_gids[i].raw, 0, MLX4_ROCE_GID_ENTRY_SIZE);
93111c6094SJack Morgenstein }
94111c6094SJack Morgenstein 
955a2cc190SJeff Kirsher static int validate_index(struct mlx4_dev *dev,
965a2cc190SJeff Kirsher 			  struct mlx4_mac_table *table, int index)
975a2cc190SJeff Kirsher {
985a2cc190SJeff Kirsher 	int err = 0;
995a2cc190SJeff Kirsher 
1005a2cc190SJeff Kirsher 	if (index < 0 || index >= table->max || !table->entries[index]) {
1015a2cc190SJeff Kirsher 		mlx4_warn(dev, "No valid Mac entry for the given index\n");
1025a2cc190SJeff Kirsher 		err = -EINVAL;
1035a2cc190SJeff Kirsher 	}
1045a2cc190SJeff Kirsher 	return err;
1055a2cc190SJeff Kirsher }
1065a2cc190SJeff Kirsher 
1075a2cc190SJeff Kirsher static int find_index(struct mlx4_dev *dev,
1085a2cc190SJeff Kirsher 		      struct mlx4_mac_table *table, u64 mac)
1095a2cc190SJeff Kirsher {
1105a2cc190SJeff Kirsher 	int i;
111ffe455adSEugenia Emantayev 
1125a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
113f4fd40b2SJack Morgenstein 		if (table->refs[i] &&
114f4fd40b2SJack Morgenstein 		    (MLX4_MAC_MASK & mac) ==
115ffe455adSEugenia Emantayev 		    (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))
1165a2cc190SJeff Kirsher 			return i;
1175a2cc190SJeff Kirsher 	}
1185a2cc190SJeff Kirsher 	/* Mac not found */
1195a2cc190SJeff Kirsher 	return -EINVAL;
1205a2cc190SJeff Kirsher }
1215a2cc190SJeff Kirsher 
122ffe455adSEugenia Emantayev static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
123ffe455adSEugenia Emantayev 				   __be64 *entries)
124ffe455adSEugenia Emantayev {
125ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
126ffe455adSEugenia Emantayev 	u32 in_mod;
127ffe455adSEugenia Emantayev 	int err;
128ffe455adSEugenia Emantayev 
129ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
130ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
131ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
132ffe455adSEugenia Emantayev 
133ffe455adSEugenia Emantayev 	memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE);
134ffe455adSEugenia Emantayev 
135ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port;
136ffe455adSEugenia Emantayev 
137a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
138a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
139a130b590SIdo Shamay 		       MLX4_CMD_NATIVE);
140ffe455adSEugenia Emantayev 
141ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
142ffe455adSEugenia Emantayev 	return err;
143ffe455adSEugenia Emantayev }
144ffe455adSEugenia Emantayev 
145297e0dadSMoni Shoua int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx)
146297e0dadSMoni Shoua {
147297e0dadSMoni Shoua 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
148297e0dadSMoni Shoua 	struct mlx4_mac_table *table = &info->mac_table;
149297e0dadSMoni Shoua 	int i;
150297e0dadSMoni Shoua 
151297e0dadSMoni Shoua 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
152297e0dadSMoni Shoua 		if (!table->refs[i])
153297e0dadSMoni Shoua 			continue;
154297e0dadSMoni Shoua 
155297e0dadSMoni Shoua 		if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
156297e0dadSMoni Shoua 			*idx = i;
157297e0dadSMoni Shoua 			return 0;
158297e0dadSMoni Shoua 		}
159297e0dadSMoni Shoua 	}
160297e0dadSMoni Shoua 
161297e0dadSMoni Shoua 	return -ENOENT;
162297e0dadSMoni Shoua }
163297e0dadSMoni Shoua EXPORT_SYMBOL_GPL(mlx4_find_cached_mac);
164297e0dadSMoni Shoua 
1655f61385dSMoni Shoua static bool mlx4_need_mf_bond(struct mlx4_dev *dev)
1665f61385dSMoni Shoua {
1675f61385dSMoni Shoua 	int i, num_eth_ports = 0;
1685f61385dSMoni Shoua 
1695f61385dSMoni Shoua 	if (!mlx4_is_mfunc(dev))
1705f61385dSMoni Shoua 		return false;
1715f61385dSMoni Shoua 	mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
1725f61385dSMoni Shoua 		++num_eth_ports;
1735f61385dSMoni Shoua 
1745f61385dSMoni Shoua 	return (num_eth_ports ==  2) ? true : false;
1755f61385dSMoni Shoua }
1765f61385dSMoni Shoua 
177ffe455adSEugenia Emantayev int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
178ffe455adSEugenia Emantayev {
179ffe455adSEugenia Emantayev 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
180ffe455adSEugenia Emantayev 	struct mlx4_mac_table *table = &info->mac_table;
181ffe455adSEugenia Emantayev 	int i, err = 0;
182ffe455adSEugenia Emantayev 	int free = -1;
1835f61385dSMoni Shoua 	int free_for_dup = -1;
1845f61385dSMoni Shoua 	bool dup = mlx4_is_mf_bonded(dev);
1855f61385dSMoni Shoua 	u8 dup_port = (port == 1) ? 2 : 1;
1865f61385dSMoni Shoua 	struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
1875f61385dSMoni Shoua 	bool need_mf_bond = mlx4_need_mf_bond(dev);
1885f61385dSMoni Shoua 	bool can_mf_bond = true;
189ffe455adSEugenia Emantayev 
1905f61385dSMoni Shoua 	mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d %s duplicate\n",
1915f61385dSMoni Shoua 		 (unsigned long long)mac, port,
1925f61385dSMoni Shoua 		 dup ? "with" : "without");
193ffe455adSEugenia Emantayev 
1945f61385dSMoni Shoua 	if (need_mf_bond) {
1955f61385dSMoni Shoua 		if (port == 1) {
196ffe455adSEugenia Emantayev 			mutex_lock(&table->mutex);
19703a79f31SJack Morgenstein 			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
1985f61385dSMoni Shoua 		} else {
1995f61385dSMoni Shoua 			mutex_lock(&dup_table->mutex);
20003a79f31SJack Morgenstein 			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
2015f61385dSMoni Shoua 		}
2025f61385dSMoni Shoua 	} else {
2035f61385dSMoni Shoua 		mutex_lock(&table->mutex);
2045f61385dSMoni Shoua 	}
2055f61385dSMoni Shoua 
2065f61385dSMoni Shoua 	if (need_mf_bond) {
2075f61385dSMoni Shoua 		int index_at_port = -1;
2085f61385dSMoni Shoua 		int index_at_dup_port = -1;
2095f61385dSMoni Shoua 
2105f61385dSMoni Shoua 		for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
2115f61385dSMoni Shoua 			if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))))
2125f61385dSMoni Shoua 				index_at_port = i;
2135f61385dSMoni Shoua 			if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]))))
2145f61385dSMoni Shoua 				index_at_dup_port = i;
2155f61385dSMoni Shoua 		}
2165f61385dSMoni Shoua 
2175f61385dSMoni Shoua 		/* check that same mac is not in the tables at different indices */
2185f61385dSMoni Shoua 		if ((index_at_port != index_at_dup_port) &&
2195f61385dSMoni Shoua 		    (index_at_port >= 0) &&
2205f61385dSMoni Shoua 		    (index_at_dup_port >= 0))
2215f61385dSMoni Shoua 			can_mf_bond = false;
2225f61385dSMoni Shoua 
2235f61385dSMoni Shoua 		/* If the mac is already in the primary table, the slot must be
2245f61385dSMoni Shoua 		 * available in the duplicate table as well.
2255f61385dSMoni Shoua 		 */
2265f61385dSMoni Shoua 		if (index_at_port >= 0 && index_at_dup_port < 0 &&
2275f61385dSMoni Shoua 		    dup_table->refs[index_at_port]) {
2285f61385dSMoni Shoua 			can_mf_bond = false;
2295f61385dSMoni Shoua 		}
2305f61385dSMoni Shoua 		/* If the mac is already in the duplicate table, check that the
2315f61385dSMoni Shoua 		 * corresponding index is not occupied in the primary table, or
2325f61385dSMoni Shoua 		 * the primary table already contains the mac at the same index.
2335f61385dSMoni Shoua 		 * Otherwise, you cannot bond (primary contains a different mac
2345f61385dSMoni Shoua 		 * at that index).
2355f61385dSMoni Shoua 		 */
2365f61385dSMoni Shoua 		if (index_at_dup_port >= 0) {
2375f61385dSMoni Shoua 			if (!table->refs[index_at_dup_port] ||
2385f61385dSMoni Shoua 			    ((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[index_at_dup_port]))))
2395f61385dSMoni Shoua 				free_for_dup = index_at_dup_port;
2405f61385dSMoni Shoua 			else
2415f61385dSMoni Shoua 				can_mf_bond = false;
2425f61385dSMoni Shoua 		}
2435f61385dSMoni Shoua 	}
2445f61385dSMoni Shoua 
245ffe455adSEugenia Emantayev 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
246f4fd40b2SJack Morgenstein 		if (!table->refs[i]) {
247f4fd40b2SJack Morgenstein 			if (free < 0)
248ffe455adSEugenia Emantayev 				free = i;
2495f61385dSMoni Shoua 			if (free_for_dup < 0 && need_mf_bond && can_mf_bond) {
2505f61385dSMoni Shoua 				if (!dup_table->refs[i])
2515f61385dSMoni Shoua 					free_for_dup = i;
2525f61385dSMoni Shoua 			}
253ffe455adSEugenia Emantayev 			continue;
254ffe455adSEugenia Emantayev 		}
255ffe455adSEugenia Emantayev 
256f4fd40b2SJack Morgenstein 		if ((MLX4_MAC_MASK & mac) ==
257f4fd40b2SJack Morgenstein 		     (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
2586ce71acdSRony Efraim 			/* MAC already registered, increment ref count */
2596ce71acdSRony Efraim 			err = i;
2606ce71acdSRony Efraim 			++table->refs[i];
2615f61385dSMoni Shoua 			if (dup) {
2625f61385dSMoni Shoua 				u64 dup_mac = MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]);
2635f61385dSMoni Shoua 
2645f61385dSMoni Shoua 				if (dup_mac != mac || !dup_table->is_dup[i]) {
2655f61385dSMoni Shoua 					mlx4_warn(dev, "register mac: expect duplicate mac 0x%llx on port %d index %d\n",
2665f61385dSMoni Shoua 						  mac, dup_port, i);
2675f61385dSMoni Shoua 				}
2685f61385dSMoni Shoua 			}
269ffe455adSEugenia Emantayev 			goto out;
270ffe455adSEugenia Emantayev 		}
271ffe455adSEugenia Emantayev 	}
272ffe455adSEugenia Emantayev 
2735f61385dSMoni Shoua 	if (need_mf_bond && (free_for_dup < 0)) {
2745f61385dSMoni Shoua 		if (dup) {
2755f61385dSMoni Shoua 			mlx4_warn(dev, "Fail to allocate duplicate MAC table entry\n");
2765f61385dSMoni Shoua 			mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n");
2775f61385dSMoni Shoua 			dup = false;
2785f61385dSMoni Shoua 		}
2795f61385dSMoni Shoua 		can_mf_bond = false;
2805f61385dSMoni Shoua 	}
2815f61385dSMoni Shoua 
2825f61385dSMoni Shoua 	if (need_mf_bond && can_mf_bond)
2835f61385dSMoni Shoua 		free = free_for_dup;
2845f61385dSMoni Shoua 
285ffe455adSEugenia Emantayev 	mlx4_dbg(dev, "Free MAC index is %d\n", free);
286ffe455adSEugenia Emantayev 
287ffe455adSEugenia Emantayev 	if (table->total == table->max) {
288ffe455adSEugenia Emantayev 		/* No free mac entries */
289ffe455adSEugenia Emantayev 		err = -ENOSPC;
290ffe455adSEugenia Emantayev 		goto out;
291ffe455adSEugenia Emantayev 	}
292ffe455adSEugenia Emantayev 
293ffe455adSEugenia Emantayev 	/* Register new MAC */
294ffe455adSEugenia Emantayev 	table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
295ffe455adSEugenia Emantayev 
296ffe455adSEugenia Emantayev 	err = mlx4_set_port_mac_table(dev, port, table->entries);
297ffe455adSEugenia Emantayev 	if (unlikely(err)) {
298ffe455adSEugenia Emantayev 		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
299ffe455adSEugenia Emantayev 			 (unsigned long long) mac);
300ffe455adSEugenia Emantayev 		table->entries[free] = 0;
301ffe455adSEugenia Emantayev 		goto out;
302ffe455adSEugenia Emantayev 	}
3036ce71acdSRony Efraim 	table->refs[free] = 1;
3045f61385dSMoni Shoua 	table->is_dup[free] = false;
305ffe455adSEugenia Emantayev 	++table->total;
3065f61385dSMoni Shoua 	if (dup) {
3075f61385dSMoni Shoua 		dup_table->refs[free] = 0;
3085f61385dSMoni Shoua 		dup_table->is_dup[free] = true;
3095f61385dSMoni Shoua 		dup_table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
3105f61385dSMoni Shoua 
3115f61385dSMoni Shoua 		err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries);
3125f61385dSMoni Shoua 		if (unlikely(err)) {
3135f61385dSMoni Shoua 			mlx4_warn(dev, "Failed adding duplicate mac: 0x%llx\n", mac);
3145f61385dSMoni Shoua 			dup_table->is_dup[free] = false;
3155f61385dSMoni Shoua 			dup_table->entries[free] = 0;
3165f61385dSMoni Shoua 			goto out;
3175f61385dSMoni Shoua 		}
3185f61385dSMoni Shoua 		++dup_table->total;
3195f61385dSMoni Shoua 	}
3205f61385dSMoni Shoua 	err = free;
321ffe455adSEugenia Emantayev out:
3225f61385dSMoni Shoua 	if (need_mf_bond) {
3235f61385dSMoni Shoua 		if (port == 2) {
324ffe455adSEugenia Emantayev 			mutex_unlock(&table->mutex);
3255f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
3265f61385dSMoni Shoua 		} else {
3275f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
3285f61385dSMoni Shoua 			mutex_unlock(&table->mutex);
3295f61385dSMoni Shoua 		}
3305f61385dSMoni Shoua 	} else {
3315f61385dSMoni Shoua 		mutex_unlock(&table->mutex);
3325f61385dSMoni Shoua 	}
333ffe455adSEugenia Emantayev 	return err;
334ffe455adSEugenia Emantayev }
335ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_register_mac);
336ffe455adSEugenia Emantayev 
337ffe455adSEugenia Emantayev int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
338ffe455adSEugenia Emantayev {
339e7dbeba8SJack Morgenstein 	u64 out_param = 0;
340acddd5ddSJack Morgenstein 	int err = -EINVAL;
341ffe455adSEugenia Emantayev 
342ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
343acddd5ddSJack Morgenstein 		if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) {
344acddd5ddSJack Morgenstein 			err = mlx4_cmd_imm(dev, mac, &out_param,
345acddd5ddSJack Morgenstein 					   ((u32) port) << 8 | (u32) RES_MAC,
346acddd5ddSJack Morgenstein 					   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
347acddd5ddSJack Morgenstein 					   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
348acddd5ddSJack Morgenstein 		}
349acddd5ddSJack Morgenstein 		if (err && err == -EINVAL && mlx4_is_slave(dev)) {
350acddd5ddSJack Morgenstein 			/* retry using old REG_MAC format */
351ffe455adSEugenia Emantayev 			set_param_l(&out_param, port);
352ffe455adSEugenia Emantayev 			err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC,
353ffe455adSEugenia Emantayev 					   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
354ffe455adSEugenia Emantayev 					   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
355acddd5ddSJack Morgenstein 			if (!err)
356acddd5ddSJack Morgenstein 				dev->flags |= MLX4_FLAG_OLD_REG_MAC;
357acddd5ddSJack Morgenstein 		}
358ffe455adSEugenia Emantayev 		if (err)
359ffe455adSEugenia Emantayev 			return err;
360ffe455adSEugenia Emantayev 
361ffe455adSEugenia Emantayev 		return get_param_l(&out_param);
362ffe455adSEugenia Emantayev 	}
363ffe455adSEugenia Emantayev 	return __mlx4_register_mac(dev, port, mac);
364ffe455adSEugenia Emantayev }
365ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(mlx4_register_mac);
366ffe455adSEugenia Emantayev 
36716a10ffdSYan Burman int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port)
36816a10ffdSYan Burman {
36916a10ffdSYan Burman 	return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
37016a10ffdSYan Burman 			(port - 1) * (1 << dev->caps.log_num_macs);
37116a10ffdSYan Burman }
37216a10ffdSYan Burman EXPORT_SYMBOL_GPL(mlx4_get_base_qpn);
373ffe455adSEugenia Emantayev 
374ffe455adSEugenia Emantayev void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
375ffe455adSEugenia Emantayev {
376143b3efbSEugenia Emantayev 	struct mlx4_port_info *info;
377143b3efbSEugenia Emantayev 	struct mlx4_mac_table *table;
378ffe455adSEugenia Emantayev 	int index;
3795f61385dSMoni Shoua 	bool dup = mlx4_is_mf_bonded(dev);
3805f61385dSMoni Shoua 	u8 dup_port = (port == 1) ? 2 : 1;
3815f61385dSMoni Shoua 	struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
382ffe455adSEugenia Emantayev 
383143b3efbSEugenia Emantayev 	if (port < 1 || port > dev->caps.num_ports) {
384143b3efbSEugenia Emantayev 		mlx4_warn(dev, "invalid port number (%d), aborting...\n", port);
385143b3efbSEugenia Emantayev 		return;
386143b3efbSEugenia Emantayev 	}
387143b3efbSEugenia Emantayev 	info = &mlx4_priv(dev)->port[port];
388143b3efbSEugenia Emantayev 	table = &info->mac_table;
3895f61385dSMoni Shoua 
3905f61385dSMoni Shoua 	if (dup) {
3915f61385dSMoni Shoua 		if (port == 1) {
3925a2cc190SJeff Kirsher 			mutex_lock(&table->mutex);
39303a79f31SJack Morgenstein 			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
3945f61385dSMoni Shoua 		} else {
3955f61385dSMoni Shoua 			mutex_lock(&dup_table->mutex);
39603a79f31SJack Morgenstein 			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
3975f61385dSMoni Shoua 		}
3985f61385dSMoni Shoua 	} else {
3995f61385dSMoni Shoua 		mutex_lock(&table->mutex);
4005f61385dSMoni Shoua 	}
4015f61385dSMoni Shoua 
4026ce71acdSRony Efraim 	index = find_index(dev, table, mac);
4035a2cc190SJeff Kirsher 
4045a2cc190SJeff Kirsher 	if (validate_index(dev, table, index))
4055a2cc190SJeff Kirsher 		goto out;
4065f61385dSMoni Shoua 
4075f61385dSMoni Shoua 	if (--table->refs[index] || table->is_dup[index]) {
4081a91de28SJoe Perches 		mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n",
4091a91de28SJoe Perches 			 index);
4105f61385dSMoni Shoua 		if (!table->refs[index])
4115f61385dSMoni Shoua 			dup_table->is_dup[index] = false;
4126ce71acdSRony Efraim 		goto out;
4136ce71acdSRony Efraim 	}
4145a2cc190SJeff Kirsher 
4155a2cc190SJeff Kirsher 	table->entries[index] = 0;
4165f61385dSMoni Shoua 	if (mlx4_set_port_mac_table(dev, port, table->entries))
4175f61385dSMoni Shoua 		mlx4_warn(dev, "Fail to set mac in port %d during unregister\n", port);
4185a2cc190SJeff Kirsher 	--table->total;
4195f61385dSMoni Shoua 
4205f61385dSMoni Shoua 	if (dup) {
4215f61385dSMoni Shoua 		dup_table->is_dup[index] = false;
4225f61385dSMoni Shoua 		if (dup_table->refs[index])
4235f61385dSMoni Shoua 			goto out;
4245f61385dSMoni Shoua 		dup_table->entries[index] = 0;
4255f61385dSMoni Shoua 		if (mlx4_set_port_mac_table(dev, dup_port, dup_table->entries))
4265f61385dSMoni Shoua 			mlx4_warn(dev, "Fail to set mac in duplicate port %d during unregister\n", dup_port);
4275f61385dSMoni Shoua 
4285f61385dSMoni Shoua 		--table->total;
4295f61385dSMoni Shoua 	}
4305a2cc190SJeff Kirsher out:
4315f61385dSMoni Shoua 	if (dup) {
4325f61385dSMoni Shoua 		if (port == 2) {
4335a2cc190SJeff Kirsher 			mutex_unlock(&table->mutex);
4345f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
4355f61385dSMoni Shoua 		} else {
4365f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
4375f61385dSMoni Shoua 			mutex_unlock(&table->mutex);
4385f61385dSMoni Shoua 		}
4395f61385dSMoni Shoua 	} else {
4405f61385dSMoni Shoua 		mutex_unlock(&table->mutex);
4415f61385dSMoni Shoua 	}
4425a2cc190SJeff Kirsher }
443ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_unregister_mac);
444ffe455adSEugenia Emantayev 
445ffe455adSEugenia Emantayev void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
446ffe455adSEugenia Emantayev {
447e7dbeba8SJack Morgenstein 	u64 out_param = 0;
448ffe455adSEugenia Emantayev 
449ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
450acddd5ddSJack Morgenstein 		if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) {
451acddd5ddSJack Morgenstein 			(void) mlx4_cmd_imm(dev, mac, &out_param,
452acddd5ddSJack Morgenstein 					    ((u32) port) << 8 | (u32) RES_MAC,
453acddd5ddSJack Morgenstein 					    RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
454acddd5ddSJack Morgenstein 					    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
455acddd5ddSJack Morgenstein 		} else {
456acddd5ddSJack Morgenstein 			/* use old unregister mac format */
457ffe455adSEugenia Emantayev 			set_param_l(&out_param, port);
458162344edSOr Gerlitz 			(void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC,
459ffe455adSEugenia Emantayev 					    RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
460ffe455adSEugenia Emantayev 					    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
461acddd5ddSJack Morgenstein 		}
462ffe455adSEugenia Emantayev 		return;
463ffe455adSEugenia Emantayev 	}
464ffe455adSEugenia Emantayev 	__mlx4_unregister_mac(dev, port, mac);
465ffe455adSEugenia Emantayev 	return;
466ffe455adSEugenia Emantayev }
4675a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
4685a2cc190SJeff Kirsher 
46916a10ffdSYan Burman int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
4705a2cc190SJeff Kirsher {
4715a2cc190SJeff Kirsher 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
4725a2cc190SJeff Kirsher 	struct mlx4_mac_table *table = &info->mac_table;
473ffe455adSEugenia Emantayev 	int index = qpn - info->base_qpn;
474ffe455adSEugenia Emantayev 	int err = 0;
4755f61385dSMoni Shoua 	bool dup = mlx4_is_mf_bonded(dev);
4765f61385dSMoni Shoua 	u8 dup_port = (port == 1) ? 2 : 1;
4775f61385dSMoni Shoua 	struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
4785a2cc190SJeff Kirsher 
479ffe455adSEugenia Emantayev 	/* CX1 doesn't support multi-functions */
4805f61385dSMoni Shoua 	if (dup) {
4815f61385dSMoni Shoua 		if (port == 1) {
4825a2cc190SJeff Kirsher 			mutex_lock(&table->mutex);
48303a79f31SJack Morgenstein 			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
4845f61385dSMoni Shoua 		} else {
4855f61385dSMoni Shoua 			mutex_lock(&dup_table->mutex);
48603a79f31SJack Morgenstein 			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
4875f61385dSMoni Shoua 		}
4885f61385dSMoni Shoua 	} else {
4895f61385dSMoni Shoua 		mutex_lock(&table->mutex);
4905f61385dSMoni Shoua 	}
4915a2cc190SJeff Kirsher 
4925a2cc190SJeff Kirsher 	err = validate_index(dev, table, index);
4935a2cc190SJeff Kirsher 	if (err)
4945a2cc190SJeff Kirsher 		goto out;
4955a2cc190SJeff Kirsher 
4965a2cc190SJeff Kirsher 	table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
4975a2cc190SJeff Kirsher 
4985a2cc190SJeff Kirsher 	err = mlx4_set_port_mac_table(dev, port, table->entries);
4995a2cc190SJeff Kirsher 	if (unlikely(err)) {
500ffe455adSEugenia Emantayev 		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
501ffe455adSEugenia Emantayev 			 (unsigned long long) new_mac);
5025a2cc190SJeff Kirsher 		table->entries[index] = 0;
5035f61385dSMoni Shoua 	} else {
5045f61385dSMoni Shoua 		if (dup) {
5055f61385dSMoni Shoua 			dup_table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
5065f61385dSMoni Shoua 
5075f61385dSMoni Shoua 			err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries);
5085f61385dSMoni Shoua 			if (unlikely(err)) {
5095f61385dSMoni Shoua 				mlx4_err(dev, "Failed adding duplicate MAC: 0x%llx\n",
5105f61385dSMoni Shoua 					 (unsigned long long)new_mac);
5115f61385dSMoni Shoua 				dup_table->entries[index] = 0;
5125f61385dSMoni Shoua 			}
5135f61385dSMoni Shoua 		}
5145a2cc190SJeff Kirsher 	}
5155a2cc190SJeff Kirsher out:
5165f61385dSMoni Shoua 	if (dup) {
5175f61385dSMoni Shoua 		if (port == 2) {
5185a2cc190SJeff Kirsher 			mutex_unlock(&table->mutex);
5195f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
5205f61385dSMoni Shoua 		} else {
5215f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
5225f61385dSMoni Shoua 			mutex_unlock(&table->mutex);
5235f61385dSMoni Shoua 		}
5245f61385dSMoni Shoua 	} else {
5255f61385dSMoni Shoua 		mutex_unlock(&table->mutex);
5265f61385dSMoni Shoua 	}
5275a2cc190SJeff Kirsher 	return err;
5285a2cc190SJeff Kirsher }
52916a10ffdSYan Burman EXPORT_SYMBOL_GPL(__mlx4_replace_mac);
530ffe455adSEugenia Emantayev 
5315a2cc190SJeff Kirsher static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
5325a2cc190SJeff Kirsher 				    __be32 *entries)
5335a2cc190SJeff Kirsher {
5345a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *mailbox;
5355a2cc190SJeff Kirsher 	u32 in_mod;
5365a2cc190SJeff Kirsher 	int err;
5375a2cc190SJeff Kirsher 
5385a2cc190SJeff Kirsher 	mailbox = mlx4_alloc_cmd_mailbox(dev);
5395a2cc190SJeff Kirsher 	if (IS_ERR(mailbox))
5405a2cc190SJeff Kirsher 		return PTR_ERR(mailbox);
5415a2cc190SJeff Kirsher 
5425a2cc190SJeff Kirsher 	memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE);
5435a2cc190SJeff Kirsher 	in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port;
544a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
545a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
546a130b590SIdo Shamay 		       MLX4_CMD_NATIVE);
5475a2cc190SJeff Kirsher 
5485a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, mailbox);
5495a2cc190SJeff Kirsher 
5505a2cc190SJeff Kirsher 	return err;
5515a2cc190SJeff Kirsher }
5525a2cc190SJeff Kirsher 
5535a2cc190SJeff Kirsher int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
5545a2cc190SJeff Kirsher {
5555a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
5565a2cc190SJeff Kirsher 	int i;
5575a2cc190SJeff Kirsher 
5585a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) {
5595a2cc190SJeff Kirsher 		if (table->refs[i] &&
5605a2cc190SJeff Kirsher 		    (vid == (MLX4_VLAN_MASK &
5615a2cc190SJeff Kirsher 			      be32_to_cpu(table->entries[i])))) {
5625a2cc190SJeff Kirsher 			/* VLAN already registered, increase reference count */
5635a2cc190SJeff Kirsher 			*idx = i;
5645a2cc190SJeff Kirsher 			return 0;
5655a2cc190SJeff Kirsher 		}
5665a2cc190SJeff Kirsher 	}
5675a2cc190SJeff Kirsher 
5685a2cc190SJeff Kirsher 	return -ENOENT;
5695a2cc190SJeff Kirsher }
5705a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
5715a2cc190SJeff Kirsher 
5723f7fb021SRony Efraim int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
573ffe455adSEugenia Emantayev 				int *index)
5745a2cc190SJeff Kirsher {
5755a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
5765a2cc190SJeff Kirsher 	int i, err = 0;
5775a2cc190SJeff Kirsher 	int free = -1;
5785f61385dSMoni Shoua 	int free_for_dup = -1;
5795f61385dSMoni Shoua 	bool dup = mlx4_is_mf_bonded(dev);
5805f61385dSMoni Shoua 	u8 dup_port = (port == 1) ? 2 : 1;
5815f61385dSMoni Shoua 	struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table;
5825f61385dSMoni Shoua 	bool need_mf_bond = mlx4_need_mf_bond(dev);
5835f61385dSMoni Shoua 	bool can_mf_bond = true;
5845a2cc190SJeff Kirsher 
5855f61385dSMoni Shoua 	mlx4_dbg(dev, "Registering VLAN: %d for port %d %s duplicate\n",
5865f61385dSMoni Shoua 		 vlan, port,
5875f61385dSMoni Shoua 		 dup ? "with" : "without");
5885f61385dSMoni Shoua 
5895f61385dSMoni Shoua 	if (need_mf_bond) {
5905f61385dSMoni Shoua 		if (port == 1) {
5915a2cc190SJeff Kirsher 			mutex_lock(&table->mutex);
59203a79f31SJack Morgenstein 			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
5935f61385dSMoni Shoua 		} else {
5945f61385dSMoni Shoua 			mutex_lock(&dup_table->mutex);
59503a79f31SJack Morgenstein 			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
5965f61385dSMoni Shoua 		}
5975f61385dSMoni Shoua 	} else {
5985f61385dSMoni Shoua 		mutex_lock(&table->mutex);
5995f61385dSMoni Shoua 	}
600e72ebf5aSYevgeny Petrilin 
601e72ebf5aSYevgeny Petrilin 	if (table->total == table->max) {
602e72ebf5aSYevgeny Petrilin 		/* No free vlan entries */
603e72ebf5aSYevgeny Petrilin 		err = -ENOSPC;
604e72ebf5aSYevgeny Petrilin 		goto out;
605e72ebf5aSYevgeny Petrilin 	}
606e72ebf5aSYevgeny Petrilin 
6075f61385dSMoni Shoua 	if (need_mf_bond) {
6085f61385dSMoni Shoua 		int index_at_port = -1;
6095f61385dSMoni Shoua 		int index_at_dup_port = -1;
6105f61385dSMoni Shoua 
6115a2cc190SJeff Kirsher 		for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
6125f61385dSMoni Shoua 			if ((vlan == (MLX4_VLAN_MASK & be32_to_cpu(table->entries[i]))))
6135f61385dSMoni Shoua 				index_at_port = i;
6145f61385dSMoni Shoua 			if ((vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i]))))
6155f61385dSMoni Shoua 				index_at_dup_port = i;
6165f61385dSMoni Shoua 		}
6175f61385dSMoni Shoua 		/* check that same vlan is not in the tables at different indices */
6185f61385dSMoni Shoua 		if ((index_at_port != index_at_dup_port) &&
6195f61385dSMoni Shoua 		    (index_at_port >= 0) &&
6205f61385dSMoni Shoua 		    (index_at_dup_port >= 0))
6215f61385dSMoni Shoua 			can_mf_bond = false;
6225f61385dSMoni Shoua 
6235f61385dSMoni Shoua 		/* If the vlan is already in the primary table, the slot must be
6245f61385dSMoni Shoua 		 * available in the duplicate table as well.
6255f61385dSMoni Shoua 		 */
6265f61385dSMoni Shoua 		if (index_at_port >= 0 && index_at_dup_port < 0 &&
6275f61385dSMoni Shoua 		    dup_table->refs[index_at_port]) {
6285f61385dSMoni Shoua 			can_mf_bond = false;
6295f61385dSMoni Shoua 		}
6305f61385dSMoni Shoua 		/* If the vlan is already in the duplicate table, check that the
6315f61385dSMoni Shoua 		 * corresponding index is not occupied in the primary table, or
6325f61385dSMoni Shoua 		 * the primary table already contains the vlan at the same index.
6335f61385dSMoni Shoua 		 * Otherwise, you cannot bond (primary contains a different vlan
6345f61385dSMoni Shoua 		 * at that index).
6355f61385dSMoni Shoua 		 */
6365f61385dSMoni Shoua 		if (index_at_dup_port >= 0) {
6375f61385dSMoni Shoua 			if (!table->refs[index_at_dup_port] ||
6385f61385dSMoni Shoua 			    (vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[index_at_dup_port]))))
6395f61385dSMoni Shoua 				free_for_dup = index_at_dup_port;
6405f61385dSMoni Shoua 			else
6415f61385dSMoni Shoua 				can_mf_bond = false;
6425f61385dSMoni Shoua 		}
6435a2cc190SJeff Kirsher 	}
6445a2cc190SJeff Kirsher 
6455f61385dSMoni Shoua 	for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
6465f61385dSMoni Shoua 		if (!table->refs[i]) {
6475f61385dSMoni Shoua 			if (free < 0)
6485f61385dSMoni Shoua 				free = i;
6495f61385dSMoni Shoua 			if (free_for_dup < 0 && need_mf_bond && can_mf_bond) {
6505f61385dSMoni Shoua 				if (!dup_table->refs[i])
6515f61385dSMoni Shoua 					free_for_dup = i;
6525f61385dSMoni Shoua 			}
6535f61385dSMoni Shoua 		}
6545f61385dSMoni Shoua 
6555f61385dSMoni Shoua 		if ((table->refs[i] || table->is_dup[i]) &&
6565a2cc190SJeff Kirsher 		    (vlan == (MLX4_VLAN_MASK &
6575a2cc190SJeff Kirsher 			      be32_to_cpu(table->entries[i])))) {
6585a2cc190SJeff Kirsher 			/* Vlan already registered, increase references count */
6595f61385dSMoni Shoua 			mlx4_dbg(dev, "vlan %u is already registered.\n", vlan);
6605a2cc190SJeff Kirsher 			*index = i;
6615a2cc190SJeff Kirsher 			++table->refs[i];
6625f61385dSMoni Shoua 			if (dup) {
6635f61385dSMoni Shoua 				u16 dup_vlan = MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i]);
6645f61385dSMoni Shoua 
6655f61385dSMoni Shoua 				if (dup_vlan != vlan || !dup_table->is_dup[i]) {
6665f61385dSMoni Shoua 					mlx4_warn(dev, "register vlan: expected duplicate vlan %u on port %d index %d\n",
6675f61385dSMoni Shoua 						  vlan, dup_port, i);
6685f61385dSMoni Shoua 				}
6695f61385dSMoni Shoua 			}
6705a2cc190SJeff Kirsher 			goto out;
6715a2cc190SJeff Kirsher 		}
6725a2cc190SJeff Kirsher 	}
6735a2cc190SJeff Kirsher 
6745f61385dSMoni Shoua 	if (need_mf_bond && (free_for_dup < 0)) {
6755f61385dSMoni Shoua 		if (dup) {
6765f61385dSMoni Shoua 			mlx4_warn(dev, "Fail to allocate duplicate VLAN table entry\n");
6775f61385dSMoni Shoua 			mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n");
6785f61385dSMoni Shoua 			dup = false;
6795f61385dSMoni Shoua 		}
6805f61385dSMoni Shoua 		can_mf_bond = false;
6815f61385dSMoni Shoua 	}
6825f61385dSMoni Shoua 
6835f61385dSMoni Shoua 	if (need_mf_bond && can_mf_bond)
6845f61385dSMoni Shoua 		free = free_for_dup;
6855f61385dSMoni Shoua 
6865a2cc190SJeff Kirsher 	if (free < 0) {
6875a2cc190SJeff Kirsher 		err = -ENOMEM;
6885a2cc190SJeff Kirsher 		goto out;
6895a2cc190SJeff Kirsher 	}
6905a2cc190SJeff Kirsher 
691ffe455adSEugenia Emantayev 	/* Register new VLAN */
6925a2cc190SJeff Kirsher 	table->refs[free] = 1;
6935f61385dSMoni Shoua 	table->is_dup[free] = false;
6945a2cc190SJeff Kirsher 	table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
6955a2cc190SJeff Kirsher 
6965a2cc190SJeff Kirsher 	err = mlx4_set_port_vlan_table(dev, port, table->entries);
6975a2cc190SJeff Kirsher 	if (unlikely(err)) {
6985a2cc190SJeff Kirsher 		mlx4_warn(dev, "Failed adding vlan: %u\n", vlan);
6995a2cc190SJeff Kirsher 		table->refs[free] = 0;
7005a2cc190SJeff Kirsher 		table->entries[free] = 0;
7015a2cc190SJeff Kirsher 		goto out;
7025a2cc190SJeff Kirsher 	}
7035f61385dSMoni Shoua 	++table->total;
7045f61385dSMoni Shoua 	if (dup) {
7055f61385dSMoni Shoua 		dup_table->refs[free] = 0;
7065f61385dSMoni Shoua 		dup_table->is_dup[free] = true;
7075f61385dSMoni Shoua 		dup_table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
7085f61385dSMoni Shoua 
7095f61385dSMoni Shoua 		err = mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries);
7105f61385dSMoni Shoua 		if (unlikely(err)) {
7115f61385dSMoni Shoua 			mlx4_warn(dev, "Failed adding duplicate vlan: %u\n", vlan);
7125f61385dSMoni Shoua 			dup_table->is_dup[free] = false;
7135f61385dSMoni Shoua 			dup_table->entries[free] = 0;
7145f61385dSMoni Shoua 			goto out;
7155f61385dSMoni Shoua 		}
7165f61385dSMoni Shoua 		++dup_table->total;
7175f61385dSMoni Shoua 	}
7185a2cc190SJeff Kirsher 
7195a2cc190SJeff Kirsher 	*index = free;
7205a2cc190SJeff Kirsher out:
7215f61385dSMoni Shoua 	if (need_mf_bond) {
7225f61385dSMoni Shoua 		if (port == 2) {
7235a2cc190SJeff Kirsher 			mutex_unlock(&table->mutex);
7245f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
7255f61385dSMoni Shoua 		} else {
7265f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
7275f61385dSMoni Shoua 			mutex_unlock(&table->mutex);
7285f61385dSMoni Shoua 		}
7295f61385dSMoni Shoua 	} else {
7305f61385dSMoni Shoua 		mutex_unlock(&table->mutex);
7315f61385dSMoni Shoua 	}
7325a2cc190SJeff Kirsher 	return err;
7335a2cc190SJeff Kirsher }
734ffe455adSEugenia Emantayev 
735ffe455adSEugenia Emantayev int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
736ffe455adSEugenia Emantayev {
737e7dbeba8SJack Morgenstein 	u64 out_param = 0;
738ffe455adSEugenia Emantayev 	int err;
739ffe455adSEugenia Emantayev 
740162226a1SJack Morgenstein 	if (vlan > 4095)
741162226a1SJack Morgenstein 		return -EINVAL;
742162226a1SJack Morgenstein 
743ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
744acddd5ddSJack Morgenstein 		err = mlx4_cmd_imm(dev, vlan, &out_param,
745acddd5ddSJack Morgenstein 				   ((u32) port) << 8 | (u32) RES_VLAN,
746ffe455adSEugenia Emantayev 				   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
747ffe455adSEugenia Emantayev 				   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
748ffe455adSEugenia Emantayev 		if (!err)
749ffe455adSEugenia Emantayev 			*index = get_param_l(&out_param);
750ffe455adSEugenia Emantayev 
751ffe455adSEugenia Emantayev 		return err;
752ffe455adSEugenia Emantayev 	}
753ffe455adSEugenia Emantayev 	return __mlx4_register_vlan(dev, port, vlan, index);
754ffe455adSEugenia Emantayev }
7555a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_register_vlan);
7565a2cc190SJeff Kirsher 
7572009d005SJack Morgenstein void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
7585a2cc190SJeff Kirsher {
7595a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
7602009d005SJack Morgenstein 	int index;
7615f61385dSMoni Shoua 	bool dup = mlx4_is_mf_bonded(dev);
7625f61385dSMoni Shoua 	u8 dup_port = (port == 1) ? 2 : 1;
7635f61385dSMoni Shoua 	struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table;
7642009d005SJack Morgenstein 
7655f61385dSMoni Shoua 	if (dup) {
7665f61385dSMoni Shoua 		if (port == 1) {
7672009d005SJack Morgenstein 			mutex_lock(&table->mutex);
76803a79f31SJack Morgenstein 			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
7695f61385dSMoni Shoua 		} else {
7705f61385dSMoni Shoua 			mutex_lock(&dup_table->mutex);
77103a79f31SJack Morgenstein 			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
7725f61385dSMoni Shoua 		}
7735f61385dSMoni Shoua 	} else {
7745f61385dSMoni Shoua 		mutex_lock(&table->mutex);
7755f61385dSMoni Shoua 	}
7765f61385dSMoni Shoua 
7772009d005SJack Morgenstein 	if (mlx4_find_cached_vlan(dev, port, vlan, &index)) {
7782009d005SJack Morgenstein 		mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan);
7792009d005SJack Morgenstein 		goto out;
7802009d005SJack Morgenstein 	}
7815a2cc190SJeff Kirsher 
7825a2cc190SJeff Kirsher 	if (index < MLX4_VLAN_REGULAR) {
7835a2cc190SJeff Kirsher 		mlx4_warn(dev, "Trying to free special vlan index %d\n", index);
7845a2cc190SJeff Kirsher 		goto out;
7855a2cc190SJeff Kirsher 	}
7862009d005SJack Morgenstein 
7875f61385dSMoni Shoua 	if (--table->refs[index] || table->is_dup[index]) {
7881a91de28SJoe Perches 		mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n",
7891a91de28SJoe Perches 			 table->refs[index], index);
7905f61385dSMoni Shoua 		if (!table->refs[index])
7915f61385dSMoni Shoua 			dup_table->is_dup[index] = false;
7925a2cc190SJeff Kirsher 		goto out;
7935a2cc190SJeff Kirsher 	}
7945a2cc190SJeff Kirsher 	table->entries[index] = 0;
7955f61385dSMoni Shoua 	if (mlx4_set_port_vlan_table(dev, port, table->entries))
7965f61385dSMoni Shoua 		mlx4_warn(dev, "Fail to set vlan in port %d during unregister\n", port);
7975a2cc190SJeff Kirsher 	--table->total;
7985f61385dSMoni Shoua 	if (dup) {
7995f61385dSMoni Shoua 		dup_table->is_dup[index] = false;
8005f61385dSMoni Shoua 		if (dup_table->refs[index])
8015f61385dSMoni Shoua 			goto out;
8025f61385dSMoni Shoua 		dup_table->entries[index] = 0;
8035f61385dSMoni Shoua 		if (mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries))
8045f61385dSMoni Shoua 			mlx4_warn(dev, "Fail to set vlan in duplicate port %d during unregister\n", dup_port);
8055f61385dSMoni Shoua 		--dup_table->total;
8065f61385dSMoni Shoua 	}
8075a2cc190SJeff Kirsher out:
8085f61385dSMoni Shoua 	if (dup) {
8095f61385dSMoni Shoua 		if (port == 2) {
8105a2cc190SJeff Kirsher 			mutex_unlock(&table->mutex);
8115f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
8125f61385dSMoni Shoua 		} else {
8135f61385dSMoni Shoua 			mutex_unlock(&dup_table->mutex);
8145f61385dSMoni Shoua 			mutex_unlock(&table->mutex);
8155f61385dSMoni Shoua 		}
8165f61385dSMoni Shoua 	} else {
8175f61385dSMoni Shoua 		mutex_unlock(&table->mutex);
8185f61385dSMoni Shoua 	}
8195a2cc190SJeff Kirsher }
820ffe455adSEugenia Emantayev 
8212009d005SJack Morgenstein void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
822ffe455adSEugenia Emantayev {
823162226a1SJack Morgenstein 	u64 out_param = 0;
824ffe455adSEugenia Emantayev 
825ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
8262009d005SJack Morgenstein 		(void) mlx4_cmd_imm(dev, vlan, &out_param,
827acddd5ddSJack Morgenstein 				    ((u32) port) << 8 | (u32) RES_VLAN,
828162226a1SJack Morgenstein 				    RES_OP_RESERVE_AND_MAP,
829ffe455adSEugenia Emantayev 				    MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A,
830ffe455adSEugenia Emantayev 				    MLX4_CMD_WRAPPED);
831ffe455adSEugenia Emantayev 		return;
832ffe455adSEugenia Emantayev 	}
8332009d005SJack Morgenstein 	__mlx4_unregister_vlan(dev, port, vlan);
834ffe455adSEugenia Emantayev }
8355a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_vlan);
8365a2cc190SJeff Kirsher 
8375f61385dSMoni Shoua int mlx4_bond_mac_table(struct mlx4_dev *dev)
8385f61385dSMoni Shoua {
8395f61385dSMoni Shoua 	struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table;
8405f61385dSMoni Shoua 	struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table;
8415f61385dSMoni Shoua 	int ret = 0;
8425f61385dSMoni Shoua 	int i;
8435f61385dSMoni Shoua 	bool update1 = false;
8445f61385dSMoni Shoua 	bool update2 = false;
8455f61385dSMoni Shoua 
8465f61385dSMoni Shoua 	mutex_lock(&t1->mutex);
8475f61385dSMoni Shoua 	mutex_lock(&t2->mutex);
8485f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
8495f61385dSMoni Shoua 		if ((t1->entries[i] != t2->entries[i]) &&
8505f61385dSMoni Shoua 		    t1->entries[i] && t2->entries[i]) {
8515f61385dSMoni Shoua 			mlx4_warn(dev, "can't duplicate entry %d in mac table\n", i);
8525f61385dSMoni Shoua 			ret = -EINVAL;
8535f61385dSMoni Shoua 			goto unlock;
8545f61385dSMoni Shoua 		}
8555f61385dSMoni Shoua 	}
8565f61385dSMoni Shoua 
8575f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
8585f61385dSMoni Shoua 		if (t1->entries[i] && !t2->entries[i]) {
8595f61385dSMoni Shoua 			t2->entries[i] = t1->entries[i];
8605f61385dSMoni Shoua 			t2->is_dup[i] = true;
8615f61385dSMoni Shoua 			update2 = true;
8625f61385dSMoni Shoua 		} else if (!t1->entries[i] && t2->entries[i]) {
8635f61385dSMoni Shoua 			t1->entries[i] = t2->entries[i];
8645f61385dSMoni Shoua 			t1->is_dup[i] = true;
8655f61385dSMoni Shoua 			update1 = true;
8665f61385dSMoni Shoua 		} else if (t1->entries[i] && t2->entries[i]) {
8675f61385dSMoni Shoua 			t1->is_dup[i] = true;
8685f61385dSMoni Shoua 			t2->is_dup[i] = true;
8695f61385dSMoni Shoua 		}
8705f61385dSMoni Shoua 	}
8715f61385dSMoni Shoua 
8725f61385dSMoni Shoua 	if (update1) {
8735f61385dSMoni Shoua 		ret = mlx4_set_port_mac_table(dev, 1, t1->entries);
8745f61385dSMoni Shoua 		if (ret)
8755f61385dSMoni Shoua 			mlx4_warn(dev, "failed to set MAC table for port 1 (%d)\n", ret);
8765f61385dSMoni Shoua 	}
8775f61385dSMoni Shoua 	if (!ret && update2) {
8785f61385dSMoni Shoua 		ret = mlx4_set_port_mac_table(dev, 2, t2->entries);
8795f61385dSMoni Shoua 		if (ret)
8805f61385dSMoni Shoua 			mlx4_warn(dev, "failed to set MAC table for port 2 (%d)\n", ret);
8815f61385dSMoni Shoua 	}
8825f61385dSMoni Shoua 
8835f61385dSMoni Shoua 	if (ret)
8845f61385dSMoni Shoua 		mlx4_warn(dev, "failed to create mirror MAC tables\n");
8855f61385dSMoni Shoua unlock:
8865f61385dSMoni Shoua 	mutex_unlock(&t2->mutex);
8875f61385dSMoni Shoua 	mutex_unlock(&t1->mutex);
8885f61385dSMoni Shoua 	return ret;
8895f61385dSMoni Shoua }
8905f61385dSMoni Shoua 
8915f61385dSMoni Shoua int mlx4_unbond_mac_table(struct mlx4_dev *dev)
8925f61385dSMoni Shoua {
8935f61385dSMoni Shoua 	struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table;
8945f61385dSMoni Shoua 	struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table;
8955f61385dSMoni Shoua 	int ret = 0;
8965f61385dSMoni Shoua 	int ret1;
8975f61385dSMoni Shoua 	int i;
8985f61385dSMoni Shoua 	bool update1 = false;
8995f61385dSMoni Shoua 	bool update2 = false;
9005f61385dSMoni Shoua 
9015f61385dSMoni Shoua 	mutex_lock(&t1->mutex);
9025f61385dSMoni Shoua 	mutex_lock(&t2->mutex);
9035f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
9045f61385dSMoni Shoua 		if (t1->entries[i] != t2->entries[i]) {
9055f61385dSMoni Shoua 			mlx4_warn(dev, "mac table is in an unexpected state when trying to unbond\n");
9065f61385dSMoni Shoua 			ret = -EINVAL;
9075f61385dSMoni Shoua 			goto unlock;
9085f61385dSMoni Shoua 		}
9095f61385dSMoni Shoua 	}
9105f61385dSMoni Shoua 
9115f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
9125f61385dSMoni Shoua 		if (!t1->entries[i])
9135f61385dSMoni Shoua 			continue;
9145f61385dSMoni Shoua 		t1->is_dup[i] = false;
9155f61385dSMoni Shoua 		if (!t1->refs[i]) {
9165f61385dSMoni Shoua 			t1->entries[i] = 0;
9175f61385dSMoni Shoua 			update1 = true;
9185f61385dSMoni Shoua 		}
9195f61385dSMoni Shoua 		t2->is_dup[i] = false;
9205f61385dSMoni Shoua 		if (!t2->refs[i]) {
9215f61385dSMoni Shoua 			t2->entries[i] = 0;
9225f61385dSMoni Shoua 			update2 = true;
9235f61385dSMoni Shoua 		}
9245f61385dSMoni Shoua 	}
9255f61385dSMoni Shoua 
9265f61385dSMoni Shoua 	if (update1) {
9275f61385dSMoni Shoua 		ret = mlx4_set_port_mac_table(dev, 1, t1->entries);
9285f61385dSMoni Shoua 		if (ret)
9295f61385dSMoni Shoua 			mlx4_warn(dev, "failed to unmirror MAC tables for port 1(%d)\n", ret);
9305f61385dSMoni Shoua 	}
9315f61385dSMoni Shoua 	if (update2) {
9325f61385dSMoni Shoua 		ret1 = mlx4_set_port_mac_table(dev, 2, t2->entries);
9335f61385dSMoni Shoua 		if (ret1) {
9345f61385dSMoni Shoua 			mlx4_warn(dev, "failed to unmirror MAC tables for port 2(%d)\n", ret1);
9355f61385dSMoni Shoua 			ret = ret1;
9365f61385dSMoni Shoua 		}
9375f61385dSMoni Shoua 	}
9385f61385dSMoni Shoua unlock:
9395f61385dSMoni Shoua 	mutex_unlock(&t2->mutex);
9405f61385dSMoni Shoua 	mutex_unlock(&t1->mutex);
9415f61385dSMoni Shoua 	return ret;
9425f61385dSMoni Shoua }
9435f61385dSMoni Shoua 
9445f61385dSMoni Shoua int mlx4_bond_vlan_table(struct mlx4_dev *dev)
9455f61385dSMoni Shoua {
9465f61385dSMoni Shoua 	struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table;
9475f61385dSMoni Shoua 	struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table;
9485f61385dSMoni Shoua 	int ret = 0;
9495f61385dSMoni Shoua 	int i;
9505f61385dSMoni Shoua 	bool update1 = false;
9515f61385dSMoni Shoua 	bool update2 = false;
9525f61385dSMoni Shoua 
9535f61385dSMoni Shoua 	mutex_lock(&t1->mutex);
9545f61385dSMoni Shoua 	mutex_lock(&t2->mutex);
9555f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
9565f61385dSMoni Shoua 		if ((t1->entries[i] != t2->entries[i]) &&
9575f61385dSMoni Shoua 		    t1->entries[i] && t2->entries[i]) {
9585f61385dSMoni Shoua 			mlx4_warn(dev, "can't duplicate entry %d in vlan table\n", i);
9595f61385dSMoni Shoua 			ret = -EINVAL;
9605f61385dSMoni Shoua 			goto unlock;
9615f61385dSMoni Shoua 		}
9625f61385dSMoni Shoua 	}
9635f61385dSMoni Shoua 
9645f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
9655f61385dSMoni Shoua 		if (t1->entries[i] && !t2->entries[i]) {
9665f61385dSMoni Shoua 			t2->entries[i] = t1->entries[i];
9675f61385dSMoni Shoua 			t2->is_dup[i] = true;
9685f61385dSMoni Shoua 			update2 = true;
9695f61385dSMoni Shoua 		} else if (!t1->entries[i] && t2->entries[i]) {
9705f61385dSMoni Shoua 			t1->entries[i] = t2->entries[i];
9715f61385dSMoni Shoua 			t1->is_dup[i] = true;
9725f61385dSMoni Shoua 			update1 = true;
9735f61385dSMoni Shoua 		} else if (t1->entries[i] && t2->entries[i]) {
9745f61385dSMoni Shoua 			t1->is_dup[i] = true;
9755f61385dSMoni Shoua 			t2->is_dup[i] = true;
9765f61385dSMoni Shoua 		}
9775f61385dSMoni Shoua 	}
9785f61385dSMoni Shoua 
9795f61385dSMoni Shoua 	if (update1) {
9805f61385dSMoni Shoua 		ret = mlx4_set_port_vlan_table(dev, 1, t1->entries);
9815f61385dSMoni Shoua 		if (ret)
9825f61385dSMoni Shoua 			mlx4_warn(dev, "failed to set VLAN table for port 1 (%d)\n", ret);
9835f61385dSMoni Shoua 	}
9845f61385dSMoni Shoua 	if (!ret && update2) {
9855f61385dSMoni Shoua 		ret = mlx4_set_port_vlan_table(dev, 2, t2->entries);
9865f61385dSMoni Shoua 		if (ret)
9875f61385dSMoni Shoua 			mlx4_warn(dev, "failed to set VLAN table for port 2 (%d)\n", ret);
9885f61385dSMoni Shoua 	}
9895f61385dSMoni Shoua 
9905f61385dSMoni Shoua 	if (ret)
9915f61385dSMoni Shoua 		mlx4_warn(dev, "failed to create mirror VLAN tables\n");
9925f61385dSMoni Shoua unlock:
9935f61385dSMoni Shoua 	mutex_unlock(&t2->mutex);
9945f61385dSMoni Shoua 	mutex_unlock(&t1->mutex);
9955f61385dSMoni Shoua 	return ret;
9965f61385dSMoni Shoua }
9975f61385dSMoni Shoua 
9985f61385dSMoni Shoua int mlx4_unbond_vlan_table(struct mlx4_dev *dev)
9995f61385dSMoni Shoua {
10005f61385dSMoni Shoua 	struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table;
10015f61385dSMoni Shoua 	struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table;
10025f61385dSMoni Shoua 	int ret = 0;
10035f61385dSMoni Shoua 	int ret1;
10045f61385dSMoni Shoua 	int i;
10055f61385dSMoni Shoua 	bool update1 = false;
10065f61385dSMoni Shoua 	bool update2 = false;
10075f61385dSMoni Shoua 
10085f61385dSMoni Shoua 	mutex_lock(&t1->mutex);
10095f61385dSMoni Shoua 	mutex_lock(&t2->mutex);
10105f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
10115f61385dSMoni Shoua 		if (t1->entries[i] != t2->entries[i]) {
10125f61385dSMoni Shoua 			mlx4_warn(dev, "vlan table is in an unexpected state when trying to unbond\n");
10135f61385dSMoni Shoua 			ret = -EINVAL;
10145f61385dSMoni Shoua 			goto unlock;
10155f61385dSMoni Shoua 		}
10165f61385dSMoni Shoua 	}
10175f61385dSMoni Shoua 
10185f61385dSMoni Shoua 	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
10195f61385dSMoni Shoua 		if (!t1->entries[i])
10205f61385dSMoni Shoua 			continue;
10215f61385dSMoni Shoua 		t1->is_dup[i] = false;
10225f61385dSMoni Shoua 		if (!t1->refs[i]) {
10235f61385dSMoni Shoua 			t1->entries[i] = 0;
10245f61385dSMoni Shoua 			update1 = true;
10255f61385dSMoni Shoua 		}
10265f61385dSMoni Shoua 		t2->is_dup[i] = false;
10275f61385dSMoni Shoua 		if (!t2->refs[i]) {
10285f61385dSMoni Shoua 			t2->entries[i] = 0;
10295f61385dSMoni Shoua 			update2 = true;
10305f61385dSMoni Shoua 		}
10315f61385dSMoni Shoua 	}
10325f61385dSMoni Shoua 
10335f61385dSMoni Shoua 	if (update1) {
10345f61385dSMoni Shoua 		ret = mlx4_set_port_vlan_table(dev, 1, t1->entries);
10355f61385dSMoni Shoua 		if (ret)
10365f61385dSMoni Shoua 			mlx4_warn(dev, "failed to unmirror VLAN tables for port 1(%d)\n", ret);
10375f61385dSMoni Shoua 	}
10385f61385dSMoni Shoua 	if (update2) {
10395f61385dSMoni Shoua 		ret1 = mlx4_set_port_vlan_table(dev, 2, t2->entries);
10405f61385dSMoni Shoua 		if (ret1) {
10415f61385dSMoni Shoua 			mlx4_warn(dev, "failed to unmirror VLAN tables for port 2(%d)\n", ret1);
10425f61385dSMoni Shoua 			ret = ret1;
10435f61385dSMoni Shoua 		}
10445f61385dSMoni Shoua 	}
10455f61385dSMoni Shoua unlock:
10465f61385dSMoni Shoua 	mutex_unlock(&t2->mutex);
10475f61385dSMoni Shoua 	mutex_unlock(&t1->mutex);
10485f61385dSMoni Shoua 	return ret;
10495f61385dSMoni Shoua }
10505f61385dSMoni Shoua 
10515a2cc190SJeff Kirsher int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
10525a2cc190SJeff Kirsher {
10535a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
10545a2cc190SJeff Kirsher 	u8 *inbuf, *outbuf;
10555a2cc190SJeff Kirsher 	int err;
10565a2cc190SJeff Kirsher 
10575a2cc190SJeff Kirsher 	inmailbox = mlx4_alloc_cmd_mailbox(dev);
10585a2cc190SJeff Kirsher 	if (IS_ERR(inmailbox))
10595a2cc190SJeff Kirsher 		return PTR_ERR(inmailbox);
10605a2cc190SJeff Kirsher 
10615a2cc190SJeff Kirsher 	outmailbox = mlx4_alloc_cmd_mailbox(dev);
10625a2cc190SJeff Kirsher 	if (IS_ERR(outmailbox)) {
10635a2cc190SJeff Kirsher 		mlx4_free_cmd_mailbox(dev, inmailbox);
10645a2cc190SJeff Kirsher 		return PTR_ERR(outmailbox);
10655a2cc190SJeff Kirsher 	}
10665a2cc190SJeff Kirsher 
10675a2cc190SJeff Kirsher 	inbuf = inmailbox->buf;
10685a2cc190SJeff Kirsher 	outbuf = outmailbox->buf;
10695a2cc190SJeff Kirsher 	inbuf[0] = 1;
10705a2cc190SJeff Kirsher 	inbuf[1] = 1;
10715a2cc190SJeff Kirsher 	inbuf[2] = 1;
10725a2cc190SJeff Kirsher 	inbuf[3] = 1;
10735a2cc190SJeff Kirsher 	*(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015);
10745a2cc190SJeff Kirsher 	*(__be32 *) (&inbuf[20]) = cpu_to_be32(port);
10755a2cc190SJeff Kirsher 
10765a2cc190SJeff Kirsher 	err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3,
1077f9baff50SJack Morgenstein 			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
1078f9baff50SJack Morgenstein 			   MLX4_CMD_NATIVE);
10795a2cc190SJeff Kirsher 	if (!err)
10805a2cc190SJeff Kirsher 		*caps = *(__be32 *) (outbuf + 84);
10815a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, inmailbox);
10825a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, outmailbox);
10835a2cc190SJeff Kirsher 	return err;
10845a2cc190SJeff Kirsher }
10859cd59352SJack Morgenstein static struct mlx4_roce_gid_entry zgid_entry;
10865a2cc190SJeff Kirsher 
1087449fc488SMatan Barak int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port)
1088b6ffaeffSJack Morgenstein {
1089449fc488SMatan Barak 	int vfs;
1090449fc488SMatan Barak 	int slave_gid = slave;
1091449fc488SMatan Barak 	unsigned i;
1092449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
1093449fc488SMatan Barak 	struct mlx4_active_ports actv_ports;
1094449fc488SMatan Barak 	unsigned max_port_p_one;
1095449fc488SMatan Barak 
1096b6ffaeffSJack Morgenstein 	if (slave == 0)
1097b6ffaeffSJack Morgenstein 		return MLX4_ROCE_PF_GIDS;
1098449fc488SMatan Barak 
1099449fc488SMatan Barak 	/* Slave is a VF */
1100449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1101449fc488SMatan Barak 	actv_ports = mlx4_get_active_ports(dev, slave);
1102449fc488SMatan Barak 	max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
1103449fc488SMatan Barak 		bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
1104449fc488SMatan Barak 
1105449fc488SMatan Barak 	for (i = 1; i < max_port_p_one; i++) {
1106449fc488SMatan Barak 		struct mlx4_active_ports exclusive_ports;
1107449fc488SMatan Barak 		struct mlx4_slaves_pport slaves_pport_actv;
1108449fc488SMatan Barak 		bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
1109449fc488SMatan Barak 		set_bit(i - 1, exclusive_ports.ports);
1110449fc488SMatan Barak 		if (i == port)
1111449fc488SMatan Barak 			continue;
1112449fc488SMatan Barak 		slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
1113449fc488SMatan Barak 				    dev, &exclusive_ports);
1114449fc488SMatan Barak 		slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
1115872bf2fbSYishai Hadas 					   dev->persist->num_vfs + 1);
1116449fc488SMatan Barak 	}
1117872bf2fbSYishai Hadas 	vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1;
1118449fc488SMatan Barak 	if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs))
1119449fc488SMatan Barak 		return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1;
1120449fc488SMatan Barak 	return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs;
1121b6ffaeffSJack Morgenstein }
1122b6ffaeffSJack Morgenstein 
1123449fc488SMatan Barak int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port)
1124b6ffaeffSJack Morgenstein {
1125b6ffaeffSJack Morgenstein 	int gids;
1126449fc488SMatan Barak 	unsigned i;
1127449fc488SMatan Barak 	int slave_gid = slave;
1128b6ffaeffSJack Morgenstein 	int vfs;
1129b6ffaeffSJack Morgenstein 
1130449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
1131449fc488SMatan Barak 	struct mlx4_active_ports actv_ports;
1132449fc488SMatan Barak 	unsigned max_port_p_one;
1133b6ffaeffSJack Morgenstein 
1134b6ffaeffSJack Morgenstein 	if (slave == 0)
1135b6ffaeffSJack Morgenstein 		return 0;
1136b6ffaeffSJack Morgenstein 
1137449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1138449fc488SMatan Barak 	actv_ports = mlx4_get_active_ports(dev, slave);
1139449fc488SMatan Barak 	max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
1140449fc488SMatan Barak 		bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
1141449fc488SMatan Barak 
1142449fc488SMatan Barak 	for (i = 1; i < max_port_p_one; i++) {
1143449fc488SMatan Barak 		struct mlx4_active_ports exclusive_ports;
1144449fc488SMatan Barak 		struct mlx4_slaves_pport slaves_pport_actv;
1145449fc488SMatan Barak 		bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
1146449fc488SMatan Barak 		set_bit(i - 1, exclusive_ports.ports);
1147449fc488SMatan Barak 		if (i == port)
1148449fc488SMatan Barak 			continue;
1149449fc488SMatan Barak 		slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
1150449fc488SMatan Barak 				    dev, &exclusive_ports);
1151449fc488SMatan Barak 		slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
1152872bf2fbSYishai Hadas 					   dev->persist->num_vfs + 1);
1153b6ffaeffSJack Morgenstein 	}
1154449fc488SMatan Barak 	gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
1155872bf2fbSYishai Hadas 	vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1;
1156449fc488SMatan Barak 	if (slave_gid <= gids % vfs)
1157449fc488SMatan Barak 		return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1);
1158449fc488SMatan Barak 
1159449fc488SMatan Barak 	return MLX4_ROCE_PF_GIDS + (gids % vfs) +
1160449fc488SMatan Barak 		((gids / vfs) * (slave_gid - 1));
1161449fc488SMatan Barak }
1162449fc488SMatan Barak EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix);
1163b6ffaeffSJack Morgenstein 
1164111c6094SJack Morgenstein static int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave,
1165111c6094SJack Morgenstein 				     int port, struct mlx4_cmd_mailbox *mailbox)
1166111c6094SJack Morgenstein {
1167111c6094SJack Morgenstein 	struct mlx4_roce_gid_entry *gid_entry_mbox;
1168111c6094SJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
1169111c6094SJack Morgenstein 	int num_gids, base, offset;
1170111c6094SJack Morgenstein 	int i, err;
1171111c6094SJack Morgenstein 
1172111c6094SJack Morgenstein 	num_gids = mlx4_get_slave_num_gids(dev, slave, port);
1173111c6094SJack Morgenstein 	base = mlx4_get_base_gid_ix(dev, slave, port);
1174111c6094SJack Morgenstein 
1175111c6094SJack Morgenstein 	memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE);
1176111c6094SJack Morgenstein 
1177111c6094SJack Morgenstein 	mutex_lock(&(priv->port[port].gid_table.mutex));
1178111c6094SJack Morgenstein 	/* Zero-out gids belonging to that slave in the port GID table */
1179111c6094SJack Morgenstein 	for (i = 0, offset = base; i < num_gids; offset++, i++)
1180111c6094SJack Morgenstein 		memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
1181111c6094SJack Morgenstein 		       zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE);
1182111c6094SJack Morgenstein 
1183111c6094SJack Morgenstein 	/* Now, copy roce port gids table to mailbox for passing to FW */
1184111c6094SJack Morgenstein 	gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf;
1185111c6094SJack Morgenstein 	for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
1186111c6094SJack Morgenstein 		memcpy(gid_entry_mbox->raw,
1187111c6094SJack Morgenstein 		       priv->port[port].gid_table.roce_gids[i].raw,
1188111c6094SJack Morgenstein 		       MLX4_ROCE_GID_ENTRY_SIZE);
1189111c6094SJack Morgenstein 
1190111c6094SJack Morgenstein 	err = mlx4_cmd(dev, mailbox->dma,
1191a130b590SIdo Shamay 		       ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8),
1192a130b590SIdo Shamay 		       MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT,
1193a130b590SIdo Shamay 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
1194111c6094SJack Morgenstein 	mutex_unlock(&(priv->port[port].gid_table.mutex));
1195111c6094SJack Morgenstein 	return err;
1196111c6094SJack Morgenstein }
1197111c6094SJack Morgenstein 
1198111c6094SJack Morgenstein 
1199111c6094SJack Morgenstein void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave)
1200111c6094SJack Morgenstein {
1201111c6094SJack Morgenstein 	struct mlx4_active_ports actv_ports;
1202111c6094SJack Morgenstein 	struct mlx4_cmd_mailbox *mailbox;
1203111c6094SJack Morgenstein 	int num_eth_ports, err;
1204111c6094SJack Morgenstein 	int i;
1205111c6094SJack Morgenstein 
1206872bf2fbSYishai Hadas 	if (slave < 0 || slave > dev->persist->num_vfs)
1207111c6094SJack Morgenstein 		return;
1208111c6094SJack Morgenstein 
1209111c6094SJack Morgenstein 	actv_ports = mlx4_get_active_ports(dev, slave);
1210111c6094SJack Morgenstein 
1211111c6094SJack Morgenstein 	for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) {
1212111c6094SJack Morgenstein 		if (test_bit(i, actv_ports.ports)) {
1213111c6094SJack Morgenstein 			if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
1214111c6094SJack Morgenstein 				continue;
1215111c6094SJack Morgenstein 			num_eth_ports++;
1216111c6094SJack Morgenstein 		}
1217111c6094SJack Morgenstein 	}
1218111c6094SJack Morgenstein 
1219111c6094SJack Morgenstein 	if (!num_eth_ports)
1220111c6094SJack Morgenstein 		return;
1221111c6094SJack Morgenstein 
1222111c6094SJack Morgenstein 	/* have ETH ports.  Alloc mailbox for SET_PORT command */
1223111c6094SJack Morgenstein 	mailbox = mlx4_alloc_cmd_mailbox(dev);
1224111c6094SJack Morgenstein 	if (IS_ERR(mailbox))
1225111c6094SJack Morgenstein 		return;
1226111c6094SJack Morgenstein 
1227111c6094SJack Morgenstein 	for (i = 0; i < dev->caps.num_ports; i++) {
1228111c6094SJack Morgenstein 		if (test_bit(i, actv_ports.ports)) {
1229111c6094SJack Morgenstein 			if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
1230111c6094SJack Morgenstein 				continue;
1231111c6094SJack Morgenstein 			err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox);
1232111c6094SJack Morgenstein 			if (err)
1233111c6094SJack Morgenstein 				mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n",
1234111c6094SJack Morgenstein 					  slave, i + 1, err);
1235111c6094SJack Morgenstein 		}
1236111c6094SJack Morgenstein 	}
1237111c6094SJack Morgenstein 
1238111c6094SJack Morgenstein 	mlx4_free_cmd_mailbox(dev, mailbox);
1239111c6094SJack Morgenstein 	return;
1240111c6094SJack Morgenstein }
1241111c6094SJack Morgenstein 
1242ffe455adSEugenia Emantayev static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
1243ffe455adSEugenia Emantayev 				u8 op_mod, struct mlx4_cmd_mailbox *inbox)
1244ffe455adSEugenia Emantayev {
1245ffe455adSEugenia Emantayev 	struct mlx4_priv *priv = mlx4_priv(dev);
1246ffe455adSEugenia Emantayev 	struct mlx4_port_info *port_info;
1247ffe455adSEugenia Emantayev 	struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
1248ffe455adSEugenia Emantayev 	struct mlx4_slave_state *slave_st = &master->slave_state[slave];
1249ffe455adSEugenia Emantayev 	struct mlx4_set_port_rqp_calc_context *qpn_context;
1250ffe455adSEugenia Emantayev 	struct mlx4_set_port_general_context *gen_context;
1251b6ffaeffSJack Morgenstein 	struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1;
1252ffe455adSEugenia Emantayev 	int reset_qkey_viols;
1253ffe455adSEugenia Emantayev 	int port;
1254ffe455adSEugenia Emantayev 	int is_eth;
1255b6ffaeffSJack Morgenstein 	int num_gids;
1256b6ffaeffSJack Morgenstein 	int base;
1257ffe455adSEugenia Emantayev 	u32 in_modifier;
1258ffe455adSEugenia Emantayev 	u32 promisc;
1259ffe455adSEugenia Emantayev 	u16 mtu, prev_mtu;
1260ffe455adSEugenia Emantayev 	int err;
1261b6ffaeffSJack Morgenstein 	int i, j;
1262b6ffaeffSJack Morgenstein 	int offset;
1263ffe455adSEugenia Emantayev 	__be32 agg_cap_mask;
1264ffe455adSEugenia Emantayev 	__be32 slave_cap_mask;
1265ffe455adSEugenia Emantayev 	__be32 new_cap_mask;
1266ffe455adSEugenia Emantayev 
1267ffe455adSEugenia Emantayev 	port = in_mod & 0xff;
1268ffe455adSEugenia Emantayev 	in_modifier = in_mod >> 8;
1269ffe455adSEugenia Emantayev 	is_eth = op_mod;
1270ffe455adSEugenia Emantayev 	port_info = &priv->port[port];
1271ffe455adSEugenia Emantayev 
1272ffe455adSEugenia Emantayev 	/* Slaves cannot perform SET_PORT operations except changing MTU */
1273ffe455adSEugenia Emantayev 	if (is_eth) {
1274ffe455adSEugenia Emantayev 		if (slave != dev->caps.function &&
12759cd59352SJack Morgenstein 		    in_modifier != MLX4_SET_PORT_GENERAL &&
12769cd59352SJack Morgenstein 		    in_modifier != MLX4_SET_PORT_GID_TABLE) {
1277ffe455adSEugenia Emantayev 			mlx4_warn(dev, "denying SET_PORT for slave:%d\n",
1278ffe455adSEugenia Emantayev 					slave);
1279ffe455adSEugenia Emantayev 			return -EINVAL;
1280ffe455adSEugenia Emantayev 		}
1281ffe455adSEugenia Emantayev 		switch (in_modifier) {
1282ffe455adSEugenia Emantayev 		case MLX4_SET_PORT_RQP_CALC:
1283ffe455adSEugenia Emantayev 			qpn_context = inbox->buf;
1284ffe455adSEugenia Emantayev 			qpn_context->base_qpn =
1285ffe455adSEugenia Emantayev 				cpu_to_be32(port_info->base_qpn);
1286ffe455adSEugenia Emantayev 			qpn_context->n_mac = 0x7;
1287ffe455adSEugenia Emantayev 			promisc = be32_to_cpu(qpn_context->promisc) >>
1288ffe455adSEugenia Emantayev 				SET_PORT_PROMISC_SHIFT;
1289ffe455adSEugenia Emantayev 			qpn_context->promisc = cpu_to_be32(
1290ffe455adSEugenia Emantayev 				promisc << SET_PORT_PROMISC_SHIFT |
1291ffe455adSEugenia Emantayev 				port_info->base_qpn);
1292ffe455adSEugenia Emantayev 			promisc = be32_to_cpu(qpn_context->mcast) >>
1293ffe455adSEugenia Emantayev 				SET_PORT_MC_PROMISC_SHIFT;
1294ffe455adSEugenia Emantayev 			qpn_context->mcast = cpu_to_be32(
1295ffe455adSEugenia Emantayev 				promisc << SET_PORT_MC_PROMISC_SHIFT |
1296ffe455adSEugenia Emantayev 				port_info->base_qpn);
1297ffe455adSEugenia Emantayev 			break;
1298ffe455adSEugenia Emantayev 		case MLX4_SET_PORT_GENERAL:
1299ffe455adSEugenia Emantayev 			gen_context = inbox->buf;
1300ffe455adSEugenia Emantayev 			/* Mtu is configured as the max MTU among all the
1301ffe455adSEugenia Emantayev 			 * the functions on the port. */
1302ffe455adSEugenia Emantayev 			mtu = be16_to_cpu(gen_context->mtu);
1303c59fec20SEugenia Emantayev 			mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] +
1304c59fec20SEugenia Emantayev 				    ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
1305ffe455adSEugenia Emantayev 			prev_mtu = slave_st->mtu[port];
1306ffe455adSEugenia Emantayev 			slave_st->mtu[port] = mtu;
1307ffe455adSEugenia Emantayev 			if (mtu > master->max_mtu[port])
1308ffe455adSEugenia Emantayev 				master->max_mtu[port] = mtu;
1309ffe455adSEugenia Emantayev 			if (mtu < prev_mtu && prev_mtu ==
1310ffe455adSEugenia Emantayev 						master->max_mtu[port]) {
1311ffe455adSEugenia Emantayev 				slave_st->mtu[port] = mtu;
1312ffe455adSEugenia Emantayev 				master->max_mtu[port] = mtu;
1313ffe455adSEugenia Emantayev 				for (i = 0; i < dev->num_slaves; i++) {
1314ffe455adSEugenia Emantayev 					master->max_mtu[port] =
1315ffe455adSEugenia Emantayev 					max(master->max_mtu[port],
1316ffe455adSEugenia Emantayev 					    master->slave_state[i].mtu[port]);
1317ffe455adSEugenia Emantayev 				}
1318ffe455adSEugenia Emantayev 			}
1319ffe455adSEugenia Emantayev 
1320ffe455adSEugenia Emantayev 			gen_context->mtu = cpu_to_be16(master->max_mtu[port]);
13212a500090SEugenia Emantayev 			/* Slave cannot change Global Pause configuration */
13222a500090SEugenia Emantayev 			if (slave != mlx4_master_func_num(dev) &&
13232a500090SEugenia Emantayev 			    ((gen_context->pptx != master->pptx) ||
13242a500090SEugenia Emantayev 			     (gen_context->pprx != master->pprx))) {
13252a500090SEugenia Emantayev 				gen_context->pptx = master->pptx;
13262a500090SEugenia Emantayev 				gen_context->pprx = master->pprx;
13272a500090SEugenia Emantayev 				mlx4_warn(dev,
13282a500090SEugenia Emantayev 					  "denying Global Pause change for slave:%d\n",
13292a500090SEugenia Emantayev 					  slave);
13302a500090SEugenia Emantayev 			} else {
13312a500090SEugenia Emantayev 				master->pptx = gen_context->pptx;
13322a500090SEugenia Emantayev 				master->pprx = gen_context->pprx;
13332a500090SEugenia Emantayev 			}
1334ffe455adSEugenia Emantayev 			break;
13359cd59352SJack Morgenstein 		case MLX4_SET_PORT_GID_TABLE:
1336b6ffaeffSJack Morgenstein 			/* change to MULTIPLE entries: number of guest's gids
1337b6ffaeffSJack Morgenstein 			 * need a FOR-loop here over number of gids the guest has.
1338b6ffaeffSJack Morgenstein 			 * 1. Check no duplicates in gids passed by slave
1339b6ffaeffSJack Morgenstein 			 */
1340449fc488SMatan Barak 			num_gids = mlx4_get_slave_num_gids(dev, slave, port);
1341449fc488SMatan Barak 			base = mlx4_get_base_gid_ix(dev, slave, port);
1342b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1343b6ffaeffSJack Morgenstein 			for (i = 0; i < num_gids; gid_entry_mbox++, i++) {
1344b6ffaeffSJack Morgenstein 				if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
1345b6ffaeffSJack Morgenstein 					    sizeof(zgid_entry)))
1346b6ffaeffSJack Morgenstein 					continue;
1347b6ffaeffSJack Morgenstein 				gid_entry_mb1 = gid_entry_mbox + 1;
1348b6ffaeffSJack Morgenstein 				for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) {
1349b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mb1->raw,
1350b6ffaeffSJack Morgenstein 						    zgid_entry.raw, sizeof(zgid_entry)))
1351b6ffaeffSJack Morgenstein 						continue;
1352b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw,
1353b6ffaeffSJack Morgenstein 						    sizeof(gid_entry_mbox->raw))) {
1354b6ffaeffSJack Morgenstein 						/* found duplicate */
1355b6ffaeffSJack Morgenstein 						return -EINVAL;
1356b6ffaeffSJack Morgenstein 					}
1357b6ffaeffSJack Morgenstein 				}
1358b6ffaeffSJack Morgenstein 			}
1359b6ffaeffSJack Morgenstein 
1360b6ffaeffSJack Morgenstein 			/* 2. Check that do not have duplicates in OTHER
1361b6ffaeffSJack Morgenstein 			 *    entries in the port GID table
1362b6ffaeffSJack Morgenstein 			 */
1363111c6094SJack Morgenstein 
1364111c6094SJack Morgenstein 			mutex_lock(&(priv->port[port].gid_table.mutex));
13659cd59352SJack Morgenstein 			for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
1366b6ffaeffSJack Morgenstein 				if (i >= base && i < base + num_gids)
1367b6ffaeffSJack Morgenstein 					continue; /* don't compare to slave's current gids */
1368111c6094SJack Morgenstein 				gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i];
1369b6ffaeffSJack Morgenstein 				if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry)))
1370b6ffaeffSJack Morgenstein 					continue;
1371b6ffaeffSJack Morgenstein 				gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1372b6ffaeffSJack Morgenstein 				for (j = 0; j < num_gids; gid_entry_mbox++, j++) {
1373b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
1374b6ffaeffSJack Morgenstein 						    sizeof(zgid_entry)))
1375b6ffaeffSJack Morgenstein 						continue;
1376b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw,
1377b6ffaeffSJack Morgenstein 						    sizeof(gid_entry_tbl->raw))) {
1378b6ffaeffSJack Morgenstein 						/* found duplicate */
13791a91de28SJoe Perches 						mlx4_warn(dev, "requested gid entry for slave:%d is a duplicate of gid at index %d\n",
13809cd59352SJack Morgenstein 							  slave, i);
1381111c6094SJack Morgenstein 						mutex_unlock(&(priv->port[port].gid_table.mutex));
1382b6ffaeffSJack Morgenstein 						return -EINVAL;
13839cd59352SJack Morgenstein 					}
13849cd59352SJack Morgenstein 				}
13859cd59352SJack Morgenstein 			}
1386b6ffaeffSJack Morgenstein 
1387b6ffaeffSJack Morgenstein 			/* insert slave GIDs with memcpy, starting at slave's base index */
1388b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1389b6ffaeffSJack Morgenstein 			for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++)
1390111c6094SJack Morgenstein 				memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
1391111c6094SJack Morgenstein 				       gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE);
1392b6ffaeffSJack Morgenstein 
1393b6ffaeffSJack Morgenstein 			/* Now, copy roce port gids table to current mailbox for passing to FW */
1394b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1395b6ffaeffSJack Morgenstein 			for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
1396111c6094SJack Morgenstein 				memcpy(gid_entry_mbox->raw,
1397111c6094SJack Morgenstein 				       priv->port[port].gid_table.roce_gids[i].raw,
1398111c6094SJack Morgenstein 				       MLX4_ROCE_GID_ENTRY_SIZE);
1399b6ffaeffSJack Morgenstein 
1400111c6094SJack Morgenstein 			err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
1401111c6094SJack Morgenstein 				       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1402111c6094SJack Morgenstein 				       MLX4_CMD_NATIVE);
1403111c6094SJack Morgenstein 			mutex_unlock(&(priv->port[port].gid_table.mutex));
1404111c6094SJack Morgenstein 			return err;
1405ffe455adSEugenia Emantayev 		}
1406111c6094SJack Morgenstein 
1407111c6094SJack Morgenstein 		return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
1408ffe455adSEugenia Emantayev 				MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1409ffe455adSEugenia Emantayev 				MLX4_CMD_NATIVE);
1410ffe455adSEugenia Emantayev 	}
1411ffe455adSEugenia Emantayev 
141251af33cfSIdo Shamay 	/* Slaves are not allowed to SET_PORT beacon (LED) blink */
141351af33cfSIdo Shamay 	if (op_mod == MLX4_SET_PORT_BEACON_OPCODE) {
141451af33cfSIdo Shamay 		mlx4_warn(dev, "denying SET_PORT Beacon slave:%d\n", slave);
141551af33cfSIdo Shamay 		return -EPERM;
141651af33cfSIdo Shamay 	}
141751af33cfSIdo Shamay 
1418ffe455adSEugenia Emantayev 	/* For IB, we only consider:
1419ffe455adSEugenia Emantayev 	 * - The capability mask, which is set to the aggregate of all
1420ffe455adSEugenia Emantayev 	 *   slave function capabilities
1421ffe455adSEugenia Emantayev 	 * - The QKey violatin counter - reset according to each request.
1422ffe455adSEugenia Emantayev 	 */
1423ffe455adSEugenia Emantayev 
1424ffe455adSEugenia Emantayev 	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
1425ffe455adSEugenia Emantayev 		reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40;
1426ffe455adSEugenia Emantayev 		new_cap_mask = ((__be32 *) inbox->buf)[2];
1427ffe455adSEugenia Emantayev 	} else {
1428ffe455adSEugenia Emantayev 		reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1;
1429ffe455adSEugenia Emantayev 		new_cap_mask = ((__be32 *) inbox->buf)[1];
1430ffe455adSEugenia Emantayev 	}
1431ffe455adSEugenia Emantayev 
1432efcd235dSJack Morgenstein 	/* slave may not set the IS_SM capability for the port */
1433efcd235dSJack Morgenstein 	if (slave != mlx4_master_func_num(dev) &&
1434efcd235dSJack Morgenstein 	    (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM))
1435efcd235dSJack Morgenstein 		return -EINVAL;
1436efcd235dSJack Morgenstein 
1437efcd235dSJack Morgenstein 	/* No DEV_MGMT in multifunc mode */
1438efcd235dSJack Morgenstein 	if (mlx4_is_mfunc(dev) &&
1439efcd235dSJack Morgenstein 	    (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP))
1440efcd235dSJack Morgenstein 		return -EINVAL;
1441efcd235dSJack Morgenstein 
1442ffe455adSEugenia Emantayev 	agg_cap_mask = 0;
1443ffe455adSEugenia Emantayev 	slave_cap_mask =
1444ffe455adSEugenia Emantayev 		priv->mfunc.master.slave_state[slave].ib_cap_mask[port];
1445ffe455adSEugenia Emantayev 	priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask;
1446ffe455adSEugenia Emantayev 	for (i = 0; i < dev->num_slaves; i++)
1447ffe455adSEugenia Emantayev 		agg_cap_mask |=
1448ffe455adSEugenia Emantayev 			priv->mfunc.master.slave_state[i].ib_cap_mask[port];
1449ffe455adSEugenia Emantayev 
1450ffe455adSEugenia Emantayev 	/* only clear mailbox for guests.  Master may be setting
1451ffe455adSEugenia Emantayev 	* MTU or PKEY table size
1452ffe455adSEugenia Emantayev 	*/
1453ffe455adSEugenia Emantayev 	if (slave != dev->caps.function)
1454ffe455adSEugenia Emantayev 		memset(inbox->buf, 0, 256);
1455ffe455adSEugenia Emantayev 	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
1456edc4a67eSJack Morgenstein 		*(u8 *) inbox->buf	   |= !!reset_qkey_viols << 6;
1457ffe455adSEugenia Emantayev 		((__be32 *) inbox->buf)[2] = agg_cap_mask;
1458ffe455adSEugenia Emantayev 	} else {
1459edc4a67eSJack Morgenstein 		((u8 *) inbox->buf)[3]     |= !!reset_qkey_viols;
1460ffe455adSEugenia Emantayev 		((__be32 *) inbox->buf)[1] = agg_cap_mask;
1461ffe455adSEugenia Emantayev 	}
1462ffe455adSEugenia Emantayev 
1463ffe455adSEugenia Emantayev 	err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT,
1464ffe455adSEugenia Emantayev 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
1465ffe455adSEugenia Emantayev 	if (err)
1466ffe455adSEugenia Emantayev 		priv->mfunc.master.slave_state[slave].ib_cap_mask[port] =
1467ffe455adSEugenia Emantayev 			slave_cap_mask;
1468ffe455adSEugenia Emantayev 	return err;
1469ffe455adSEugenia Emantayev }
1470ffe455adSEugenia Emantayev 
1471ffe455adSEugenia Emantayev int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave,
1472ffe455adSEugenia Emantayev 			  struct mlx4_vhcr *vhcr,
1473ffe455adSEugenia Emantayev 			  struct mlx4_cmd_mailbox *inbox,
1474ffe455adSEugenia Emantayev 			  struct mlx4_cmd_mailbox *outbox,
1475ffe455adSEugenia Emantayev 			  struct mlx4_cmd_info *cmd)
1476ffe455adSEugenia Emantayev {
1477449fc488SMatan Barak 	int port = mlx4_slave_convert_port(
1478449fc488SMatan Barak 			dev, slave, vhcr->in_modifier & 0xFF);
1479449fc488SMatan Barak 
1480449fc488SMatan Barak 	if (port < 0)
1481449fc488SMatan Barak 		return -EINVAL;
1482449fc488SMatan Barak 
1483449fc488SMatan Barak 	vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) |
1484449fc488SMatan Barak 			    (port & 0xFF);
1485449fc488SMatan Barak 
1486ffe455adSEugenia Emantayev 	return mlx4_common_set_port(dev, slave, vhcr->in_modifier,
1487ffe455adSEugenia Emantayev 				    vhcr->op_modifier, inbox);
1488ffe455adSEugenia Emantayev }
1489ffe455adSEugenia Emantayev 
1490096335b3SOr Gerlitz /* bit locations for set port command with zero op modifier */
1491096335b3SOr Gerlitz enum {
1492096335b3SOr Gerlitz 	MLX4_SET_PORT_VL_CAP	 = 4, /* bits 7:4 */
1493096335b3SOr Gerlitz 	MLX4_SET_PORT_MTU_CAP	 = 12, /* bits 15:12 */
14946634961cSJack Morgenstein 	MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20,
1495096335b3SOr Gerlitz 	MLX4_CHANGE_PORT_VL_CAP	 = 21,
1496096335b3SOr Gerlitz 	MLX4_CHANGE_PORT_MTU_CAP = 22,
1497096335b3SOr Gerlitz };
1498096335b3SOr Gerlitz 
14996634961cSJack Morgenstein int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz)
15005a2cc190SJeff Kirsher {
15015a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *mailbox;
15026634961cSJack Morgenstein 	int err, vl_cap, pkey_tbl_flag = 0;
15035a2cc190SJeff Kirsher 
15045a2cc190SJeff Kirsher 	if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
15055a2cc190SJeff Kirsher 		return 0;
15065a2cc190SJeff Kirsher 
15075a2cc190SJeff Kirsher 	mailbox = mlx4_alloc_cmd_mailbox(dev);
15085a2cc190SJeff Kirsher 	if (IS_ERR(mailbox))
15095a2cc190SJeff Kirsher 		return PTR_ERR(mailbox);
15105a2cc190SJeff Kirsher 
15115a2cc190SJeff Kirsher 	((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port];
1512096335b3SOr Gerlitz 
15136634961cSJack Morgenstein 	if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) {
15146634961cSJack Morgenstein 		pkey_tbl_flag = 1;
15156634961cSJack Morgenstein 		((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz);
15166634961cSJack Morgenstein 	}
15176634961cSJack Morgenstein 
1518096335b3SOr Gerlitz 	/* IB VL CAP enum isn't used by the firmware, just numerical values */
1519096335b3SOr Gerlitz 	for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) {
1520096335b3SOr Gerlitz 		((__be32 *) mailbox->buf)[0] = cpu_to_be32(
1521096335b3SOr Gerlitz 			(1 << MLX4_CHANGE_PORT_MTU_CAP) |
1522096335b3SOr Gerlitz 			(1 << MLX4_CHANGE_PORT_VL_CAP)  |
15236634961cSJack Morgenstein 			(pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) |
1524096335b3SOr Gerlitz 			(dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) |
1525096335b3SOr Gerlitz 			(vl_cap << MLX4_SET_PORT_VL_CAP));
1526a130b590SIdo Shamay 		err = mlx4_cmd(dev, mailbox->dma, port,
1527a130b590SIdo Shamay 			       MLX4_SET_PORT_IB_OPCODE, MLX4_CMD_SET_PORT,
1528f9baff50SJack Morgenstein 			       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
1529096335b3SOr Gerlitz 		if (err != -ENOMEM)
1530096335b3SOr Gerlitz 			break;
1531096335b3SOr Gerlitz 	}
15325a2cc190SJeff Kirsher 
15335a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, mailbox);
15345a2cc190SJeff Kirsher 	return err;
15355a2cc190SJeff Kirsher }
1536ffe455adSEugenia Emantayev 
15371da494cbSMoni Shoua #define SET_PORT_ROCE_2_FLAGS          0x10
15381da494cbSMoni Shoua #define MLX4_SET_PORT_ROCE_V1_V2       0x2
1539cb9ffb76SJoerg Roedel int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
1540ffe455adSEugenia Emantayev 			  u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx)
1541ffe455adSEugenia Emantayev {
1542ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
1543ffe455adSEugenia Emantayev 	struct mlx4_set_port_general_context *context;
1544ffe455adSEugenia Emantayev 	int err;
1545ffe455adSEugenia Emantayev 	u32 in_mod;
1546ffe455adSEugenia Emantayev 
1547ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
1548ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
1549ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
1550ffe455adSEugenia Emantayev 	context = mailbox->buf;
1551ffe455adSEugenia Emantayev 	context->flags = SET_PORT_GEN_ALL_VALID;
1552ffe455adSEugenia Emantayev 	context->mtu = cpu_to_be16(mtu);
1553ffe455adSEugenia Emantayev 	context->pptx = (pptx * (!pfctx)) << 7;
1554ffe455adSEugenia Emantayev 	context->pfctx = pfctx;
1555ffe455adSEugenia Emantayev 	context->pprx = (pprx * (!pfcrx)) << 7;
1556ffe455adSEugenia Emantayev 	context->pfcrx = pfcrx;
1557ffe455adSEugenia Emantayev 
15581da494cbSMoni Shoua 	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2) {
15591da494cbSMoni Shoua 		context->flags |= SET_PORT_ROCE_2_FLAGS;
15601da494cbSMoni Shoua 		context->roce_mode |=
15611da494cbSMoni Shoua 			MLX4_SET_PORT_ROCE_V1_V2 << 4;
15621da494cbSMoni Shoua 	}
1563ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
1564a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1565a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1566a130b590SIdo Shamay 		       MLX4_CMD_WRAPPED);
1567ffe455adSEugenia Emantayev 
1568ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
1569ffe455adSEugenia Emantayev 	return err;
1570ffe455adSEugenia Emantayev }
1571ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_general);
1572ffe455adSEugenia Emantayev 
1573cb9ffb76SJoerg Roedel int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
1574ffe455adSEugenia Emantayev 			   u8 promisc)
1575ffe455adSEugenia Emantayev {
1576ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
1577ffe455adSEugenia Emantayev 	struct mlx4_set_port_rqp_calc_context *context;
1578ffe455adSEugenia Emantayev 	int err;
1579ffe455adSEugenia Emantayev 	u32 in_mod;
1580ffe455adSEugenia Emantayev 	u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ?
1581ffe455adSEugenia Emantayev 		MCAST_DIRECT : MCAST_DEFAULT;
1582ffe455adSEugenia Emantayev 
1583c96d97f4SHadar Hen Zion 	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
1584ffe455adSEugenia Emantayev 		return 0;
1585ffe455adSEugenia Emantayev 
1586ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
1587ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
1588ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
1589ffe455adSEugenia Emantayev 	context = mailbox->buf;
1590ffe455adSEugenia Emantayev 	context->base_qpn = cpu_to_be32(base_qpn);
1591ffe455adSEugenia Emantayev 	context->n_mac = dev->caps.log_num_macs;
1592ffe455adSEugenia Emantayev 	context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT |
1593ffe455adSEugenia Emantayev 				       base_qpn);
1594ffe455adSEugenia Emantayev 	context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT |
1595ffe455adSEugenia Emantayev 				     base_qpn);
1596ffe455adSEugenia Emantayev 	context->intra_no_vlan = 0;
1597ffe455adSEugenia Emantayev 	context->no_vlan = MLX4_NO_VLAN_IDX;
1598ffe455adSEugenia Emantayev 	context->intra_vlan_miss = 0;
1599ffe455adSEugenia Emantayev 	context->vlan_miss = MLX4_VLAN_MISS_IDX;
1600ffe455adSEugenia Emantayev 
1601ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port;
1602a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1603a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1604a130b590SIdo Shamay 		       MLX4_CMD_WRAPPED);
1605ffe455adSEugenia Emantayev 
1606ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
1607ffe455adSEugenia Emantayev 	return err;
1608ffe455adSEugenia Emantayev }
1609ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc);
1610ffe455adSEugenia Emantayev 
161178500b8cSMuhammad Mahajna int mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, u8 ignore_fcs_value)
161278500b8cSMuhammad Mahajna {
161378500b8cSMuhammad Mahajna 	struct mlx4_cmd_mailbox *mailbox;
161478500b8cSMuhammad Mahajna 	struct mlx4_set_port_general_context *context;
161578500b8cSMuhammad Mahajna 	u32 in_mod;
161678500b8cSMuhammad Mahajna 	int err;
161778500b8cSMuhammad Mahajna 
161878500b8cSMuhammad Mahajna 	mailbox = mlx4_alloc_cmd_mailbox(dev);
161978500b8cSMuhammad Mahajna 	if (IS_ERR(mailbox))
162078500b8cSMuhammad Mahajna 		return PTR_ERR(mailbox);
162178500b8cSMuhammad Mahajna 	context = mailbox->buf;
162278500b8cSMuhammad Mahajna 	context->v_ignore_fcs |= MLX4_FLAG_V_IGNORE_FCS_MASK;
162378500b8cSMuhammad Mahajna 	if (ignore_fcs_value)
162478500b8cSMuhammad Mahajna 		context->ignore_fcs |= MLX4_IGNORE_FCS_MASK;
162578500b8cSMuhammad Mahajna 	else
162678500b8cSMuhammad Mahajna 		context->ignore_fcs &= ~MLX4_IGNORE_FCS_MASK;
162778500b8cSMuhammad Mahajna 
162878500b8cSMuhammad Mahajna 	in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
162978500b8cSMuhammad Mahajna 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
163078500b8cSMuhammad Mahajna 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
163178500b8cSMuhammad Mahajna 
163278500b8cSMuhammad Mahajna 	mlx4_free_cmd_mailbox(dev, mailbox);
163378500b8cSMuhammad Mahajna 	return err;
163478500b8cSMuhammad Mahajna }
163578500b8cSMuhammad Mahajna EXPORT_SYMBOL(mlx4_SET_PORT_fcs_check);
163678500b8cSMuhammad Mahajna 
16377ffdf726SOr Gerlitz enum {
16387ffdf726SOr Gerlitz 	VXLAN_ENABLE_MODIFY	= 1 << 7,
16397ffdf726SOr Gerlitz 	VXLAN_STEERING_MODIFY	= 1 << 6,
16407ffdf726SOr Gerlitz 
16417ffdf726SOr Gerlitz 	VXLAN_ENABLE		= 1 << 7,
16427ffdf726SOr Gerlitz };
16437ffdf726SOr Gerlitz 
16447ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context {
16457ffdf726SOr Gerlitz 	u32	reserved1;
16467ffdf726SOr Gerlitz 	u8	modify_flags;
16477ffdf726SOr Gerlitz 	u8	reserved2;
16487ffdf726SOr Gerlitz 	u8	enable_flags;
16497ffdf726SOr Gerlitz 	u8	steering;
16507ffdf726SOr Gerlitz };
16517ffdf726SOr Gerlitz 
16521b136de1SOr Gerlitz int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable)
16537ffdf726SOr Gerlitz {
16547ffdf726SOr Gerlitz 	int err;
16557ffdf726SOr Gerlitz 	u32 in_mod;
16567ffdf726SOr Gerlitz 	struct mlx4_cmd_mailbox *mailbox;
16577ffdf726SOr Gerlitz 	struct mlx4_set_port_vxlan_context  *context;
16587ffdf726SOr Gerlitz 
16597ffdf726SOr Gerlitz 	mailbox = mlx4_alloc_cmd_mailbox(dev);
16607ffdf726SOr Gerlitz 	if (IS_ERR(mailbox))
16617ffdf726SOr Gerlitz 		return PTR_ERR(mailbox);
16627ffdf726SOr Gerlitz 	context = mailbox->buf;
16637ffdf726SOr Gerlitz 	memset(context, 0, sizeof(*context));
16647ffdf726SOr Gerlitz 
16657ffdf726SOr Gerlitz 	context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY;
16661b136de1SOr Gerlitz 	if (enable)
16677ffdf726SOr Gerlitz 		context->enable_flags = VXLAN_ENABLE;
16687ffdf726SOr Gerlitz 	context->steering  = steering;
16697ffdf726SOr Gerlitz 
16707ffdf726SOr Gerlitz 	in_mod = MLX4_SET_PORT_VXLAN << 8 | port;
1671a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1672a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1673a130b590SIdo Shamay 		       MLX4_CMD_NATIVE);
16747ffdf726SOr Gerlitz 
16757ffdf726SOr Gerlitz 	mlx4_free_cmd_mailbox(dev, mailbox);
16767ffdf726SOr Gerlitz 	return err;
16777ffdf726SOr Gerlitz }
16787ffdf726SOr Gerlitz EXPORT_SYMBOL(mlx4_SET_PORT_VXLAN);
16797ffdf726SOr Gerlitz 
168051af33cfSIdo Shamay int mlx4_SET_PORT_BEACON(struct mlx4_dev *dev, u8 port, u16 time)
168151af33cfSIdo Shamay {
168251af33cfSIdo Shamay 	int err;
168351af33cfSIdo Shamay 	struct mlx4_cmd_mailbox *mailbox;
168451af33cfSIdo Shamay 
168551af33cfSIdo Shamay 	mailbox = mlx4_alloc_cmd_mailbox(dev);
168651af33cfSIdo Shamay 	if (IS_ERR(mailbox))
168751af33cfSIdo Shamay 		return PTR_ERR(mailbox);
168851af33cfSIdo Shamay 
168951af33cfSIdo Shamay 	*((__be32 *)mailbox->buf) = cpu_to_be32(time);
169051af33cfSIdo Shamay 
169151af33cfSIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, port, MLX4_SET_PORT_BEACON_OPCODE,
169251af33cfSIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
169351af33cfSIdo Shamay 		       MLX4_CMD_NATIVE);
169451af33cfSIdo Shamay 
169551af33cfSIdo Shamay 	mlx4_free_cmd_mailbox(dev, mailbox);
169651af33cfSIdo Shamay 	return err;
169751af33cfSIdo Shamay }
169851af33cfSIdo Shamay EXPORT_SYMBOL(mlx4_SET_PORT_BEACON);
169951af33cfSIdo Shamay 
1700ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1701ffe455adSEugenia Emantayev 				struct mlx4_vhcr *vhcr,
1702ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *inbox,
1703ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *outbox,
1704ffe455adSEugenia Emantayev 				struct mlx4_cmd_info *cmd)
1705ffe455adSEugenia Emantayev {
1706ffe455adSEugenia Emantayev 	int err = 0;
1707ffe455adSEugenia Emantayev 
1708ffe455adSEugenia Emantayev 	return err;
1709ffe455adSEugenia Emantayev }
1710ffe455adSEugenia Emantayev 
1711ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port,
1712ffe455adSEugenia Emantayev 			u64 mac, u64 clear, u8 mode)
1713ffe455adSEugenia Emantayev {
1714ffe455adSEugenia Emantayev 	return mlx4_cmd(dev, (mac | (clear << 63)), port, mode,
1715ffe455adSEugenia Emantayev 			MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B,
1716ffe455adSEugenia Emantayev 			MLX4_CMD_WRAPPED);
1717ffe455adSEugenia Emantayev }
1718ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR);
1719ffe455adSEugenia Emantayev 
1720ffe455adSEugenia Emantayev int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1721ffe455adSEugenia Emantayev 			       struct mlx4_vhcr *vhcr,
1722ffe455adSEugenia Emantayev 			       struct mlx4_cmd_mailbox *inbox,
1723ffe455adSEugenia Emantayev 			       struct mlx4_cmd_mailbox *outbox,
1724ffe455adSEugenia Emantayev 			       struct mlx4_cmd_info *cmd)
1725ffe455adSEugenia Emantayev {
1726ffe455adSEugenia Emantayev 	int err = 0;
1727ffe455adSEugenia Emantayev 
1728ffe455adSEugenia Emantayev 	return err;
1729ffe455adSEugenia Emantayev }
1730ffe455adSEugenia Emantayev 
1731ffe455adSEugenia Emantayev int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave,
1732ffe455adSEugenia Emantayev 			       u32 in_mod, struct mlx4_cmd_mailbox *outbox)
1733ffe455adSEugenia Emantayev {
1734ffe455adSEugenia Emantayev 	return mlx4_cmd_box(dev, 0, outbox->dma, in_mod, 0,
1735ffe455adSEugenia Emantayev 			    MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B,
1736ffe455adSEugenia Emantayev 			    MLX4_CMD_NATIVE);
1737ffe455adSEugenia Emantayev }
1738ffe455adSEugenia Emantayev 
1739ffe455adSEugenia Emantayev int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave,
1740ffe455adSEugenia Emantayev 				struct mlx4_vhcr *vhcr,
1741ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *inbox,
1742ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *outbox,
1743ffe455adSEugenia Emantayev 				struct mlx4_cmd_info *cmd)
1744ffe455adSEugenia Emantayev {
174535fb9afbSEugenia Emantayev 	if (slave != dev->caps.function)
174635fb9afbSEugenia Emantayev 		return 0;
1747ffe455adSEugenia Emantayev 	return mlx4_common_dump_eth_stats(dev, slave,
1748ffe455adSEugenia Emantayev 					  vhcr->in_modifier, outbox);
1749ffe455adSEugenia Emantayev }
175093ece0c1SEugenia Emantayev 
17519cd59352SJack Morgenstein int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
17529cd59352SJack Morgenstein 				 int *slave_id)
17536ee51a4eSJack Morgenstein {
17546ee51a4eSJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
17556ee51a4eSJack Morgenstein 	int i, found_ix = -1;
1756b6ffaeffSJack Morgenstein 	int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
1757449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
1758449fc488SMatan Barak 	unsigned num_vfs;
1759449fc488SMatan Barak 	int slave_gid;
17606ee51a4eSJack Morgenstein 
17616ee51a4eSJack Morgenstein 	if (!mlx4_is_mfunc(dev))
17626ee51a4eSJack Morgenstein 		return -EINVAL;
17636ee51a4eSJack Morgenstein 
1764449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1765872bf2fbSYishai Hadas 	num_vfs = bitmap_weight(slaves_pport.slaves,
1766872bf2fbSYishai Hadas 				dev->persist->num_vfs + 1) - 1;
1767449fc488SMatan Barak 
17686ee51a4eSJack Morgenstein 	for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
1769111c6094SJack Morgenstein 		if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid,
1770111c6094SJack Morgenstein 			    MLX4_ROCE_GID_ENTRY_SIZE)) {
17716ee51a4eSJack Morgenstein 			found_ix = i;
17726ee51a4eSJack Morgenstein 			break;
17736ee51a4eSJack Morgenstein 		}
17746ee51a4eSJack Morgenstein 	}
17756ee51a4eSJack Morgenstein 
1776b6ffaeffSJack Morgenstein 	if (found_ix >= 0) {
17770254bc82SMatan Barak 		/* Calculate a slave_gid which is the slave number in the gid
17780254bc82SMatan Barak 		 * table and not a globally unique slave number.
17790254bc82SMatan Barak 		 */
1780b6ffaeffSJack Morgenstein 		if (found_ix < MLX4_ROCE_PF_GIDS)
1781449fc488SMatan Barak 			slave_gid = 0;
1782449fc488SMatan Barak 		else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) *
1783449fc488SMatan Barak 			 (vf_gids / num_vfs + 1))
1784449fc488SMatan Barak 			slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) /
1785449fc488SMatan Barak 				     (vf_gids / num_vfs + 1)) + 1;
1786b6ffaeffSJack Morgenstein 		else
1787449fc488SMatan Barak 			slave_gid =
1788b6ffaeffSJack Morgenstein 			((found_ix - MLX4_ROCE_PF_GIDS -
1789449fc488SMatan Barak 			  ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) /
1790449fc488SMatan Barak 			 (vf_gids / num_vfs)) + vf_gids % num_vfs + 1;
1791449fc488SMatan Barak 
17920254bc82SMatan Barak 		/* Calculate the globally unique slave id */
1793449fc488SMatan Barak 		if (slave_gid) {
1794449fc488SMatan Barak 			struct mlx4_active_ports exclusive_ports;
1795449fc488SMatan Barak 			struct mlx4_active_ports actv_ports;
1796449fc488SMatan Barak 			struct mlx4_slaves_pport slaves_pport_actv;
1797449fc488SMatan Barak 			unsigned max_port_p_one;
17980254bc82SMatan Barak 			int num_vfs_before = 0;
17990254bc82SMatan Barak 			int candidate_slave_gid;
1800449fc488SMatan Barak 
18010254bc82SMatan Barak 			/* Calculate how many VFs are on the previous port, if exists */
1802449fc488SMatan Barak 			for (i = 1; i < port; i++) {
1803449fc488SMatan Barak 				bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
18040254bc82SMatan Barak 				set_bit(i - 1, exclusive_ports.ports);
1805449fc488SMatan Barak 				slaves_pport_actv =
1806449fc488SMatan Barak 					mlx4_phys_to_slaves_pport_actv(
1807449fc488SMatan Barak 							dev, &exclusive_ports);
18080254bc82SMatan Barak 				num_vfs_before += bitmap_weight(
1809449fc488SMatan Barak 						slaves_pport_actv.slaves,
1810872bf2fbSYishai Hadas 						dev->persist->num_vfs + 1);
1811449fc488SMatan Barak 			}
1812449fc488SMatan Barak 
18130254bc82SMatan Barak 			/* candidate_slave_gid isn't necessarily the correct slave, but
18140254bc82SMatan Barak 			 * it has the same number of ports and is assigned to the same
18150254bc82SMatan Barak 			 * ports as the real slave we're looking for. On dual port VF,
18160254bc82SMatan Barak 			 * slave_gid = [single port VFs on port <port>] +
18170254bc82SMatan Barak 			 * [offset of the current slave from the first dual port VF] +
18180254bc82SMatan Barak 			 * 1 (for the PF).
18190254bc82SMatan Barak 			 */
18200254bc82SMatan Barak 			candidate_slave_gid = slave_gid + num_vfs_before;
18210254bc82SMatan Barak 
18220254bc82SMatan Barak 			actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid);
1823449fc488SMatan Barak 			max_port_p_one = find_first_bit(
1824449fc488SMatan Barak 				actv_ports.ports, dev->caps.num_ports) +
1825449fc488SMatan Barak 				bitmap_weight(actv_ports.ports,
1826449fc488SMatan Barak 					      dev->caps.num_ports) + 1;
1827449fc488SMatan Barak 
18280254bc82SMatan Barak 			/* Calculate the real slave number */
1829449fc488SMatan Barak 			for (i = 1; i < max_port_p_one; i++) {
1830449fc488SMatan Barak 				if (i == port)
1831449fc488SMatan Barak 					continue;
1832449fc488SMatan Barak 				bitmap_zero(exclusive_ports.ports,
1833449fc488SMatan Barak 					    dev->caps.num_ports);
1834449fc488SMatan Barak 				set_bit(i - 1, exclusive_ports.ports);
1835449fc488SMatan Barak 				slaves_pport_actv =
1836449fc488SMatan Barak 					mlx4_phys_to_slaves_pport_actv(
1837449fc488SMatan Barak 						dev, &exclusive_ports);
1838449fc488SMatan Barak 				slave_gid += bitmap_weight(
1839449fc488SMatan Barak 						slaves_pport_actv.slaves,
1840872bf2fbSYishai Hadas 						dev->persist->num_vfs + 1);
1841449fc488SMatan Barak 			}
1842449fc488SMatan Barak 		}
1843449fc488SMatan Barak 		*slave_id = slave_gid;
1844b6ffaeffSJack Morgenstein 	}
18456ee51a4eSJack Morgenstein 
18466ee51a4eSJack Morgenstein 	return (found_ix >= 0) ? 0 : -EINVAL;
18476ee51a4eSJack Morgenstein }
18486ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid);
18496ee51a4eSJack Morgenstein 
18509cd59352SJack Morgenstein int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id,
18519cd59352SJack Morgenstein 				 u8 *gid)
18526ee51a4eSJack Morgenstein {
18536ee51a4eSJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
18546ee51a4eSJack Morgenstein 
18556ee51a4eSJack Morgenstein 	if (!mlx4_is_master(dev))
18566ee51a4eSJack Morgenstein 		return -EINVAL;
18576ee51a4eSJack Morgenstein 
1858111c6094SJack Morgenstein 	memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw,
1859111c6094SJack Morgenstein 	       MLX4_ROCE_GID_ENTRY_SIZE);
18606ee51a4eSJack Morgenstein 	return 0;
18616ee51a4eSJack Morgenstein }
18626ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
186332a173c7SSaeed Mahameed 
186432a173c7SSaeed Mahameed /* Cable Module Info */
186532a173c7SSaeed Mahameed #define MODULE_INFO_MAX_READ 48
186632a173c7SSaeed Mahameed 
186732a173c7SSaeed Mahameed #define I2C_ADDR_LOW  0x50
186832a173c7SSaeed Mahameed #define I2C_ADDR_HIGH 0x51
186932a173c7SSaeed Mahameed #define I2C_PAGE_SIZE 256
187032a173c7SSaeed Mahameed 
187132a173c7SSaeed Mahameed /* Module Info Data */
187232a173c7SSaeed Mahameed struct mlx4_cable_info {
187332a173c7SSaeed Mahameed 	u8	i2c_addr;
187432a173c7SSaeed Mahameed 	u8	page_num;
187532a173c7SSaeed Mahameed 	__be16	dev_mem_address;
187632a173c7SSaeed Mahameed 	__be16	reserved1;
187732a173c7SSaeed Mahameed 	__be16	size;
187832a173c7SSaeed Mahameed 	__be32	reserved2[2];
187932a173c7SSaeed Mahameed 	u8	data[MODULE_INFO_MAX_READ];
188032a173c7SSaeed Mahameed };
188132a173c7SSaeed Mahameed 
188232a173c7SSaeed Mahameed enum cable_info_err {
188332a173c7SSaeed Mahameed 	 CABLE_INF_INV_PORT      = 0x1,
188432a173c7SSaeed Mahameed 	 CABLE_INF_OP_NOSUP      = 0x2,
188532a173c7SSaeed Mahameed 	 CABLE_INF_NOT_CONN      = 0x3,
188632a173c7SSaeed Mahameed 	 CABLE_INF_NO_EEPRM      = 0x4,
188732a173c7SSaeed Mahameed 	 CABLE_INF_PAGE_ERR      = 0x5,
188832a173c7SSaeed Mahameed 	 CABLE_INF_INV_ADDR      = 0x6,
188932a173c7SSaeed Mahameed 	 CABLE_INF_I2C_ADDR      = 0x7,
189032a173c7SSaeed Mahameed 	 CABLE_INF_QSFP_VIO      = 0x8,
189132a173c7SSaeed Mahameed 	 CABLE_INF_I2C_BUSY      = 0x9,
189232a173c7SSaeed Mahameed };
189332a173c7SSaeed Mahameed 
189432a173c7SSaeed Mahameed #define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF)
189532a173c7SSaeed Mahameed 
189632a173c7SSaeed Mahameed static inline const char *cable_info_mad_err_str(u16 mad_status)
189732a173c7SSaeed Mahameed {
189832a173c7SSaeed Mahameed 	u8 err = MAD_STATUS_2_CABLE_ERR(mad_status);
189932a173c7SSaeed Mahameed 
190032a173c7SSaeed Mahameed 	switch (err) {
190132a173c7SSaeed Mahameed 	case CABLE_INF_INV_PORT:
190232a173c7SSaeed Mahameed 		return "invalid port selected";
190332a173c7SSaeed Mahameed 	case CABLE_INF_OP_NOSUP:
190432a173c7SSaeed Mahameed 		return "operation not supported for this port (the port is of type CX4 or internal)";
190532a173c7SSaeed Mahameed 	case CABLE_INF_NOT_CONN:
190632a173c7SSaeed Mahameed 		return "cable is not connected";
190732a173c7SSaeed Mahameed 	case CABLE_INF_NO_EEPRM:
190832a173c7SSaeed Mahameed 		return "the connected cable has no EPROM (passive copper cable)";
190932a173c7SSaeed Mahameed 	case CABLE_INF_PAGE_ERR:
191032a173c7SSaeed Mahameed 		return "page number is greater than 15";
191132a173c7SSaeed Mahameed 	case CABLE_INF_INV_ADDR:
191232a173c7SSaeed Mahameed 		return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)";
191332a173c7SSaeed Mahameed 	case CABLE_INF_I2C_ADDR:
191432a173c7SSaeed Mahameed 		return "invalid I2C slave address";
191532a173c7SSaeed Mahameed 	case CABLE_INF_QSFP_VIO:
191632a173c7SSaeed Mahameed 		return "at least one cable violates the QSFP specification and ignores the modsel signal";
191732a173c7SSaeed Mahameed 	case CABLE_INF_I2C_BUSY:
191832a173c7SSaeed Mahameed 		return "I2C bus is constantly busy";
191932a173c7SSaeed Mahameed 	}
192032a173c7SSaeed Mahameed 	return "Unknown Error";
192132a173c7SSaeed Mahameed }
192232a173c7SSaeed Mahameed 
192332a173c7SSaeed Mahameed /**
192432a173c7SSaeed Mahameed  * mlx4_get_module_info - Read cable module eeprom data
192532a173c7SSaeed Mahameed  * @dev: mlx4_dev.
192632a173c7SSaeed Mahameed  * @port: port number.
192732a173c7SSaeed Mahameed  * @offset: byte offset in eeprom to start reading data from.
192832a173c7SSaeed Mahameed  * @size: num of bytes to read.
192932a173c7SSaeed Mahameed  * @data: output buffer to put the requested data into.
193032a173c7SSaeed Mahameed  *
193132a173c7SSaeed Mahameed  * Reads cable module eeprom data, puts the outcome data into
193232a173c7SSaeed Mahameed  * data pointer paramer.
193332a173c7SSaeed Mahameed  * Returns num of read bytes on success or a negative error
193432a173c7SSaeed Mahameed  * code.
193532a173c7SSaeed Mahameed  */
193632a173c7SSaeed Mahameed int mlx4_get_module_info(struct mlx4_dev *dev, u8 port,
193732a173c7SSaeed Mahameed 			 u16 offset, u16 size, u8 *data)
193832a173c7SSaeed Mahameed {
193932a173c7SSaeed Mahameed 	struct mlx4_cmd_mailbox *inbox, *outbox;
194032a173c7SSaeed Mahameed 	struct mlx4_mad_ifc *inmad, *outmad;
194132a173c7SSaeed Mahameed 	struct mlx4_cable_info *cable_info;
194232a173c7SSaeed Mahameed 	u16 i2c_addr;
194332a173c7SSaeed Mahameed 	int ret;
194432a173c7SSaeed Mahameed 
194532a173c7SSaeed Mahameed 	if (size > MODULE_INFO_MAX_READ)
194632a173c7SSaeed Mahameed 		size = MODULE_INFO_MAX_READ;
194732a173c7SSaeed Mahameed 
194832a173c7SSaeed Mahameed 	inbox = mlx4_alloc_cmd_mailbox(dev);
194932a173c7SSaeed Mahameed 	if (IS_ERR(inbox))
195032a173c7SSaeed Mahameed 		return PTR_ERR(inbox);
195132a173c7SSaeed Mahameed 
195232a173c7SSaeed Mahameed 	outbox = mlx4_alloc_cmd_mailbox(dev);
195332a173c7SSaeed Mahameed 	if (IS_ERR(outbox)) {
195432a173c7SSaeed Mahameed 		mlx4_free_cmd_mailbox(dev, inbox);
195532a173c7SSaeed Mahameed 		return PTR_ERR(outbox);
195632a173c7SSaeed Mahameed 	}
195732a173c7SSaeed Mahameed 
195832a173c7SSaeed Mahameed 	inmad = (struct mlx4_mad_ifc *)(inbox->buf);
195932a173c7SSaeed Mahameed 	outmad = (struct mlx4_mad_ifc *)(outbox->buf);
196032a173c7SSaeed Mahameed 
196132a173c7SSaeed Mahameed 	inmad->method = 0x1; /* Get */
196232a173c7SSaeed Mahameed 	inmad->class_version = 0x1;
196332a173c7SSaeed Mahameed 	inmad->mgmt_class = 0x1;
196432a173c7SSaeed Mahameed 	inmad->base_version = 0x1;
196532a173c7SSaeed Mahameed 	inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */
196632a173c7SSaeed Mahameed 
196732a173c7SSaeed Mahameed 	if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE)
196832a173c7SSaeed Mahameed 		/* Cross pages reads are not allowed
196932a173c7SSaeed Mahameed 		 * read until offset 256 in low page
197032a173c7SSaeed Mahameed 		 */
197132a173c7SSaeed Mahameed 		size -= offset + size - I2C_PAGE_SIZE;
197232a173c7SSaeed Mahameed 
197332a173c7SSaeed Mahameed 	i2c_addr = I2C_ADDR_LOW;
197432a173c7SSaeed Mahameed 	if (offset >= I2C_PAGE_SIZE) {
197532a173c7SSaeed Mahameed 		/* Reset offset to high page */
197632a173c7SSaeed Mahameed 		i2c_addr = I2C_ADDR_HIGH;
197732a173c7SSaeed Mahameed 		offset -= I2C_PAGE_SIZE;
197832a173c7SSaeed Mahameed 	}
197932a173c7SSaeed Mahameed 
198032a173c7SSaeed Mahameed 	cable_info = (struct mlx4_cable_info *)inmad->data;
198132a173c7SSaeed Mahameed 	cable_info->dev_mem_address = cpu_to_be16(offset);
198232a173c7SSaeed Mahameed 	cable_info->page_num = 0;
198332a173c7SSaeed Mahameed 	cable_info->i2c_addr = i2c_addr;
198432a173c7SSaeed Mahameed 	cable_info->size = cpu_to_be16(size);
198532a173c7SSaeed Mahameed 
198632a173c7SSaeed Mahameed 	ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
198732a173c7SSaeed Mahameed 			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
198832a173c7SSaeed Mahameed 			   MLX4_CMD_NATIVE);
198932a173c7SSaeed Mahameed 	if (ret)
199032a173c7SSaeed Mahameed 		goto out;
199132a173c7SSaeed Mahameed 
199232a173c7SSaeed Mahameed 	if (be16_to_cpu(outmad->status)) {
199332a173c7SSaeed Mahameed 		/* Mad returned with bad status */
199432a173c7SSaeed Mahameed 		ret = be16_to_cpu(outmad->status);
199532a173c7SSaeed Mahameed 		mlx4_warn(dev,
199632a173c7SSaeed 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",
199732a173c7SSaeed Mahameed 			  0xFF60, port, i2c_addr, offset, size,
199832a173c7SSaeed Mahameed 			  ret, cable_info_mad_err_str(ret));
199932a173c7SSaeed Mahameed 
200032a173c7SSaeed Mahameed 		if (i2c_addr == I2C_ADDR_HIGH &&
200132a173c7SSaeed Mahameed 		    MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR)
200232a173c7SSaeed Mahameed 			/* Some SFP cables do not support i2c slave
200332a173c7SSaeed Mahameed 			 * address 0x51 (high page), abort silently.
200432a173c7SSaeed Mahameed 			 */
200532a173c7SSaeed Mahameed 			ret = 0;
200632a173c7SSaeed Mahameed 		else
200732a173c7SSaeed Mahameed 			ret = -ret;
200832a173c7SSaeed Mahameed 		goto out;
200932a173c7SSaeed Mahameed 	}
201032a173c7SSaeed Mahameed 	cable_info = (struct mlx4_cable_info *)outmad->data;
201132a173c7SSaeed Mahameed 	memcpy(data, cable_info->data, size);
201232a173c7SSaeed Mahameed 	ret = size;
201332a173c7SSaeed Mahameed out:
201432a173c7SSaeed Mahameed 	mlx4_free_cmd_mailbox(dev, inbox);
201532a173c7SSaeed Mahameed 	mlx4_free_cmd_mailbox(dev, outbox);
201632a173c7SSaeed Mahameed 	return ret;
201732a173c7SSaeed Mahameed }
201832a173c7SSaeed Mahameed EXPORT_SYMBOL(mlx4_get_module_info);
2019af7d5185SRana Shahout 
2020af7d5185SRana Shahout int mlx4_max_tc(struct mlx4_dev *dev)
2021af7d5185SRana Shahout {
2022af7d5185SRana Shahout 	u8 num_tc = dev->caps.max_tc_eth;
2023af7d5185SRana Shahout 
2024af7d5185SRana Shahout 	if (!num_tc)
2025af7d5185SRana Shahout 		num_tc = MLNX4_TX_MAX_NUMBER;
2026af7d5185SRana Shahout 
2027af7d5185SRana Shahout 	return num_tc;
2028af7d5185SRana Shahout }
2029af7d5185SRana Shahout EXPORT_SYMBOL(mlx4_max_tc);
2030