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"
415a2cc190SJeff Kirsher 
425a2cc190SJeff Kirsher #define MLX4_MAC_VALID		(1ull << 63)
435a2cc190SJeff Kirsher 
445a2cc190SJeff Kirsher #define MLX4_VLAN_VALID		(1u << 31)
455a2cc190SJeff Kirsher #define MLX4_VLAN_MASK		0xfff
465a2cc190SJeff Kirsher 
4793ece0c1SEugenia Emantayev #define MLX4_STATS_TRAFFIC_COUNTERS_MASK	0xfULL
4893ece0c1SEugenia Emantayev #define MLX4_STATS_TRAFFIC_DROPS_MASK		0xc0ULL
4993ece0c1SEugenia Emantayev #define MLX4_STATS_ERROR_COUNTERS_MASK		0x1ffc30ULL
5093ece0c1SEugenia Emantayev #define MLX4_STATS_PORT_COUNTERS_MASK		0x1fe00000ULL
5193ece0c1SEugenia Emantayev 
525a2cc190SJeff Kirsher void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table)
535a2cc190SJeff Kirsher {
545a2cc190SJeff Kirsher 	int i;
555a2cc190SJeff Kirsher 
565a2cc190SJeff Kirsher 	mutex_init(&table->mutex);
575a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
585a2cc190SJeff Kirsher 		table->entries[i] = 0;
595a2cc190SJeff Kirsher 		table->refs[i]	 = 0;
605a2cc190SJeff Kirsher 	}
615a2cc190SJeff Kirsher 	table->max   = 1 << dev->caps.log_num_macs;
625a2cc190SJeff Kirsher 	table->total = 0;
635a2cc190SJeff Kirsher }
645a2cc190SJeff Kirsher 
655a2cc190SJeff Kirsher void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
665a2cc190SJeff Kirsher {
675a2cc190SJeff Kirsher 	int i;
685a2cc190SJeff Kirsher 
695a2cc190SJeff Kirsher 	mutex_init(&table->mutex);
705a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
715a2cc190SJeff Kirsher 		table->entries[i] = 0;
725a2cc190SJeff Kirsher 		table->refs[i]	 = 0;
735a2cc190SJeff Kirsher 	}
74e72ebf5aSYevgeny Petrilin 	table->max   = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR;
755a2cc190SJeff Kirsher 	table->total = 0;
765a2cc190SJeff Kirsher }
775a2cc190SJeff Kirsher 
78111c6094SJack Morgenstein void mlx4_init_roce_gid_table(struct mlx4_dev *dev,
79111c6094SJack Morgenstein 			      struct mlx4_roce_gid_table *table)
80111c6094SJack Morgenstein {
81111c6094SJack Morgenstein 	int i;
82111c6094SJack Morgenstein 
83111c6094SJack Morgenstein 	mutex_init(&table->mutex);
84111c6094SJack Morgenstein 	for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++)
85111c6094SJack Morgenstein 		memset(table->roce_gids[i].raw, 0, MLX4_ROCE_GID_ENTRY_SIZE);
86111c6094SJack Morgenstein }
87111c6094SJack Morgenstein 
885a2cc190SJeff Kirsher static int validate_index(struct mlx4_dev *dev,
895a2cc190SJeff Kirsher 			  struct mlx4_mac_table *table, int index)
905a2cc190SJeff Kirsher {
915a2cc190SJeff Kirsher 	int err = 0;
925a2cc190SJeff Kirsher 
935a2cc190SJeff Kirsher 	if (index < 0 || index >= table->max || !table->entries[index]) {
945a2cc190SJeff Kirsher 		mlx4_warn(dev, "No valid Mac entry for the given index\n");
955a2cc190SJeff Kirsher 		err = -EINVAL;
965a2cc190SJeff Kirsher 	}
975a2cc190SJeff Kirsher 	return err;
985a2cc190SJeff Kirsher }
995a2cc190SJeff Kirsher 
1005a2cc190SJeff Kirsher static int find_index(struct mlx4_dev *dev,
1015a2cc190SJeff Kirsher 		      struct mlx4_mac_table *table, u64 mac)
1025a2cc190SJeff Kirsher {
1035a2cc190SJeff Kirsher 	int i;
104ffe455adSEugenia Emantayev 
1055a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
106ffe455adSEugenia Emantayev 		if ((mac & MLX4_MAC_MASK) ==
107ffe455adSEugenia Emantayev 		    (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))
1085a2cc190SJeff Kirsher 			return i;
1095a2cc190SJeff Kirsher 	}
1105a2cc190SJeff Kirsher 	/* Mac not found */
1115a2cc190SJeff Kirsher 	return -EINVAL;
1125a2cc190SJeff Kirsher }
1135a2cc190SJeff Kirsher 
114ffe455adSEugenia Emantayev static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
115ffe455adSEugenia Emantayev 				   __be64 *entries)
116ffe455adSEugenia Emantayev {
117ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
118ffe455adSEugenia Emantayev 	u32 in_mod;
119ffe455adSEugenia Emantayev 	int err;
120ffe455adSEugenia Emantayev 
121ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
122ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
123ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
124ffe455adSEugenia Emantayev 
125ffe455adSEugenia Emantayev 	memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE);
126ffe455adSEugenia Emantayev 
127ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port;
128ffe455adSEugenia Emantayev 
129ffe455adSEugenia Emantayev 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
130ffe455adSEugenia Emantayev 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
131ffe455adSEugenia Emantayev 
132ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
133ffe455adSEugenia Emantayev 	return err;
134ffe455adSEugenia Emantayev }
135ffe455adSEugenia Emantayev 
136297e0dadSMoni Shoua int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx)
137297e0dadSMoni Shoua {
138297e0dadSMoni Shoua 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
139297e0dadSMoni Shoua 	struct mlx4_mac_table *table = &info->mac_table;
140297e0dadSMoni Shoua 	int i;
141297e0dadSMoni Shoua 
142297e0dadSMoni Shoua 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
143297e0dadSMoni Shoua 		if (!table->refs[i])
144297e0dadSMoni Shoua 			continue;
145297e0dadSMoni Shoua 
146297e0dadSMoni Shoua 		if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
147297e0dadSMoni Shoua 			*idx = i;
148297e0dadSMoni Shoua 			return 0;
149297e0dadSMoni Shoua 		}
150297e0dadSMoni Shoua 	}
151297e0dadSMoni Shoua 
152297e0dadSMoni Shoua 	return -ENOENT;
153297e0dadSMoni Shoua }
154297e0dadSMoni Shoua EXPORT_SYMBOL_GPL(mlx4_find_cached_mac);
155297e0dadSMoni Shoua 
156ffe455adSEugenia Emantayev int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
157ffe455adSEugenia Emantayev {
158ffe455adSEugenia Emantayev 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
159ffe455adSEugenia Emantayev 	struct mlx4_mac_table *table = &info->mac_table;
160ffe455adSEugenia Emantayev 	int i, err = 0;
161ffe455adSEugenia Emantayev 	int free = -1;
162ffe455adSEugenia Emantayev 
163ffe455adSEugenia Emantayev 	mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d\n",
164ffe455adSEugenia Emantayev 		 (unsigned long long) mac, port);
165ffe455adSEugenia Emantayev 
166ffe455adSEugenia Emantayev 	mutex_lock(&table->mutex);
167ffe455adSEugenia Emantayev 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
168ffe455adSEugenia Emantayev 		if (free < 0 && !table->entries[i]) {
169ffe455adSEugenia Emantayev 			free = i;
170ffe455adSEugenia Emantayev 			continue;
171ffe455adSEugenia Emantayev 		}
172ffe455adSEugenia Emantayev 
173ffe455adSEugenia Emantayev 		if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
1746ce71acdSRony Efraim 			/* MAC already registered, increment ref count */
1756ce71acdSRony Efraim 			err = i;
1766ce71acdSRony Efraim 			++table->refs[i];
177ffe455adSEugenia Emantayev 			goto out;
178ffe455adSEugenia Emantayev 		}
179ffe455adSEugenia Emantayev 	}
180ffe455adSEugenia Emantayev 
181ffe455adSEugenia Emantayev 	mlx4_dbg(dev, "Free MAC index is %d\n", free);
182ffe455adSEugenia Emantayev 
183ffe455adSEugenia Emantayev 	if (table->total == table->max) {
184ffe455adSEugenia Emantayev 		/* No free mac entries */
185ffe455adSEugenia Emantayev 		err = -ENOSPC;
186ffe455adSEugenia Emantayev 		goto out;
187ffe455adSEugenia Emantayev 	}
188ffe455adSEugenia Emantayev 
189ffe455adSEugenia Emantayev 	/* Register new MAC */
190ffe455adSEugenia Emantayev 	table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
191ffe455adSEugenia Emantayev 
192ffe455adSEugenia Emantayev 	err = mlx4_set_port_mac_table(dev, port, table->entries);
193ffe455adSEugenia Emantayev 	if (unlikely(err)) {
194ffe455adSEugenia Emantayev 		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
195ffe455adSEugenia Emantayev 			 (unsigned long long) mac);
196ffe455adSEugenia Emantayev 		table->entries[free] = 0;
197ffe455adSEugenia Emantayev 		goto out;
198ffe455adSEugenia Emantayev 	}
1996ce71acdSRony Efraim 	table->refs[free] = 1;
200ffe455adSEugenia Emantayev 	err = free;
201ffe455adSEugenia Emantayev 	++table->total;
202ffe455adSEugenia Emantayev out:
203ffe455adSEugenia Emantayev 	mutex_unlock(&table->mutex);
204ffe455adSEugenia Emantayev 	return err;
205ffe455adSEugenia Emantayev }
206ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_register_mac);
207ffe455adSEugenia Emantayev 
208ffe455adSEugenia Emantayev int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
209ffe455adSEugenia Emantayev {
210e7dbeba8SJack Morgenstein 	u64 out_param = 0;
211acddd5ddSJack Morgenstein 	int err = -EINVAL;
212ffe455adSEugenia Emantayev 
213ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
214acddd5ddSJack Morgenstein 		if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) {
215acddd5ddSJack Morgenstein 			err = mlx4_cmd_imm(dev, mac, &out_param,
216acddd5ddSJack Morgenstein 					   ((u32) port) << 8 | (u32) RES_MAC,
217acddd5ddSJack Morgenstein 					   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
218acddd5ddSJack Morgenstein 					   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
219acddd5ddSJack Morgenstein 		}
220acddd5ddSJack Morgenstein 		if (err && err == -EINVAL && mlx4_is_slave(dev)) {
221acddd5ddSJack Morgenstein 			/* retry using old REG_MAC format */
222ffe455adSEugenia Emantayev 			set_param_l(&out_param, port);
223ffe455adSEugenia Emantayev 			err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC,
224ffe455adSEugenia Emantayev 					   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
225ffe455adSEugenia Emantayev 					   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
226acddd5ddSJack Morgenstein 			if (!err)
227acddd5ddSJack Morgenstein 				dev->flags |= MLX4_FLAG_OLD_REG_MAC;
228acddd5ddSJack Morgenstein 		}
229ffe455adSEugenia Emantayev 		if (err)
230ffe455adSEugenia Emantayev 			return err;
231ffe455adSEugenia Emantayev 
232ffe455adSEugenia Emantayev 		return get_param_l(&out_param);
233ffe455adSEugenia Emantayev 	}
234ffe455adSEugenia Emantayev 	return __mlx4_register_mac(dev, port, mac);
235ffe455adSEugenia Emantayev }
236ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(mlx4_register_mac);
237ffe455adSEugenia Emantayev 
23816a10ffdSYan Burman int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port)
23916a10ffdSYan Burman {
24016a10ffdSYan Burman 	return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
24116a10ffdSYan Burman 			(port - 1) * (1 << dev->caps.log_num_macs);
24216a10ffdSYan Burman }
24316a10ffdSYan Burman EXPORT_SYMBOL_GPL(mlx4_get_base_qpn);
244ffe455adSEugenia Emantayev 
245ffe455adSEugenia Emantayev void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
246ffe455adSEugenia Emantayev {
247ffe455adSEugenia Emantayev 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
248ffe455adSEugenia Emantayev 	struct mlx4_mac_table *table = &info->mac_table;
249ffe455adSEugenia Emantayev 	int index;
250ffe455adSEugenia Emantayev 
2515a2cc190SJeff Kirsher 	mutex_lock(&table->mutex);
2526ce71acdSRony Efraim 	index = find_index(dev, table, mac);
2535a2cc190SJeff Kirsher 
2545a2cc190SJeff Kirsher 	if (validate_index(dev, table, index))
2555a2cc190SJeff Kirsher 		goto out;
2566ce71acdSRony Efraim 	if (--table->refs[index]) {
2571a91de28SJoe Perches 		mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n",
2581a91de28SJoe Perches 			 index);
2596ce71acdSRony Efraim 		goto out;
2606ce71acdSRony Efraim 	}
2615a2cc190SJeff Kirsher 
2625a2cc190SJeff Kirsher 	table->entries[index] = 0;
2635a2cc190SJeff Kirsher 	mlx4_set_port_mac_table(dev, port, table->entries);
2645a2cc190SJeff Kirsher 	--table->total;
2655a2cc190SJeff Kirsher out:
2665a2cc190SJeff Kirsher 	mutex_unlock(&table->mutex);
2675a2cc190SJeff Kirsher }
268ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_unregister_mac);
269ffe455adSEugenia Emantayev 
270ffe455adSEugenia Emantayev void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
271ffe455adSEugenia Emantayev {
272e7dbeba8SJack Morgenstein 	u64 out_param = 0;
273ffe455adSEugenia Emantayev 
274ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
275acddd5ddSJack Morgenstein 		if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) {
276acddd5ddSJack Morgenstein 			(void) mlx4_cmd_imm(dev, mac, &out_param,
277acddd5ddSJack Morgenstein 					    ((u32) port) << 8 | (u32) RES_MAC,
278acddd5ddSJack Morgenstein 					    RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
279acddd5ddSJack Morgenstein 					    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
280acddd5ddSJack Morgenstein 		} else {
281acddd5ddSJack Morgenstein 			/* use old unregister mac format */
282ffe455adSEugenia Emantayev 			set_param_l(&out_param, port);
283162344edSOr Gerlitz 			(void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC,
284ffe455adSEugenia Emantayev 					    RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
285ffe455adSEugenia Emantayev 					    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
286acddd5ddSJack Morgenstein 		}
287ffe455adSEugenia Emantayev 		return;
288ffe455adSEugenia Emantayev 	}
289ffe455adSEugenia Emantayev 	__mlx4_unregister_mac(dev, port, mac);
290ffe455adSEugenia Emantayev 	return;
291ffe455adSEugenia Emantayev }
2925a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
2935a2cc190SJeff Kirsher 
29416a10ffdSYan Burman int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
2955a2cc190SJeff Kirsher {
2965a2cc190SJeff Kirsher 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
2975a2cc190SJeff Kirsher 	struct mlx4_mac_table *table = &info->mac_table;
298ffe455adSEugenia Emantayev 	int index = qpn - info->base_qpn;
299ffe455adSEugenia Emantayev 	int err = 0;
3005a2cc190SJeff Kirsher 
301ffe455adSEugenia Emantayev 	/* CX1 doesn't support multi-functions */
3025a2cc190SJeff Kirsher 	mutex_lock(&table->mutex);
3035a2cc190SJeff Kirsher 
3045a2cc190SJeff Kirsher 	err = validate_index(dev, table, index);
3055a2cc190SJeff Kirsher 	if (err)
3065a2cc190SJeff Kirsher 		goto out;
3075a2cc190SJeff Kirsher 
3085a2cc190SJeff Kirsher 	table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
3095a2cc190SJeff Kirsher 
3105a2cc190SJeff Kirsher 	err = mlx4_set_port_mac_table(dev, port, table->entries);
3115a2cc190SJeff Kirsher 	if (unlikely(err)) {
312ffe455adSEugenia Emantayev 		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
313ffe455adSEugenia Emantayev 			 (unsigned long long) new_mac);
3145a2cc190SJeff Kirsher 		table->entries[index] = 0;
3155a2cc190SJeff Kirsher 	}
3165a2cc190SJeff Kirsher out:
3175a2cc190SJeff Kirsher 	mutex_unlock(&table->mutex);
3185a2cc190SJeff Kirsher 	return err;
3195a2cc190SJeff Kirsher }
32016a10ffdSYan Burman EXPORT_SYMBOL_GPL(__mlx4_replace_mac);
321ffe455adSEugenia Emantayev 
3225a2cc190SJeff Kirsher static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
3235a2cc190SJeff Kirsher 				    __be32 *entries)
3245a2cc190SJeff Kirsher {
3255a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *mailbox;
3265a2cc190SJeff Kirsher 	u32 in_mod;
3275a2cc190SJeff Kirsher 	int err;
3285a2cc190SJeff Kirsher 
3295a2cc190SJeff Kirsher 	mailbox = mlx4_alloc_cmd_mailbox(dev);
3305a2cc190SJeff Kirsher 	if (IS_ERR(mailbox))
3315a2cc190SJeff Kirsher 		return PTR_ERR(mailbox);
3325a2cc190SJeff Kirsher 
3335a2cc190SJeff Kirsher 	memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE);
3345a2cc190SJeff Kirsher 	in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port;
3355a2cc190SJeff Kirsher 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
336162226a1SJack Morgenstein 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
3375a2cc190SJeff Kirsher 
3385a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, mailbox);
3395a2cc190SJeff Kirsher 
3405a2cc190SJeff Kirsher 	return err;
3415a2cc190SJeff Kirsher }
3425a2cc190SJeff Kirsher 
3435a2cc190SJeff Kirsher int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
3445a2cc190SJeff Kirsher {
3455a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
3465a2cc190SJeff Kirsher 	int i;
3475a2cc190SJeff Kirsher 
3485a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) {
3495a2cc190SJeff Kirsher 		if (table->refs[i] &&
3505a2cc190SJeff Kirsher 		    (vid == (MLX4_VLAN_MASK &
3515a2cc190SJeff Kirsher 			      be32_to_cpu(table->entries[i])))) {
3525a2cc190SJeff Kirsher 			/* VLAN already registered, increase reference count */
3535a2cc190SJeff Kirsher 			*idx = i;
3545a2cc190SJeff Kirsher 			return 0;
3555a2cc190SJeff Kirsher 		}
3565a2cc190SJeff Kirsher 	}
3575a2cc190SJeff Kirsher 
3585a2cc190SJeff Kirsher 	return -ENOENT;
3595a2cc190SJeff Kirsher }
3605a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
3615a2cc190SJeff Kirsher 
3623f7fb021SRony Efraim int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
363ffe455adSEugenia Emantayev 				int *index)
3645a2cc190SJeff Kirsher {
3655a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
3665a2cc190SJeff Kirsher 	int i, err = 0;
3675a2cc190SJeff Kirsher 	int free = -1;
3685a2cc190SJeff Kirsher 
3695a2cc190SJeff Kirsher 	mutex_lock(&table->mutex);
370e72ebf5aSYevgeny Petrilin 
371e72ebf5aSYevgeny Petrilin 	if (table->total == table->max) {
372e72ebf5aSYevgeny Petrilin 		/* No free vlan entries */
373e72ebf5aSYevgeny Petrilin 		err = -ENOSPC;
374e72ebf5aSYevgeny Petrilin 		goto out;
375e72ebf5aSYevgeny Petrilin 	}
376e72ebf5aSYevgeny Petrilin 
3775a2cc190SJeff Kirsher 	for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
3785a2cc190SJeff Kirsher 		if (free < 0 && (table->refs[i] == 0)) {
3795a2cc190SJeff Kirsher 			free = i;
3805a2cc190SJeff Kirsher 			continue;
3815a2cc190SJeff Kirsher 		}
3825a2cc190SJeff Kirsher 
3835a2cc190SJeff Kirsher 		if (table->refs[i] &&
3845a2cc190SJeff Kirsher 		    (vlan == (MLX4_VLAN_MASK &
3855a2cc190SJeff Kirsher 			      be32_to_cpu(table->entries[i])))) {
3865a2cc190SJeff Kirsher 			/* Vlan already registered, increase references count */
3875a2cc190SJeff Kirsher 			*index = i;
3885a2cc190SJeff Kirsher 			++table->refs[i];
3895a2cc190SJeff Kirsher 			goto out;
3905a2cc190SJeff Kirsher 		}
3915a2cc190SJeff Kirsher 	}
3925a2cc190SJeff Kirsher 
3935a2cc190SJeff Kirsher 	if (free < 0) {
3945a2cc190SJeff Kirsher 		err = -ENOMEM;
3955a2cc190SJeff Kirsher 		goto out;
3965a2cc190SJeff Kirsher 	}
3975a2cc190SJeff Kirsher 
398ffe455adSEugenia Emantayev 	/* Register new VLAN */
3995a2cc190SJeff Kirsher 	table->refs[free] = 1;
4005a2cc190SJeff Kirsher 	table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
4015a2cc190SJeff Kirsher 
4025a2cc190SJeff Kirsher 	err = mlx4_set_port_vlan_table(dev, port, table->entries);
4035a2cc190SJeff Kirsher 	if (unlikely(err)) {
4045a2cc190SJeff Kirsher 		mlx4_warn(dev, "Failed adding vlan: %u\n", vlan);
4055a2cc190SJeff Kirsher 		table->refs[free] = 0;
4065a2cc190SJeff Kirsher 		table->entries[free] = 0;
4075a2cc190SJeff Kirsher 		goto out;
4085a2cc190SJeff Kirsher 	}
4095a2cc190SJeff Kirsher 
4105a2cc190SJeff Kirsher 	*index = free;
4115a2cc190SJeff Kirsher 	++table->total;
4125a2cc190SJeff Kirsher out:
4135a2cc190SJeff Kirsher 	mutex_unlock(&table->mutex);
4145a2cc190SJeff Kirsher 	return err;
4155a2cc190SJeff Kirsher }
416ffe455adSEugenia Emantayev 
417ffe455adSEugenia Emantayev int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
418ffe455adSEugenia Emantayev {
419e7dbeba8SJack Morgenstein 	u64 out_param = 0;
420ffe455adSEugenia Emantayev 	int err;
421ffe455adSEugenia Emantayev 
422162226a1SJack Morgenstein 	if (vlan > 4095)
423162226a1SJack Morgenstein 		return -EINVAL;
424162226a1SJack Morgenstein 
425ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
426acddd5ddSJack Morgenstein 		err = mlx4_cmd_imm(dev, vlan, &out_param,
427acddd5ddSJack Morgenstein 				   ((u32) port) << 8 | (u32) RES_VLAN,
428ffe455adSEugenia Emantayev 				   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
429ffe455adSEugenia Emantayev 				   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
430ffe455adSEugenia Emantayev 		if (!err)
431ffe455adSEugenia Emantayev 			*index = get_param_l(&out_param);
432ffe455adSEugenia Emantayev 
433ffe455adSEugenia Emantayev 		return err;
434ffe455adSEugenia Emantayev 	}
435ffe455adSEugenia Emantayev 	return __mlx4_register_vlan(dev, port, vlan, index);
436ffe455adSEugenia Emantayev }
4375a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_register_vlan);
4385a2cc190SJeff Kirsher 
4392009d005SJack Morgenstein void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
4405a2cc190SJeff Kirsher {
4415a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
4422009d005SJack Morgenstein 	int index;
4432009d005SJack Morgenstein 
4442009d005SJack Morgenstein 	mutex_lock(&table->mutex);
4452009d005SJack Morgenstein 	if (mlx4_find_cached_vlan(dev, port, vlan, &index)) {
4462009d005SJack Morgenstein 		mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan);
4472009d005SJack Morgenstein 		goto out;
4482009d005SJack Morgenstein 	}
4495a2cc190SJeff Kirsher 
4505a2cc190SJeff Kirsher 	if (index < MLX4_VLAN_REGULAR) {
4515a2cc190SJeff Kirsher 		mlx4_warn(dev, "Trying to free special vlan index %d\n", index);
4525a2cc190SJeff Kirsher 		goto out;
4535a2cc190SJeff Kirsher 	}
4542009d005SJack Morgenstein 
4555a2cc190SJeff Kirsher 	if (--table->refs[index]) {
4561a91de28SJoe Perches 		mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n",
4571a91de28SJoe Perches 			 table->refs[index], index);
4585a2cc190SJeff Kirsher 		goto out;
4595a2cc190SJeff Kirsher 	}
4605a2cc190SJeff Kirsher 	table->entries[index] = 0;
4615a2cc190SJeff Kirsher 	mlx4_set_port_vlan_table(dev, port, table->entries);
4625a2cc190SJeff Kirsher 	--table->total;
4635a2cc190SJeff Kirsher out:
4645a2cc190SJeff Kirsher 	mutex_unlock(&table->mutex);
4655a2cc190SJeff Kirsher }
466ffe455adSEugenia Emantayev 
4672009d005SJack Morgenstein void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
468ffe455adSEugenia Emantayev {
469162226a1SJack Morgenstein 	u64 out_param = 0;
470ffe455adSEugenia Emantayev 
471ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
4722009d005SJack Morgenstein 		(void) mlx4_cmd_imm(dev, vlan, &out_param,
473acddd5ddSJack Morgenstein 				    ((u32) port) << 8 | (u32) RES_VLAN,
474162226a1SJack Morgenstein 				    RES_OP_RESERVE_AND_MAP,
475ffe455adSEugenia Emantayev 				    MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A,
476ffe455adSEugenia Emantayev 				    MLX4_CMD_WRAPPED);
477ffe455adSEugenia Emantayev 		return;
478ffe455adSEugenia Emantayev 	}
4792009d005SJack Morgenstein 	__mlx4_unregister_vlan(dev, port, vlan);
480ffe455adSEugenia Emantayev }
4815a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_vlan);
4825a2cc190SJeff Kirsher 
4835a2cc190SJeff Kirsher int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
4845a2cc190SJeff Kirsher {
4855a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
4865a2cc190SJeff Kirsher 	u8 *inbuf, *outbuf;
4875a2cc190SJeff Kirsher 	int err;
4885a2cc190SJeff Kirsher 
4895a2cc190SJeff Kirsher 	inmailbox = mlx4_alloc_cmd_mailbox(dev);
4905a2cc190SJeff Kirsher 	if (IS_ERR(inmailbox))
4915a2cc190SJeff Kirsher 		return PTR_ERR(inmailbox);
4925a2cc190SJeff Kirsher 
4935a2cc190SJeff Kirsher 	outmailbox = mlx4_alloc_cmd_mailbox(dev);
4945a2cc190SJeff Kirsher 	if (IS_ERR(outmailbox)) {
4955a2cc190SJeff Kirsher 		mlx4_free_cmd_mailbox(dev, inmailbox);
4965a2cc190SJeff Kirsher 		return PTR_ERR(outmailbox);
4975a2cc190SJeff Kirsher 	}
4985a2cc190SJeff Kirsher 
4995a2cc190SJeff Kirsher 	inbuf = inmailbox->buf;
5005a2cc190SJeff Kirsher 	outbuf = outmailbox->buf;
5015a2cc190SJeff Kirsher 	inbuf[0] = 1;
5025a2cc190SJeff Kirsher 	inbuf[1] = 1;
5035a2cc190SJeff Kirsher 	inbuf[2] = 1;
5045a2cc190SJeff Kirsher 	inbuf[3] = 1;
5055a2cc190SJeff Kirsher 	*(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015);
5065a2cc190SJeff Kirsher 	*(__be32 *) (&inbuf[20]) = cpu_to_be32(port);
5075a2cc190SJeff Kirsher 
5085a2cc190SJeff Kirsher 	err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3,
509f9baff50SJack Morgenstein 			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
510f9baff50SJack Morgenstein 			   MLX4_CMD_NATIVE);
5115a2cc190SJeff Kirsher 	if (!err)
5125a2cc190SJeff Kirsher 		*caps = *(__be32 *) (outbuf + 84);
5135a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, inmailbox);
5145a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, outmailbox);
5155a2cc190SJeff Kirsher 	return err;
5165a2cc190SJeff Kirsher }
5179cd59352SJack Morgenstein static struct mlx4_roce_gid_entry zgid_entry;
5185a2cc190SJeff Kirsher 
519449fc488SMatan Barak int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port)
520b6ffaeffSJack Morgenstein {
521449fc488SMatan Barak 	int vfs;
522449fc488SMatan Barak 	int slave_gid = slave;
523449fc488SMatan Barak 	unsigned i;
524449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
525449fc488SMatan Barak 	struct mlx4_active_ports actv_ports;
526449fc488SMatan Barak 	unsigned max_port_p_one;
527449fc488SMatan Barak 
528b6ffaeffSJack Morgenstein 	if (slave == 0)
529b6ffaeffSJack Morgenstein 		return MLX4_ROCE_PF_GIDS;
530449fc488SMatan Barak 
531449fc488SMatan Barak 	/* Slave is a VF */
532449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
533449fc488SMatan Barak 	actv_ports = mlx4_get_active_ports(dev, slave);
534449fc488SMatan Barak 	max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
535449fc488SMatan Barak 		bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
536449fc488SMatan Barak 
537449fc488SMatan Barak 	for (i = 1; i < max_port_p_one; i++) {
538449fc488SMatan Barak 		struct mlx4_active_ports exclusive_ports;
539449fc488SMatan Barak 		struct mlx4_slaves_pport slaves_pport_actv;
540449fc488SMatan Barak 		bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
541449fc488SMatan Barak 		set_bit(i - 1, exclusive_ports.ports);
542449fc488SMatan Barak 		if (i == port)
543449fc488SMatan Barak 			continue;
544449fc488SMatan Barak 		slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
545449fc488SMatan Barak 				    dev, &exclusive_ports);
546449fc488SMatan Barak 		slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
547449fc488SMatan Barak 					   dev->num_vfs + 1);
548449fc488SMatan Barak 	}
549449fc488SMatan Barak 	vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
550449fc488SMatan Barak 	if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs))
551449fc488SMatan Barak 		return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1;
552449fc488SMatan Barak 	return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs;
553b6ffaeffSJack Morgenstein }
554b6ffaeffSJack Morgenstein 
555449fc488SMatan Barak int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port)
556b6ffaeffSJack Morgenstein {
557b6ffaeffSJack Morgenstein 	int gids;
558449fc488SMatan Barak 	unsigned i;
559449fc488SMatan Barak 	int slave_gid = slave;
560b6ffaeffSJack Morgenstein 	int vfs;
561b6ffaeffSJack Morgenstein 
562449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
563449fc488SMatan Barak 	struct mlx4_active_ports actv_ports;
564449fc488SMatan Barak 	unsigned max_port_p_one;
565b6ffaeffSJack Morgenstein 
566b6ffaeffSJack Morgenstein 	if (slave == 0)
567b6ffaeffSJack Morgenstein 		return 0;
568b6ffaeffSJack Morgenstein 
569449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
570449fc488SMatan Barak 	actv_ports = mlx4_get_active_ports(dev, slave);
571449fc488SMatan Barak 	max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
572449fc488SMatan Barak 		bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
573449fc488SMatan Barak 
574449fc488SMatan Barak 	for (i = 1; i < max_port_p_one; i++) {
575449fc488SMatan Barak 		struct mlx4_active_ports exclusive_ports;
576449fc488SMatan Barak 		struct mlx4_slaves_pport slaves_pport_actv;
577449fc488SMatan Barak 		bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
578449fc488SMatan Barak 		set_bit(i - 1, exclusive_ports.ports);
579449fc488SMatan Barak 		if (i == port)
580449fc488SMatan Barak 			continue;
581449fc488SMatan Barak 		slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
582449fc488SMatan Barak 				    dev, &exclusive_ports);
583449fc488SMatan Barak 		slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
584449fc488SMatan Barak 					   dev->num_vfs + 1);
585b6ffaeffSJack Morgenstein 	}
586449fc488SMatan Barak 	gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
587449fc488SMatan Barak 	vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
588449fc488SMatan Barak 	if (slave_gid <= gids % vfs)
589449fc488SMatan Barak 		return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1);
590449fc488SMatan Barak 
591449fc488SMatan Barak 	return MLX4_ROCE_PF_GIDS + (gids % vfs) +
592449fc488SMatan Barak 		((gids / vfs) * (slave_gid - 1));
593449fc488SMatan Barak }
594449fc488SMatan Barak EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix);
595b6ffaeffSJack Morgenstein 
596111c6094SJack Morgenstein static int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave,
597111c6094SJack Morgenstein 				     int port, struct mlx4_cmd_mailbox *mailbox)
598111c6094SJack Morgenstein {
599111c6094SJack Morgenstein 	struct mlx4_roce_gid_entry *gid_entry_mbox;
600111c6094SJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
601111c6094SJack Morgenstein 	int num_gids, base, offset;
602111c6094SJack Morgenstein 	int i, err;
603111c6094SJack Morgenstein 
604111c6094SJack Morgenstein 	num_gids = mlx4_get_slave_num_gids(dev, slave, port);
605111c6094SJack Morgenstein 	base = mlx4_get_base_gid_ix(dev, slave, port);
606111c6094SJack Morgenstein 
607111c6094SJack Morgenstein 	memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE);
608111c6094SJack Morgenstein 
609111c6094SJack Morgenstein 	mutex_lock(&(priv->port[port].gid_table.mutex));
610111c6094SJack Morgenstein 	/* Zero-out gids belonging to that slave in the port GID table */
611111c6094SJack Morgenstein 	for (i = 0, offset = base; i < num_gids; offset++, i++)
612111c6094SJack Morgenstein 		memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
613111c6094SJack Morgenstein 		       zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE);
614111c6094SJack Morgenstein 
615111c6094SJack Morgenstein 	/* Now, copy roce port gids table to mailbox for passing to FW */
616111c6094SJack Morgenstein 	gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf;
617111c6094SJack Morgenstein 	for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
618111c6094SJack Morgenstein 		memcpy(gid_entry_mbox->raw,
619111c6094SJack Morgenstein 		       priv->port[port].gid_table.roce_gids[i].raw,
620111c6094SJack Morgenstein 		       MLX4_ROCE_GID_ENTRY_SIZE);
621111c6094SJack Morgenstein 
622111c6094SJack Morgenstein 	err = mlx4_cmd(dev, mailbox->dma,
623111c6094SJack Morgenstein 		       ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8), 1,
624111c6094SJack Morgenstein 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
625111c6094SJack Morgenstein 		       MLX4_CMD_NATIVE);
626111c6094SJack Morgenstein 	mutex_unlock(&(priv->port[port].gid_table.mutex));
627111c6094SJack Morgenstein 	return err;
628111c6094SJack Morgenstein }
629111c6094SJack Morgenstein 
630111c6094SJack Morgenstein 
631111c6094SJack Morgenstein void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave)
632111c6094SJack Morgenstein {
633111c6094SJack Morgenstein 	struct mlx4_active_ports actv_ports;
634111c6094SJack Morgenstein 	struct mlx4_cmd_mailbox *mailbox;
635111c6094SJack Morgenstein 	int num_eth_ports, err;
636111c6094SJack Morgenstein 	int i;
637111c6094SJack Morgenstein 
638111c6094SJack Morgenstein 	if (slave < 0 || slave > dev->num_vfs)
639111c6094SJack Morgenstein 		return;
640111c6094SJack Morgenstein 
641111c6094SJack Morgenstein 	actv_ports = mlx4_get_active_ports(dev, slave);
642111c6094SJack Morgenstein 
643111c6094SJack Morgenstein 	for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) {
644111c6094SJack Morgenstein 		if (test_bit(i, actv_ports.ports)) {
645111c6094SJack Morgenstein 			if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
646111c6094SJack Morgenstein 				continue;
647111c6094SJack Morgenstein 			num_eth_ports++;
648111c6094SJack Morgenstein 		}
649111c6094SJack Morgenstein 	}
650111c6094SJack Morgenstein 
651111c6094SJack Morgenstein 	if (!num_eth_ports)
652111c6094SJack Morgenstein 		return;
653111c6094SJack Morgenstein 
654111c6094SJack Morgenstein 	/* have ETH ports.  Alloc mailbox for SET_PORT command */
655111c6094SJack Morgenstein 	mailbox = mlx4_alloc_cmd_mailbox(dev);
656111c6094SJack Morgenstein 	if (IS_ERR(mailbox))
657111c6094SJack Morgenstein 		return;
658111c6094SJack Morgenstein 
659111c6094SJack Morgenstein 	for (i = 0; i < dev->caps.num_ports; i++) {
660111c6094SJack Morgenstein 		if (test_bit(i, actv_ports.ports)) {
661111c6094SJack Morgenstein 			if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
662111c6094SJack Morgenstein 				continue;
663111c6094SJack Morgenstein 			err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox);
664111c6094SJack Morgenstein 			if (err)
665111c6094SJack Morgenstein 				mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n",
666111c6094SJack Morgenstein 					  slave, i + 1, err);
667111c6094SJack Morgenstein 		}
668111c6094SJack Morgenstein 	}
669111c6094SJack Morgenstein 
670111c6094SJack Morgenstein 	mlx4_free_cmd_mailbox(dev, mailbox);
671111c6094SJack Morgenstein 	return;
672111c6094SJack Morgenstein }
673111c6094SJack Morgenstein 
674ffe455adSEugenia Emantayev static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
675ffe455adSEugenia Emantayev 				u8 op_mod, struct mlx4_cmd_mailbox *inbox)
676ffe455adSEugenia Emantayev {
677ffe455adSEugenia Emantayev 	struct mlx4_priv *priv = mlx4_priv(dev);
678ffe455adSEugenia Emantayev 	struct mlx4_port_info *port_info;
679ffe455adSEugenia Emantayev 	struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
680ffe455adSEugenia Emantayev 	struct mlx4_slave_state *slave_st = &master->slave_state[slave];
681ffe455adSEugenia Emantayev 	struct mlx4_set_port_rqp_calc_context *qpn_context;
682ffe455adSEugenia Emantayev 	struct mlx4_set_port_general_context *gen_context;
683b6ffaeffSJack Morgenstein 	struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1;
684ffe455adSEugenia Emantayev 	int reset_qkey_viols;
685ffe455adSEugenia Emantayev 	int port;
686ffe455adSEugenia Emantayev 	int is_eth;
687b6ffaeffSJack Morgenstein 	int num_gids;
688b6ffaeffSJack Morgenstein 	int base;
689ffe455adSEugenia Emantayev 	u32 in_modifier;
690ffe455adSEugenia Emantayev 	u32 promisc;
691ffe455adSEugenia Emantayev 	u16 mtu, prev_mtu;
692ffe455adSEugenia Emantayev 	int err;
693b6ffaeffSJack Morgenstein 	int i, j;
694b6ffaeffSJack Morgenstein 	int offset;
695ffe455adSEugenia Emantayev 	__be32 agg_cap_mask;
696ffe455adSEugenia Emantayev 	__be32 slave_cap_mask;
697ffe455adSEugenia Emantayev 	__be32 new_cap_mask;
698ffe455adSEugenia Emantayev 
699ffe455adSEugenia Emantayev 	port = in_mod & 0xff;
700ffe455adSEugenia Emantayev 	in_modifier = in_mod >> 8;
701ffe455adSEugenia Emantayev 	is_eth = op_mod;
702ffe455adSEugenia Emantayev 	port_info = &priv->port[port];
703ffe455adSEugenia Emantayev 
704ffe455adSEugenia Emantayev 	/* Slaves cannot perform SET_PORT operations except changing MTU */
705ffe455adSEugenia Emantayev 	if (is_eth) {
706ffe455adSEugenia Emantayev 		if (slave != dev->caps.function &&
7079cd59352SJack Morgenstein 		    in_modifier != MLX4_SET_PORT_GENERAL &&
7089cd59352SJack Morgenstein 		    in_modifier != MLX4_SET_PORT_GID_TABLE) {
709ffe455adSEugenia Emantayev 			mlx4_warn(dev, "denying SET_PORT for slave:%d\n",
710ffe455adSEugenia Emantayev 					slave);
711ffe455adSEugenia Emantayev 			return -EINVAL;
712ffe455adSEugenia Emantayev 		}
713ffe455adSEugenia Emantayev 		switch (in_modifier) {
714ffe455adSEugenia Emantayev 		case MLX4_SET_PORT_RQP_CALC:
715ffe455adSEugenia Emantayev 			qpn_context = inbox->buf;
716ffe455adSEugenia Emantayev 			qpn_context->base_qpn =
717ffe455adSEugenia Emantayev 				cpu_to_be32(port_info->base_qpn);
718ffe455adSEugenia Emantayev 			qpn_context->n_mac = 0x7;
719ffe455adSEugenia Emantayev 			promisc = be32_to_cpu(qpn_context->promisc) >>
720ffe455adSEugenia Emantayev 				SET_PORT_PROMISC_SHIFT;
721ffe455adSEugenia Emantayev 			qpn_context->promisc = cpu_to_be32(
722ffe455adSEugenia Emantayev 				promisc << SET_PORT_PROMISC_SHIFT |
723ffe455adSEugenia Emantayev 				port_info->base_qpn);
724ffe455adSEugenia Emantayev 			promisc = be32_to_cpu(qpn_context->mcast) >>
725ffe455adSEugenia Emantayev 				SET_PORT_MC_PROMISC_SHIFT;
726ffe455adSEugenia Emantayev 			qpn_context->mcast = cpu_to_be32(
727ffe455adSEugenia Emantayev 				promisc << SET_PORT_MC_PROMISC_SHIFT |
728ffe455adSEugenia Emantayev 				port_info->base_qpn);
729ffe455adSEugenia Emantayev 			break;
730ffe455adSEugenia Emantayev 		case MLX4_SET_PORT_GENERAL:
731ffe455adSEugenia Emantayev 			gen_context = inbox->buf;
732ffe455adSEugenia Emantayev 			/* Mtu is configured as the max MTU among all the
733ffe455adSEugenia Emantayev 			 * the functions on the port. */
734ffe455adSEugenia Emantayev 			mtu = be16_to_cpu(gen_context->mtu);
735c59fec20SEugenia Emantayev 			mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] +
736c59fec20SEugenia Emantayev 				    ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
737ffe455adSEugenia Emantayev 			prev_mtu = slave_st->mtu[port];
738ffe455adSEugenia Emantayev 			slave_st->mtu[port] = mtu;
739ffe455adSEugenia Emantayev 			if (mtu > master->max_mtu[port])
740ffe455adSEugenia Emantayev 				master->max_mtu[port] = mtu;
741ffe455adSEugenia Emantayev 			if (mtu < prev_mtu && prev_mtu ==
742ffe455adSEugenia Emantayev 						master->max_mtu[port]) {
743ffe455adSEugenia Emantayev 				slave_st->mtu[port] = mtu;
744ffe455adSEugenia Emantayev 				master->max_mtu[port] = mtu;
745ffe455adSEugenia Emantayev 				for (i = 0; i < dev->num_slaves; i++) {
746ffe455adSEugenia Emantayev 					master->max_mtu[port] =
747ffe455adSEugenia Emantayev 					max(master->max_mtu[port],
748ffe455adSEugenia Emantayev 					    master->slave_state[i].mtu[port]);
749ffe455adSEugenia Emantayev 				}
750ffe455adSEugenia Emantayev 			}
751ffe455adSEugenia Emantayev 
752ffe455adSEugenia Emantayev 			gen_context->mtu = cpu_to_be16(master->max_mtu[port]);
753ffe455adSEugenia Emantayev 			break;
7549cd59352SJack Morgenstein 		case MLX4_SET_PORT_GID_TABLE:
755b6ffaeffSJack Morgenstein 			/* change to MULTIPLE entries: number of guest's gids
756b6ffaeffSJack Morgenstein 			 * need a FOR-loop here over number of gids the guest has.
757b6ffaeffSJack Morgenstein 			 * 1. Check no duplicates in gids passed by slave
758b6ffaeffSJack Morgenstein 			 */
759449fc488SMatan Barak 			num_gids = mlx4_get_slave_num_gids(dev, slave, port);
760449fc488SMatan Barak 			base = mlx4_get_base_gid_ix(dev, slave, port);
761b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
762b6ffaeffSJack Morgenstein 			for (i = 0; i < num_gids; gid_entry_mbox++, i++) {
763b6ffaeffSJack Morgenstein 				if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
764b6ffaeffSJack Morgenstein 					    sizeof(zgid_entry)))
765b6ffaeffSJack Morgenstein 					continue;
766b6ffaeffSJack Morgenstein 				gid_entry_mb1 = gid_entry_mbox + 1;
767b6ffaeffSJack Morgenstein 				for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) {
768b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mb1->raw,
769b6ffaeffSJack Morgenstein 						    zgid_entry.raw, sizeof(zgid_entry)))
770b6ffaeffSJack Morgenstein 						continue;
771b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw,
772b6ffaeffSJack Morgenstein 						    sizeof(gid_entry_mbox->raw))) {
773b6ffaeffSJack Morgenstein 						/* found duplicate */
774b6ffaeffSJack Morgenstein 						return -EINVAL;
775b6ffaeffSJack Morgenstein 					}
776b6ffaeffSJack Morgenstein 				}
777b6ffaeffSJack Morgenstein 			}
778b6ffaeffSJack Morgenstein 
779b6ffaeffSJack Morgenstein 			/* 2. Check that do not have duplicates in OTHER
780b6ffaeffSJack Morgenstein 			 *    entries in the port GID table
781b6ffaeffSJack Morgenstein 			 */
782111c6094SJack Morgenstein 
783111c6094SJack Morgenstein 			mutex_lock(&(priv->port[port].gid_table.mutex));
7849cd59352SJack Morgenstein 			for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
785b6ffaeffSJack Morgenstein 				if (i >= base && i < base + num_gids)
786b6ffaeffSJack Morgenstein 					continue; /* don't compare to slave's current gids */
787111c6094SJack Morgenstein 				gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i];
788b6ffaeffSJack Morgenstein 				if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry)))
789b6ffaeffSJack Morgenstein 					continue;
790b6ffaeffSJack Morgenstein 				gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
791b6ffaeffSJack Morgenstein 				for (j = 0; j < num_gids; gid_entry_mbox++, j++) {
792b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
793b6ffaeffSJack Morgenstein 						    sizeof(zgid_entry)))
794b6ffaeffSJack Morgenstein 						continue;
795b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw,
796b6ffaeffSJack Morgenstein 						    sizeof(gid_entry_tbl->raw))) {
797b6ffaeffSJack Morgenstein 						/* found duplicate */
7981a91de28SJoe Perches 						mlx4_warn(dev, "requested gid entry for slave:%d is a duplicate of gid at index %d\n",
7999cd59352SJack Morgenstein 							  slave, i);
800111c6094SJack Morgenstein 						mutex_unlock(&(priv->port[port].gid_table.mutex));
801b6ffaeffSJack Morgenstein 						return -EINVAL;
8029cd59352SJack Morgenstein 					}
8039cd59352SJack Morgenstein 				}
8049cd59352SJack Morgenstein 			}
805b6ffaeffSJack Morgenstein 
806b6ffaeffSJack Morgenstein 			/* insert slave GIDs with memcpy, starting at slave's base index */
807b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
808b6ffaeffSJack Morgenstein 			for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++)
809111c6094SJack Morgenstein 				memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
810111c6094SJack Morgenstein 				       gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE);
811b6ffaeffSJack Morgenstein 
812b6ffaeffSJack Morgenstein 			/* Now, copy roce port gids table to current mailbox for passing to FW */
813b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
814b6ffaeffSJack Morgenstein 			for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
815111c6094SJack Morgenstein 				memcpy(gid_entry_mbox->raw,
816111c6094SJack Morgenstein 				       priv->port[port].gid_table.roce_gids[i].raw,
817111c6094SJack Morgenstein 				       MLX4_ROCE_GID_ENTRY_SIZE);
818b6ffaeffSJack Morgenstein 
819111c6094SJack Morgenstein 			err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
820111c6094SJack Morgenstein 				       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
821111c6094SJack Morgenstein 				       MLX4_CMD_NATIVE);
822111c6094SJack Morgenstein 			mutex_unlock(&(priv->port[port].gid_table.mutex));
823111c6094SJack Morgenstein 			return err;
824ffe455adSEugenia Emantayev 		}
825111c6094SJack Morgenstein 
826111c6094SJack Morgenstein 		return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
827ffe455adSEugenia Emantayev 				MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
828ffe455adSEugenia Emantayev 				MLX4_CMD_NATIVE);
829ffe455adSEugenia Emantayev 	}
830ffe455adSEugenia Emantayev 
831ffe455adSEugenia Emantayev 	/* For IB, we only consider:
832ffe455adSEugenia Emantayev 	 * - The capability mask, which is set to the aggregate of all
833ffe455adSEugenia Emantayev 	 *   slave function capabilities
834ffe455adSEugenia Emantayev 	 * - The QKey violatin counter - reset according to each request.
835ffe455adSEugenia Emantayev 	 */
836ffe455adSEugenia Emantayev 
837ffe455adSEugenia Emantayev 	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
838ffe455adSEugenia Emantayev 		reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40;
839ffe455adSEugenia Emantayev 		new_cap_mask = ((__be32 *) inbox->buf)[2];
840ffe455adSEugenia Emantayev 	} else {
841ffe455adSEugenia Emantayev 		reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1;
842ffe455adSEugenia Emantayev 		new_cap_mask = ((__be32 *) inbox->buf)[1];
843ffe455adSEugenia Emantayev 	}
844ffe455adSEugenia Emantayev 
845efcd235dSJack Morgenstein 	/* slave may not set the IS_SM capability for the port */
846efcd235dSJack Morgenstein 	if (slave != mlx4_master_func_num(dev) &&
847efcd235dSJack Morgenstein 	    (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM))
848efcd235dSJack Morgenstein 		return -EINVAL;
849efcd235dSJack Morgenstein 
850efcd235dSJack Morgenstein 	/* No DEV_MGMT in multifunc mode */
851efcd235dSJack Morgenstein 	if (mlx4_is_mfunc(dev) &&
852efcd235dSJack Morgenstein 	    (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP))
853efcd235dSJack Morgenstein 		return -EINVAL;
854efcd235dSJack Morgenstein 
855ffe455adSEugenia Emantayev 	agg_cap_mask = 0;
856ffe455adSEugenia Emantayev 	slave_cap_mask =
857ffe455adSEugenia Emantayev 		priv->mfunc.master.slave_state[slave].ib_cap_mask[port];
858ffe455adSEugenia Emantayev 	priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask;
859ffe455adSEugenia Emantayev 	for (i = 0; i < dev->num_slaves; i++)
860ffe455adSEugenia Emantayev 		agg_cap_mask |=
861ffe455adSEugenia Emantayev 			priv->mfunc.master.slave_state[i].ib_cap_mask[port];
862ffe455adSEugenia Emantayev 
863ffe455adSEugenia Emantayev 	/* only clear mailbox for guests.  Master may be setting
864ffe455adSEugenia Emantayev 	* MTU or PKEY table size
865ffe455adSEugenia Emantayev 	*/
866ffe455adSEugenia Emantayev 	if (slave != dev->caps.function)
867ffe455adSEugenia Emantayev 		memset(inbox->buf, 0, 256);
868ffe455adSEugenia Emantayev 	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
869edc4a67eSJack Morgenstein 		*(u8 *) inbox->buf	   |= !!reset_qkey_viols << 6;
870ffe455adSEugenia Emantayev 		((__be32 *) inbox->buf)[2] = agg_cap_mask;
871ffe455adSEugenia Emantayev 	} else {
872edc4a67eSJack Morgenstein 		((u8 *) inbox->buf)[3]     |= !!reset_qkey_viols;
873ffe455adSEugenia Emantayev 		((__be32 *) inbox->buf)[1] = agg_cap_mask;
874ffe455adSEugenia Emantayev 	}
875ffe455adSEugenia Emantayev 
876ffe455adSEugenia Emantayev 	err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT,
877ffe455adSEugenia Emantayev 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
878ffe455adSEugenia Emantayev 	if (err)
879ffe455adSEugenia Emantayev 		priv->mfunc.master.slave_state[slave].ib_cap_mask[port] =
880ffe455adSEugenia Emantayev 			slave_cap_mask;
881ffe455adSEugenia Emantayev 	return err;
882ffe455adSEugenia Emantayev }
883ffe455adSEugenia Emantayev 
884ffe455adSEugenia Emantayev int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave,
885ffe455adSEugenia Emantayev 			  struct mlx4_vhcr *vhcr,
886ffe455adSEugenia Emantayev 			  struct mlx4_cmd_mailbox *inbox,
887ffe455adSEugenia Emantayev 			  struct mlx4_cmd_mailbox *outbox,
888ffe455adSEugenia Emantayev 			  struct mlx4_cmd_info *cmd)
889ffe455adSEugenia Emantayev {
890449fc488SMatan Barak 	int port = mlx4_slave_convert_port(
891449fc488SMatan Barak 			dev, slave, vhcr->in_modifier & 0xFF);
892449fc488SMatan Barak 
893449fc488SMatan Barak 	if (port < 0)
894449fc488SMatan Barak 		return -EINVAL;
895449fc488SMatan Barak 
896449fc488SMatan Barak 	vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) |
897449fc488SMatan Barak 			    (port & 0xFF);
898449fc488SMatan Barak 
899ffe455adSEugenia Emantayev 	return mlx4_common_set_port(dev, slave, vhcr->in_modifier,
900ffe455adSEugenia Emantayev 				    vhcr->op_modifier, inbox);
901ffe455adSEugenia Emantayev }
902ffe455adSEugenia Emantayev 
903096335b3SOr Gerlitz /* bit locations for set port command with zero op modifier */
904096335b3SOr Gerlitz enum {
905096335b3SOr Gerlitz 	MLX4_SET_PORT_VL_CAP	 = 4, /* bits 7:4 */
906096335b3SOr Gerlitz 	MLX4_SET_PORT_MTU_CAP	 = 12, /* bits 15:12 */
9076634961cSJack Morgenstein 	MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20,
908096335b3SOr Gerlitz 	MLX4_CHANGE_PORT_VL_CAP	 = 21,
909096335b3SOr Gerlitz 	MLX4_CHANGE_PORT_MTU_CAP = 22,
910096335b3SOr Gerlitz };
911096335b3SOr Gerlitz 
9126634961cSJack Morgenstein int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz)
9135a2cc190SJeff Kirsher {
9145a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *mailbox;
9156634961cSJack Morgenstein 	int err, vl_cap, pkey_tbl_flag = 0;
9165a2cc190SJeff Kirsher 
9175a2cc190SJeff Kirsher 	if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
9185a2cc190SJeff Kirsher 		return 0;
9195a2cc190SJeff Kirsher 
9205a2cc190SJeff Kirsher 	mailbox = mlx4_alloc_cmd_mailbox(dev);
9215a2cc190SJeff Kirsher 	if (IS_ERR(mailbox))
9225a2cc190SJeff Kirsher 		return PTR_ERR(mailbox);
9235a2cc190SJeff Kirsher 
9245a2cc190SJeff Kirsher 	((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port];
925096335b3SOr Gerlitz 
9266634961cSJack Morgenstein 	if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) {
9276634961cSJack Morgenstein 		pkey_tbl_flag = 1;
9286634961cSJack Morgenstein 		((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz);
9296634961cSJack Morgenstein 	}
9306634961cSJack Morgenstein 
931096335b3SOr Gerlitz 	/* IB VL CAP enum isn't used by the firmware, just numerical values */
932096335b3SOr Gerlitz 	for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) {
933096335b3SOr Gerlitz 		((__be32 *) mailbox->buf)[0] = cpu_to_be32(
934096335b3SOr Gerlitz 			(1 << MLX4_CHANGE_PORT_MTU_CAP) |
935096335b3SOr Gerlitz 			(1 << MLX4_CHANGE_PORT_VL_CAP)  |
9366634961cSJack Morgenstein 			(pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) |
937096335b3SOr Gerlitz 			(dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) |
938096335b3SOr Gerlitz 			(vl_cap << MLX4_SET_PORT_VL_CAP));
9395a2cc190SJeff Kirsher 		err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT,
940f9baff50SJack Morgenstein 				MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
941096335b3SOr Gerlitz 		if (err != -ENOMEM)
942096335b3SOr Gerlitz 			break;
943096335b3SOr Gerlitz 	}
9445a2cc190SJeff Kirsher 
9455a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, mailbox);
9465a2cc190SJeff Kirsher 	return err;
9475a2cc190SJeff Kirsher }
948ffe455adSEugenia Emantayev 
949cb9ffb76SJoerg Roedel int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
950ffe455adSEugenia Emantayev 			  u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx)
951ffe455adSEugenia Emantayev {
952ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
953ffe455adSEugenia Emantayev 	struct mlx4_set_port_general_context *context;
954ffe455adSEugenia Emantayev 	int err;
955ffe455adSEugenia Emantayev 	u32 in_mod;
956ffe455adSEugenia Emantayev 
957ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
958ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
959ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
960ffe455adSEugenia Emantayev 	context = mailbox->buf;
961ffe455adSEugenia Emantayev 	context->flags = SET_PORT_GEN_ALL_VALID;
962ffe455adSEugenia Emantayev 	context->mtu = cpu_to_be16(mtu);
963ffe455adSEugenia Emantayev 	context->pptx = (pptx * (!pfctx)) << 7;
964ffe455adSEugenia Emantayev 	context->pfctx = pfctx;
965ffe455adSEugenia Emantayev 	context->pprx = (pprx * (!pfcrx)) << 7;
966ffe455adSEugenia Emantayev 	context->pfcrx = pfcrx;
967ffe455adSEugenia Emantayev 
968ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
969ffe455adSEugenia Emantayev 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
970ffe455adSEugenia Emantayev 		       MLX4_CMD_TIME_CLASS_B,  MLX4_CMD_WRAPPED);
971ffe455adSEugenia Emantayev 
972ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
973ffe455adSEugenia Emantayev 	return err;
974ffe455adSEugenia Emantayev }
975ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_general);
976ffe455adSEugenia Emantayev 
977cb9ffb76SJoerg Roedel int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
978ffe455adSEugenia Emantayev 			   u8 promisc)
979ffe455adSEugenia Emantayev {
980ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
981ffe455adSEugenia Emantayev 	struct mlx4_set_port_rqp_calc_context *context;
982ffe455adSEugenia Emantayev 	int err;
983ffe455adSEugenia Emantayev 	u32 in_mod;
984ffe455adSEugenia Emantayev 	u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ?
985ffe455adSEugenia Emantayev 		MCAST_DIRECT : MCAST_DEFAULT;
986ffe455adSEugenia Emantayev 
987c96d97f4SHadar Hen Zion 	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
988ffe455adSEugenia Emantayev 		return 0;
989ffe455adSEugenia Emantayev 
990ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
991ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
992ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
993ffe455adSEugenia Emantayev 	context = mailbox->buf;
994ffe455adSEugenia Emantayev 	context->base_qpn = cpu_to_be32(base_qpn);
995ffe455adSEugenia Emantayev 	context->n_mac = dev->caps.log_num_macs;
996ffe455adSEugenia Emantayev 	context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT |
997ffe455adSEugenia Emantayev 				       base_qpn);
998ffe455adSEugenia Emantayev 	context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT |
999ffe455adSEugenia Emantayev 				     base_qpn);
1000ffe455adSEugenia Emantayev 	context->intra_no_vlan = 0;
1001ffe455adSEugenia Emantayev 	context->no_vlan = MLX4_NO_VLAN_IDX;
1002ffe455adSEugenia Emantayev 	context->intra_vlan_miss = 0;
1003ffe455adSEugenia Emantayev 	context->vlan_miss = MLX4_VLAN_MISS_IDX;
1004ffe455adSEugenia Emantayev 
1005ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port;
1006ffe455adSEugenia Emantayev 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
1007ffe455adSEugenia Emantayev 		       MLX4_CMD_TIME_CLASS_B,  MLX4_CMD_WRAPPED);
1008ffe455adSEugenia Emantayev 
1009ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
1010ffe455adSEugenia Emantayev 	return err;
1011ffe455adSEugenia Emantayev }
1012ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc);
1013ffe455adSEugenia Emantayev 
1014e5395e92SAmir Vadai int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc)
1015e5395e92SAmir Vadai {
1016e5395e92SAmir Vadai 	struct mlx4_cmd_mailbox *mailbox;
1017e5395e92SAmir Vadai 	struct mlx4_set_port_prio2tc_context *context;
1018e5395e92SAmir Vadai 	int err;
1019e5395e92SAmir Vadai 	u32 in_mod;
1020e5395e92SAmir Vadai 	int i;
1021e5395e92SAmir Vadai 
1022e5395e92SAmir Vadai 	mailbox = mlx4_alloc_cmd_mailbox(dev);
1023e5395e92SAmir Vadai 	if (IS_ERR(mailbox))
1024e5395e92SAmir Vadai 		return PTR_ERR(mailbox);
1025e5395e92SAmir Vadai 	context = mailbox->buf;
1026e5395e92SAmir Vadai 	for (i = 0; i < MLX4_NUM_UP; i += 2)
1027e5395e92SAmir Vadai 		context->prio2tc[i >> 1] = prio2tc[i] << 4 | prio2tc[i + 1];
1028e5395e92SAmir Vadai 
1029e5395e92SAmir Vadai 	in_mod = MLX4_SET_PORT_PRIO2TC << 8 | port;
1030e5395e92SAmir Vadai 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
1031e5395e92SAmir Vadai 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
1032e5395e92SAmir Vadai 
1033e5395e92SAmir Vadai 	mlx4_free_cmd_mailbox(dev, mailbox);
1034e5395e92SAmir Vadai 	return err;
1035e5395e92SAmir Vadai }
1036e5395e92SAmir Vadai EXPORT_SYMBOL(mlx4_SET_PORT_PRIO2TC);
1037e5395e92SAmir Vadai 
1038e5395e92SAmir Vadai int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw,
1039e5395e92SAmir Vadai 		u8 *pg, u16 *ratelimit)
1040e5395e92SAmir Vadai {
1041e5395e92SAmir Vadai 	struct mlx4_cmd_mailbox *mailbox;
1042e5395e92SAmir Vadai 	struct mlx4_set_port_scheduler_context *context;
1043e5395e92SAmir Vadai 	int err;
1044e5395e92SAmir Vadai 	u32 in_mod;
1045e5395e92SAmir Vadai 	int i;
1046e5395e92SAmir Vadai 
1047e5395e92SAmir Vadai 	mailbox = mlx4_alloc_cmd_mailbox(dev);
1048e5395e92SAmir Vadai 	if (IS_ERR(mailbox))
1049e5395e92SAmir Vadai 		return PTR_ERR(mailbox);
1050e5395e92SAmir Vadai 	context = mailbox->buf;
1051e5395e92SAmir Vadai 
1052e5395e92SAmir Vadai 	for (i = 0; i < MLX4_NUM_TC; i++) {
1053e5395e92SAmir Vadai 		struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i];
1054523ece88SEugenia Emantayev 		u16 r;
1055523ece88SEugenia Emantayev 
1056523ece88SEugenia Emantayev 		if (ratelimit && ratelimit[i]) {
1057523ece88SEugenia Emantayev 			if (ratelimit[i] <= MLX4_MAX_100M_UNITS_VAL) {
1058523ece88SEugenia Emantayev 				r = ratelimit[i];
1059523ece88SEugenia Emantayev 				tc->max_bw_units =
1060523ece88SEugenia Emantayev 					htons(MLX4_RATELIMIT_100M_UNITS);
1061523ece88SEugenia Emantayev 			} else {
1062523ece88SEugenia Emantayev 				r = ratelimit[i]/10;
1063523ece88SEugenia Emantayev 				tc->max_bw_units =
1064523ece88SEugenia Emantayev 					htons(MLX4_RATELIMIT_1G_UNITS);
1065523ece88SEugenia Emantayev 			}
1066523ece88SEugenia Emantayev 			tc->max_bw_value = htons(r);
1067523ece88SEugenia Emantayev 		} else {
1068523ece88SEugenia Emantayev 			tc->max_bw_value = htons(MLX4_RATELIMIT_DEFAULT);
1069523ece88SEugenia Emantayev 			tc->max_bw_units = htons(MLX4_RATELIMIT_1G_UNITS);
1070523ece88SEugenia Emantayev 		}
1071e5395e92SAmir Vadai 
1072e5395e92SAmir Vadai 		tc->pg = htons(pg[i]);
1073e5395e92SAmir Vadai 		tc->bw_precentage = htons(tc_tx_bw[i]);
1074e5395e92SAmir Vadai 	}
1075e5395e92SAmir Vadai 
1076e5395e92SAmir Vadai 	in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port;
1077e5395e92SAmir Vadai 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
1078e5395e92SAmir Vadai 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
1079e5395e92SAmir Vadai 
1080e5395e92SAmir Vadai 	mlx4_free_cmd_mailbox(dev, mailbox);
1081e5395e92SAmir Vadai 	return err;
1082e5395e92SAmir Vadai }
1083e5395e92SAmir Vadai EXPORT_SYMBOL(mlx4_SET_PORT_SCHEDULER);
1084e5395e92SAmir Vadai 
10857ffdf726SOr Gerlitz enum {
10867ffdf726SOr Gerlitz 	VXLAN_ENABLE_MODIFY	= 1 << 7,
10877ffdf726SOr Gerlitz 	VXLAN_STEERING_MODIFY	= 1 << 6,
10887ffdf726SOr Gerlitz 
10897ffdf726SOr Gerlitz 	VXLAN_ENABLE		= 1 << 7,
10907ffdf726SOr Gerlitz };
10917ffdf726SOr Gerlitz 
10927ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context {
10937ffdf726SOr Gerlitz 	u32	reserved1;
10947ffdf726SOr Gerlitz 	u8	modify_flags;
10957ffdf726SOr Gerlitz 	u8	reserved2;
10967ffdf726SOr Gerlitz 	u8	enable_flags;
10977ffdf726SOr Gerlitz 	u8	steering;
10987ffdf726SOr Gerlitz };
10997ffdf726SOr Gerlitz 
11001b136de1SOr Gerlitz int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable)
11017ffdf726SOr Gerlitz {
11027ffdf726SOr Gerlitz 	int err;
11037ffdf726SOr Gerlitz 	u32 in_mod;
11047ffdf726SOr Gerlitz 	struct mlx4_cmd_mailbox *mailbox;
11057ffdf726SOr Gerlitz 	struct mlx4_set_port_vxlan_context  *context;
11067ffdf726SOr Gerlitz 
11077ffdf726SOr Gerlitz 	mailbox = mlx4_alloc_cmd_mailbox(dev);
11087ffdf726SOr Gerlitz 	if (IS_ERR(mailbox))
11097ffdf726SOr Gerlitz 		return PTR_ERR(mailbox);
11107ffdf726SOr Gerlitz 	context = mailbox->buf;
11117ffdf726SOr Gerlitz 	memset(context, 0, sizeof(*context));
11127ffdf726SOr Gerlitz 
11137ffdf726SOr Gerlitz 	context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY;
11141b136de1SOr Gerlitz 	if (enable)
11157ffdf726SOr Gerlitz 		context->enable_flags = VXLAN_ENABLE;
11167ffdf726SOr Gerlitz 	context->steering  = steering;
11177ffdf726SOr Gerlitz 
11187ffdf726SOr Gerlitz 	in_mod = MLX4_SET_PORT_VXLAN << 8 | port;
11197ffdf726SOr Gerlitz 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
11207ffdf726SOr Gerlitz 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
11217ffdf726SOr Gerlitz 
11227ffdf726SOr Gerlitz 	mlx4_free_cmd_mailbox(dev, mailbox);
11237ffdf726SOr Gerlitz 	return err;
11247ffdf726SOr Gerlitz }
11257ffdf726SOr Gerlitz EXPORT_SYMBOL(mlx4_SET_PORT_VXLAN);
11267ffdf726SOr Gerlitz 
1127ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1128ffe455adSEugenia Emantayev 				struct mlx4_vhcr *vhcr,
1129ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *inbox,
1130ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *outbox,
1131ffe455adSEugenia Emantayev 				struct mlx4_cmd_info *cmd)
1132ffe455adSEugenia Emantayev {
1133ffe455adSEugenia Emantayev 	int err = 0;
1134ffe455adSEugenia Emantayev 
1135ffe455adSEugenia Emantayev 	return err;
1136ffe455adSEugenia Emantayev }
1137ffe455adSEugenia Emantayev 
1138ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port,
1139ffe455adSEugenia Emantayev 			u64 mac, u64 clear, u8 mode)
1140ffe455adSEugenia Emantayev {
1141ffe455adSEugenia Emantayev 	return mlx4_cmd(dev, (mac | (clear << 63)), port, mode,
1142ffe455adSEugenia Emantayev 			MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B,
1143ffe455adSEugenia Emantayev 			MLX4_CMD_WRAPPED);
1144ffe455adSEugenia Emantayev }
1145ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR);
1146ffe455adSEugenia Emantayev 
1147ffe455adSEugenia Emantayev int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1148ffe455adSEugenia Emantayev 			       struct mlx4_vhcr *vhcr,
1149ffe455adSEugenia Emantayev 			       struct mlx4_cmd_mailbox *inbox,
1150ffe455adSEugenia Emantayev 			       struct mlx4_cmd_mailbox *outbox,
1151ffe455adSEugenia Emantayev 			       struct mlx4_cmd_info *cmd)
1152ffe455adSEugenia Emantayev {
1153ffe455adSEugenia Emantayev 	int err = 0;
1154ffe455adSEugenia Emantayev 
1155ffe455adSEugenia Emantayev 	return err;
1156ffe455adSEugenia Emantayev }
1157ffe455adSEugenia Emantayev 
1158ffe455adSEugenia Emantayev int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave,
1159ffe455adSEugenia Emantayev 			       u32 in_mod, struct mlx4_cmd_mailbox *outbox)
1160ffe455adSEugenia Emantayev {
1161ffe455adSEugenia Emantayev 	return mlx4_cmd_box(dev, 0, outbox->dma, in_mod, 0,
1162ffe455adSEugenia Emantayev 			    MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B,
1163ffe455adSEugenia Emantayev 			    MLX4_CMD_NATIVE);
1164ffe455adSEugenia Emantayev }
1165ffe455adSEugenia Emantayev 
1166ffe455adSEugenia Emantayev int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave,
1167ffe455adSEugenia Emantayev 				struct mlx4_vhcr *vhcr,
1168ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *inbox,
1169ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *outbox,
1170ffe455adSEugenia Emantayev 				struct mlx4_cmd_info *cmd)
1171ffe455adSEugenia Emantayev {
117235fb9afbSEugenia Emantayev 	if (slave != dev->caps.function)
117335fb9afbSEugenia Emantayev 		return 0;
1174ffe455adSEugenia Emantayev 	return mlx4_common_dump_eth_stats(dev, slave,
1175ffe455adSEugenia Emantayev 					  vhcr->in_modifier, outbox);
1176ffe455adSEugenia Emantayev }
117793ece0c1SEugenia Emantayev 
117893ece0c1SEugenia Emantayev void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap)
117993ece0c1SEugenia Emantayev {
118093ece0c1SEugenia Emantayev 	if (!mlx4_is_mfunc(dev)) {
118193ece0c1SEugenia Emantayev 		*stats_bitmap = 0;
118293ece0c1SEugenia Emantayev 		return;
118393ece0c1SEugenia Emantayev 	}
118493ece0c1SEugenia Emantayev 
118593ece0c1SEugenia Emantayev 	*stats_bitmap = (MLX4_STATS_TRAFFIC_COUNTERS_MASK |
118693ece0c1SEugenia Emantayev 			 MLX4_STATS_TRAFFIC_DROPS_MASK |
118793ece0c1SEugenia Emantayev 			 MLX4_STATS_PORT_COUNTERS_MASK);
118893ece0c1SEugenia Emantayev 
118993ece0c1SEugenia Emantayev 	if (mlx4_is_master(dev))
119093ece0c1SEugenia Emantayev 		*stats_bitmap |= MLX4_STATS_ERROR_COUNTERS_MASK;
119193ece0c1SEugenia Emantayev }
119293ece0c1SEugenia Emantayev EXPORT_SYMBOL(mlx4_set_stats_bitmap);
11936ee51a4eSJack Morgenstein 
11949cd59352SJack Morgenstein int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
11959cd59352SJack Morgenstein 				 int *slave_id)
11966ee51a4eSJack Morgenstein {
11976ee51a4eSJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
11986ee51a4eSJack Morgenstein 	int i, found_ix = -1;
1199b6ffaeffSJack Morgenstein 	int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
1200449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
1201449fc488SMatan Barak 	unsigned num_vfs;
1202449fc488SMatan Barak 	int slave_gid;
12036ee51a4eSJack Morgenstein 
12046ee51a4eSJack Morgenstein 	if (!mlx4_is_mfunc(dev))
12056ee51a4eSJack Morgenstein 		return -EINVAL;
12066ee51a4eSJack Morgenstein 
1207449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1208449fc488SMatan Barak 	num_vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
1209449fc488SMatan Barak 
12106ee51a4eSJack Morgenstein 	for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
1211111c6094SJack Morgenstein 		if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid,
1212111c6094SJack Morgenstein 			    MLX4_ROCE_GID_ENTRY_SIZE)) {
12136ee51a4eSJack Morgenstein 			found_ix = i;
12146ee51a4eSJack Morgenstein 			break;
12156ee51a4eSJack Morgenstein 		}
12166ee51a4eSJack Morgenstein 	}
12176ee51a4eSJack Morgenstein 
1218b6ffaeffSJack Morgenstein 	if (found_ix >= 0) {
12190254bc82SMatan Barak 		/* Calculate a slave_gid which is the slave number in the gid
12200254bc82SMatan Barak 		 * table and not a globally unique slave number.
12210254bc82SMatan Barak 		 */
1222b6ffaeffSJack Morgenstein 		if (found_ix < MLX4_ROCE_PF_GIDS)
1223449fc488SMatan Barak 			slave_gid = 0;
1224449fc488SMatan Barak 		else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) *
1225449fc488SMatan Barak 			 (vf_gids / num_vfs + 1))
1226449fc488SMatan Barak 			slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) /
1227449fc488SMatan Barak 				     (vf_gids / num_vfs + 1)) + 1;
1228b6ffaeffSJack Morgenstein 		else
1229449fc488SMatan Barak 			slave_gid =
1230b6ffaeffSJack Morgenstein 			((found_ix - MLX4_ROCE_PF_GIDS -
1231449fc488SMatan Barak 			  ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) /
1232449fc488SMatan Barak 			 (vf_gids / num_vfs)) + vf_gids % num_vfs + 1;
1233449fc488SMatan Barak 
12340254bc82SMatan Barak 		/* Calculate the globally unique slave id */
1235449fc488SMatan Barak 		if (slave_gid) {
1236449fc488SMatan Barak 			struct mlx4_active_ports exclusive_ports;
1237449fc488SMatan Barak 			struct mlx4_active_ports actv_ports;
1238449fc488SMatan Barak 			struct mlx4_slaves_pport slaves_pport_actv;
1239449fc488SMatan Barak 			unsigned max_port_p_one;
12400254bc82SMatan Barak 			int num_vfs_before = 0;
12410254bc82SMatan Barak 			int candidate_slave_gid;
1242449fc488SMatan Barak 
12430254bc82SMatan Barak 			/* Calculate how many VFs are on the previous port, if exists */
1244449fc488SMatan Barak 			for (i = 1; i < port; i++) {
1245449fc488SMatan Barak 				bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
12460254bc82SMatan Barak 				set_bit(i - 1, exclusive_ports.ports);
1247449fc488SMatan Barak 				slaves_pport_actv =
1248449fc488SMatan Barak 					mlx4_phys_to_slaves_pport_actv(
1249449fc488SMatan Barak 							dev, &exclusive_ports);
12500254bc82SMatan Barak 				num_vfs_before += bitmap_weight(
1251449fc488SMatan Barak 						slaves_pport_actv.slaves,
1252449fc488SMatan Barak 						dev->num_vfs + 1);
1253449fc488SMatan Barak 			}
1254449fc488SMatan Barak 
12550254bc82SMatan Barak 			/* candidate_slave_gid isn't necessarily the correct slave, but
12560254bc82SMatan Barak 			 * it has the same number of ports and is assigned to the same
12570254bc82SMatan Barak 			 * ports as the real slave we're looking for. On dual port VF,
12580254bc82SMatan Barak 			 * slave_gid = [single port VFs on port <port>] +
12590254bc82SMatan Barak 			 * [offset of the current slave from the first dual port VF] +
12600254bc82SMatan Barak 			 * 1 (for the PF).
12610254bc82SMatan Barak 			 */
12620254bc82SMatan Barak 			candidate_slave_gid = slave_gid + num_vfs_before;
12630254bc82SMatan Barak 
12640254bc82SMatan Barak 			actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid);
1265449fc488SMatan Barak 			max_port_p_one = find_first_bit(
1266449fc488SMatan Barak 				actv_ports.ports, dev->caps.num_ports) +
1267449fc488SMatan Barak 				bitmap_weight(actv_ports.ports,
1268449fc488SMatan Barak 					      dev->caps.num_ports) + 1;
1269449fc488SMatan Barak 
12700254bc82SMatan Barak 			/* Calculate the real slave number */
1271449fc488SMatan Barak 			for (i = 1; i < max_port_p_one; i++) {
1272449fc488SMatan Barak 				if (i == port)
1273449fc488SMatan Barak 					continue;
1274449fc488SMatan Barak 				bitmap_zero(exclusive_ports.ports,
1275449fc488SMatan Barak 					    dev->caps.num_ports);
1276449fc488SMatan Barak 				set_bit(i - 1, exclusive_ports.ports);
1277449fc488SMatan Barak 				slaves_pport_actv =
1278449fc488SMatan Barak 					mlx4_phys_to_slaves_pport_actv(
1279449fc488SMatan Barak 						dev, &exclusive_ports);
1280449fc488SMatan Barak 				slave_gid += bitmap_weight(
1281449fc488SMatan Barak 						slaves_pport_actv.slaves,
1282449fc488SMatan Barak 						dev->num_vfs + 1);
1283449fc488SMatan Barak 			}
1284449fc488SMatan Barak 		}
1285449fc488SMatan Barak 		*slave_id = slave_gid;
1286b6ffaeffSJack Morgenstein 	}
12876ee51a4eSJack Morgenstein 
12886ee51a4eSJack Morgenstein 	return (found_ix >= 0) ? 0 : -EINVAL;
12896ee51a4eSJack Morgenstein }
12906ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid);
12916ee51a4eSJack Morgenstein 
12929cd59352SJack Morgenstein int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id,
12939cd59352SJack Morgenstein 				 u8 *gid)
12946ee51a4eSJack Morgenstein {
12956ee51a4eSJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
12966ee51a4eSJack Morgenstein 
12976ee51a4eSJack Morgenstein 	if (!mlx4_is_master(dev))
12986ee51a4eSJack Morgenstein 		return -EINVAL;
12996ee51a4eSJack Morgenstein 
1300111c6094SJack Morgenstein 	memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw,
1301111c6094SJack Morgenstein 	       MLX4_ROCE_GID_ENTRY_SIZE);
13026ee51a4eSJack Morgenstein 	return 0;
13036ee51a4eSJack Morgenstein }
13046ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
1305