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