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 
785a2cc190SJeff Kirsher static int validate_index(struct mlx4_dev *dev,
795a2cc190SJeff Kirsher 			  struct mlx4_mac_table *table, int index)
805a2cc190SJeff Kirsher {
815a2cc190SJeff Kirsher 	int err = 0;
825a2cc190SJeff Kirsher 
835a2cc190SJeff Kirsher 	if (index < 0 || index >= table->max || !table->entries[index]) {
845a2cc190SJeff Kirsher 		mlx4_warn(dev, "No valid Mac entry for the given index\n");
855a2cc190SJeff Kirsher 		err = -EINVAL;
865a2cc190SJeff Kirsher 	}
875a2cc190SJeff Kirsher 	return err;
885a2cc190SJeff Kirsher }
895a2cc190SJeff Kirsher 
905a2cc190SJeff Kirsher static int find_index(struct mlx4_dev *dev,
915a2cc190SJeff Kirsher 		      struct mlx4_mac_table *table, u64 mac)
925a2cc190SJeff Kirsher {
935a2cc190SJeff Kirsher 	int i;
94ffe455adSEugenia Emantayev 
955a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
96ffe455adSEugenia Emantayev 		if ((mac & MLX4_MAC_MASK) ==
97ffe455adSEugenia Emantayev 		    (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))
985a2cc190SJeff Kirsher 			return i;
995a2cc190SJeff Kirsher 	}
1005a2cc190SJeff Kirsher 	/* Mac not found */
1015a2cc190SJeff Kirsher 	return -EINVAL;
1025a2cc190SJeff Kirsher }
1035a2cc190SJeff Kirsher 
104ffe455adSEugenia Emantayev static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
105ffe455adSEugenia Emantayev 				   __be64 *entries)
106ffe455adSEugenia Emantayev {
107ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
108ffe455adSEugenia Emantayev 	u32 in_mod;
109ffe455adSEugenia Emantayev 	int err;
110ffe455adSEugenia Emantayev 
111ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
112ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
113ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
114ffe455adSEugenia Emantayev 
115ffe455adSEugenia Emantayev 	memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE);
116ffe455adSEugenia Emantayev 
117ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port;
118ffe455adSEugenia Emantayev 
119ffe455adSEugenia Emantayev 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
120ffe455adSEugenia Emantayev 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
121ffe455adSEugenia Emantayev 
122ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
123ffe455adSEugenia Emantayev 	return err;
124ffe455adSEugenia Emantayev }
125ffe455adSEugenia Emantayev 
126297e0dadSMoni Shoua int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx)
127297e0dadSMoni Shoua {
128297e0dadSMoni Shoua 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
129297e0dadSMoni Shoua 	struct mlx4_mac_table *table = &info->mac_table;
130297e0dadSMoni Shoua 	int i;
131297e0dadSMoni Shoua 
132297e0dadSMoni Shoua 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
133297e0dadSMoni Shoua 		if (!table->refs[i])
134297e0dadSMoni Shoua 			continue;
135297e0dadSMoni Shoua 
136297e0dadSMoni Shoua 		if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
137297e0dadSMoni Shoua 			*idx = i;
138297e0dadSMoni Shoua 			return 0;
139297e0dadSMoni Shoua 		}
140297e0dadSMoni Shoua 	}
141297e0dadSMoni Shoua 
142297e0dadSMoni Shoua 	return -ENOENT;
143297e0dadSMoni Shoua }
144297e0dadSMoni Shoua EXPORT_SYMBOL_GPL(mlx4_find_cached_mac);
145297e0dadSMoni Shoua 
146ffe455adSEugenia Emantayev int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
147ffe455adSEugenia Emantayev {
148ffe455adSEugenia Emantayev 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
149ffe455adSEugenia Emantayev 	struct mlx4_mac_table *table = &info->mac_table;
150ffe455adSEugenia Emantayev 	int i, err = 0;
151ffe455adSEugenia Emantayev 	int free = -1;
152ffe455adSEugenia Emantayev 
153ffe455adSEugenia Emantayev 	mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d\n",
154ffe455adSEugenia Emantayev 		 (unsigned long long) mac, port);
155ffe455adSEugenia Emantayev 
156ffe455adSEugenia Emantayev 	mutex_lock(&table->mutex);
157ffe455adSEugenia Emantayev 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
158ffe455adSEugenia Emantayev 		if (free < 0 && !table->entries[i]) {
159ffe455adSEugenia Emantayev 			free = i;
160ffe455adSEugenia Emantayev 			continue;
161ffe455adSEugenia Emantayev 		}
162ffe455adSEugenia Emantayev 
163ffe455adSEugenia Emantayev 		if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
1646ce71acdSRony Efraim 			/* MAC already registered, increment ref count */
1656ce71acdSRony Efraim 			err = i;
1666ce71acdSRony Efraim 			++table->refs[i];
167ffe455adSEugenia Emantayev 			goto out;
168ffe455adSEugenia Emantayev 		}
169ffe455adSEugenia Emantayev 	}
170ffe455adSEugenia Emantayev 
171ffe455adSEugenia Emantayev 	mlx4_dbg(dev, "Free MAC index is %d\n", free);
172ffe455adSEugenia Emantayev 
173ffe455adSEugenia Emantayev 	if (table->total == table->max) {
174ffe455adSEugenia Emantayev 		/* No free mac entries */
175ffe455adSEugenia Emantayev 		err = -ENOSPC;
176ffe455adSEugenia Emantayev 		goto out;
177ffe455adSEugenia Emantayev 	}
178ffe455adSEugenia Emantayev 
179ffe455adSEugenia Emantayev 	/* Register new MAC */
180ffe455adSEugenia Emantayev 	table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
181ffe455adSEugenia Emantayev 
182ffe455adSEugenia Emantayev 	err = mlx4_set_port_mac_table(dev, port, table->entries);
183ffe455adSEugenia Emantayev 	if (unlikely(err)) {
184ffe455adSEugenia Emantayev 		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
185ffe455adSEugenia Emantayev 			 (unsigned long long) mac);
186ffe455adSEugenia Emantayev 		table->entries[free] = 0;
187ffe455adSEugenia Emantayev 		goto out;
188ffe455adSEugenia Emantayev 	}
1896ce71acdSRony Efraim 	table->refs[free] = 1;
190ffe455adSEugenia Emantayev 	err = free;
191ffe455adSEugenia Emantayev 	++table->total;
192ffe455adSEugenia Emantayev out:
193ffe455adSEugenia Emantayev 	mutex_unlock(&table->mutex);
194ffe455adSEugenia Emantayev 	return err;
195ffe455adSEugenia Emantayev }
196ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_register_mac);
197ffe455adSEugenia Emantayev 
198ffe455adSEugenia Emantayev int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
199ffe455adSEugenia Emantayev {
200e7dbeba8SJack Morgenstein 	u64 out_param = 0;
201acddd5ddSJack Morgenstein 	int err = -EINVAL;
202ffe455adSEugenia Emantayev 
203ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
204acddd5ddSJack Morgenstein 		if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) {
205acddd5ddSJack Morgenstein 			err = mlx4_cmd_imm(dev, mac, &out_param,
206acddd5ddSJack Morgenstein 					   ((u32) port) << 8 | (u32) RES_MAC,
207acddd5ddSJack Morgenstein 					   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
208acddd5ddSJack Morgenstein 					   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
209acddd5ddSJack Morgenstein 		}
210acddd5ddSJack Morgenstein 		if (err && err == -EINVAL && mlx4_is_slave(dev)) {
211acddd5ddSJack Morgenstein 			/* retry using old REG_MAC format */
212ffe455adSEugenia Emantayev 			set_param_l(&out_param, port);
213ffe455adSEugenia Emantayev 			err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC,
214ffe455adSEugenia Emantayev 					   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
215ffe455adSEugenia Emantayev 					   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
216acddd5ddSJack Morgenstein 			if (!err)
217acddd5ddSJack Morgenstein 				dev->flags |= MLX4_FLAG_OLD_REG_MAC;
218acddd5ddSJack Morgenstein 		}
219ffe455adSEugenia Emantayev 		if (err)
220ffe455adSEugenia Emantayev 			return err;
221ffe455adSEugenia Emantayev 
222ffe455adSEugenia Emantayev 		return get_param_l(&out_param);
223ffe455adSEugenia Emantayev 	}
224ffe455adSEugenia Emantayev 	return __mlx4_register_mac(dev, port, mac);
225ffe455adSEugenia Emantayev }
226ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(mlx4_register_mac);
227ffe455adSEugenia Emantayev 
22816a10ffdSYan Burman int mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port)
22916a10ffdSYan Burman {
23016a10ffdSYan Burman 	return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
23116a10ffdSYan Burman 			(port - 1) * (1 << dev->caps.log_num_macs);
23216a10ffdSYan Burman }
23316a10ffdSYan Burman EXPORT_SYMBOL_GPL(mlx4_get_base_qpn);
234ffe455adSEugenia Emantayev 
235ffe455adSEugenia Emantayev void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
236ffe455adSEugenia Emantayev {
237ffe455adSEugenia Emantayev 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
238ffe455adSEugenia Emantayev 	struct mlx4_mac_table *table = &info->mac_table;
239ffe455adSEugenia Emantayev 	int index;
240ffe455adSEugenia Emantayev 
2415a2cc190SJeff Kirsher 	mutex_lock(&table->mutex);
2426ce71acdSRony Efraim 	index = find_index(dev, table, mac);
2435a2cc190SJeff Kirsher 
2445a2cc190SJeff Kirsher 	if (validate_index(dev, table, index))
2455a2cc190SJeff Kirsher 		goto out;
2466ce71acdSRony Efraim 	if (--table->refs[index]) {
2476ce71acdSRony Efraim 		mlx4_dbg(dev, "Have more references for index %d,"
2486ce71acdSRony Efraim 			 "no need to modify mac table\n", index);
2496ce71acdSRony Efraim 		goto out;
2506ce71acdSRony Efraim 	}
2515a2cc190SJeff Kirsher 
2525a2cc190SJeff Kirsher 	table->entries[index] = 0;
2535a2cc190SJeff Kirsher 	mlx4_set_port_mac_table(dev, port, table->entries);
2545a2cc190SJeff Kirsher 	--table->total;
2555a2cc190SJeff Kirsher out:
2565a2cc190SJeff Kirsher 	mutex_unlock(&table->mutex);
2575a2cc190SJeff Kirsher }
258ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_unregister_mac);
259ffe455adSEugenia Emantayev 
260ffe455adSEugenia Emantayev void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
261ffe455adSEugenia Emantayev {
262e7dbeba8SJack Morgenstein 	u64 out_param = 0;
263ffe455adSEugenia Emantayev 
264ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
265acddd5ddSJack Morgenstein 		if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) {
266acddd5ddSJack Morgenstein 			(void) mlx4_cmd_imm(dev, mac, &out_param,
267acddd5ddSJack Morgenstein 					    ((u32) port) << 8 | (u32) RES_MAC,
268acddd5ddSJack Morgenstein 					    RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
269acddd5ddSJack Morgenstein 					    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
270acddd5ddSJack Morgenstein 		} else {
271acddd5ddSJack Morgenstein 			/* use old unregister mac format */
272ffe455adSEugenia Emantayev 			set_param_l(&out_param, port);
273162344edSOr Gerlitz 			(void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC,
274ffe455adSEugenia Emantayev 					    RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
275ffe455adSEugenia Emantayev 					    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
276acddd5ddSJack Morgenstein 		}
277ffe455adSEugenia Emantayev 		return;
278ffe455adSEugenia Emantayev 	}
279ffe455adSEugenia Emantayev 	__mlx4_unregister_mac(dev, port, mac);
280ffe455adSEugenia Emantayev 	return;
281ffe455adSEugenia Emantayev }
2825a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
2835a2cc190SJeff Kirsher 
28416a10ffdSYan Burman int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
2855a2cc190SJeff Kirsher {
2865a2cc190SJeff Kirsher 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
2875a2cc190SJeff Kirsher 	struct mlx4_mac_table *table = &info->mac_table;
288ffe455adSEugenia Emantayev 	int index = qpn - info->base_qpn;
289ffe455adSEugenia Emantayev 	int err = 0;
2905a2cc190SJeff Kirsher 
291ffe455adSEugenia Emantayev 	/* CX1 doesn't support multi-functions */
2925a2cc190SJeff Kirsher 	mutex_lock(&table->mutex);
2935a2cc190SJeff Kirsher 
2945a2cc190SJeff Kirsher 	err = validate_index(dev, table, index);
2955a2cc190SJeff Kirsher 	if (err)
2965a2cc190SJeff Kirsher 		goto out;
2975a2cc190SJeff Kirsher 
2985a2cc190SJeff Kirsher 	table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
2995a2cc190SJeff Kirsher 
3005a2cc190SJeff Kirsher 	err = mlx4_set_port_mac_table(dev, port, table->entries);
3015a2cc190SJeff Kirsher 	if (unlikely(err)) {
302ffe455adSEugenia Emantayev 		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
303ffe455adSEugenia Emantayev 			 (unsigned long long) new_mac);
3045a2cc190SJeff Kirsher 		table->entries[index] = 0;
3055a2cc190SJeff Kirsher 	}
3065a2cc190SJeff Kirsher out:
3075a2cc190SJeff Kirsher 	mutex_unlock(&table->mutex);
3085a2cc190SJeff Kirsher 	return err;
3095a2cc190SJeff Kirsher }
31016a10ffdSYan Burman EXPORT_SYMBOL_GPL(__mlx4_replace_mac);
311ffe455adSEugenia Emantayev 
3125a2cc190SJeff Kirsher static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
3135a2cc190SJeff Kirsher 				    __be32 *entries)
3145a2cc190SJeff Kirsher {
3155a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *mailbox;
3165a2cc190SJeff Kirsher 	u32 in_mod;
3175a2cc190SJeff Kirsher 	int err;
3185a2cc190SJeff Kirsher 
3195a2cc190SJeff Kirsher 	mailbox = mlx4_alloc_cmd_mailbox(dev);
3205a2cc190SJeff Kirsher 	if (IS_ERR(mailbox))
3215a2cc190SJeff Kirsher 		return PTR_ERR(mailbox);
3225a2cc190SJeff Kirsher 
3235a2cc190SJeff Kirsher 	memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE);
3245a2cc190SJeff Kirsher 	in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port;
3255a2cc190SJeff Kirsher 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
326162226a1SJack Morgenstein 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
3275a2cc190SJeff Kirsher 
3285a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, mailbox);
3295a2cc190SJeff Kirsher 
3305a2cc190SJeff Kirsher 	return err;
3315a2cc190SJeff Kirsher }
3325a2cc190SJeff Kirsher 
3335a2cc190SJeff Kirsher int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
3345a2cc190SJeff Kirsher {
3355a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
3365a2cc190SJeff Kirsher 	int i;
3375a2cc190SJeff Kirsher 
3385a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) {
3395a2cc190SJeff Kirsher 		if (table->refs[i] &&
3405a2cc190SJeff Kirsher 		    (vid == (MLX4_VLAN_MASK &
3415a2cc190SJeff Kirsher 			      be32_to_cpu(table->entries[i])))) {
3425a2cc190SJeff Kirsher 			/* VLAN already registered, increase reference count */
3435a2cc190SJeff Kirsher 			*idx = i;
3445a2cc190SJeff Kirsher 			return 0;
3455a2cc190SJeff Kirsher 		}
3465a2cc190SJeff Kirsher 	}
3475a2cc190SJeff Kirsher 
3485a2cc190SJeff Kirsher 	return -ENOENT;
3495a2cc190SJeff Kirsher }
3505a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
3515a2cc190SJeff Kirsher 
3523f7fb021SRony Efraim int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
353ffe455adSEugenia Emantayev 				int *index)
3545a2cc190SJeff Kirsher {
3555a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
3565a2cc190SJeff Kirsher 	int i, err = 0;
3575a2cc190SJeff Kirsher 	int free = -1;
3585a2cc190SJeff Kirsher 
3595a2cc190SJeff Kirsher 	mutex_lock(&table->mutex);
360e72ebf5aSYevgeny Petrilin 
361e72ebf5aSYevgeny Petrilin 	if (table->total == table->max) {
362e72ebf5aSYevgeny Petrilin 		/* No free vlan entries */
363e72ebf5aSYevgeny Petrilin 		err = -ENOSPC;
364e72ebf5aSYevgeny Petrilin 		goto out;
365e72ebf5aSYevgeny Petrilin 	}
366e72ebf5aSYevgeny Petrilin 
3675a2cc190SJeff Kirsher 	for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
3685a2cc190SJeff Kirsher 		if (free < 0 && (table->refs[i] == 0)) {
3695a2cc190SJeff Kirsher 			free = i;
3705a2cc190SJeff Kirsher 			continue;
3715a2cc190SJeff Kirsher 		}
3725a2cc190SJeff Kirsher 
3735a2cc190SJeff Kirsher 		if (table->refs[i] &&
3745a2cc190SJeff Kirsher 		    (vlan == (MLX4_VLAN_MASK &
3755a2cc190SJeff Kirsher 			      be32_to_cpu(table->entries[i])))) {
3765a2cc190SJeff Kirsher 			/* Vlan already registered, increase references count */
3775a2cc190SJeff Kirsher 			*index = i;
3785a2cc190SJeff Kirsher 			++table->refs[i];
3795a2cc190SJeff Kirsher 			goto out;
3805a2cc190SJeff Kirsher 		}
3815a2cc190SJeff Kirsher 	}
3825a2cc190SJeff Kirsher 
3835a2cc190SJeff Kirsher 	if (free < 0) {
3845a2cc190SJeff Kirsher 		err = -ENOMEM;
3855a2cc190SJeff Kirsher 		goto out;
3865a2cc190SJeff Kirsher 	}
3875a2cc190SJeff Kirsher 
388ffe455adSEugenia Emantayev 	/* Register new VLAN */
3895a2cc190SJeff Kirsher 	table->refs[free] = 1;
3905a2cc190SJeff Kirsher 	table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
3915a2cc190SJeff Kirsher 
3925a2cc190SJeff Kirsher 	err = mlx4_set_port_vlan_table(dev, port, table->entries);
3935a2cc190SJeff Kirsher 	if (unlikely(err)) {
3945a2cc190SJeff Kirsher 		mlx4_warn(dev, "Failed adding vlan: %u\n", vlan);
3955a2cc190SJeff Kirsher 		table->refs[free] = 0;
3965a2cc190SJeff Kirsher 		table->entries[free] = 0;
3975a2cc190SJeff Kirsher 		goto out;
3985a2cc190SJeff Kirsher 	}
3995a2cc190SJeff Kirsher 
4005a2cc190SJeff Kirsher 	*index = free;
4015a2cc190SJeff Kirsher 	++table->total;
4025a2cc190SJeff Kirsher out:
4035a2cc190SJeff Kirsher 	mutex_unlock(&table->mutex);
4045a2cc190SJeff Kirsher 	return err;
4055a2cc190SJeff Kirsher }
406ffe455adSEugenia Emantayev 
407ffe455adSEugenia Emantayev int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
408ffe455adSEugenia Emantayev {
409e7dbeba8SJack Morgenstein 	u64 out_param = 0;
410ffe455adSEugenia Emantayev 	int err;
411ffe455adSEugenia Emantayev 
412162226a1SJack Morgenstein 	if (vlan > 4095)
413162226a1SJack Morgenstein 		return -EINVAL;
414162226a1SJack Morgenstein 
415ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
416acddd5ddSJack Morgenstein 		err = mlx4_cmd_imm(dev, vlan, &out_param,
417acddd5ddSJack Morgenstein 				   ((u32) port) << 8 | (u32) RES_VLAN,
418ffe455adSEugenia Emantayev 				   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
419ffe455adSEugenia Emantayev 				   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
420ffe455adSEugenia Emantayev 		if (!err)
421ffe455adSEugenia Emantayev 			*index = get_param_l(&out_param);
422ffe455adSEugenia Emantayev 
423ffe455adSEugenia Emantayev 		return err;
424ffe455adSEugenia Emantayev 	}
425ffe455adSEugenia Emantayev 	return __mlx4_register_vlan(dev, port, vlan, index);
426ffe455adSEugenia Emantayev }
4275a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_register_vlan);
4285a2cc190SJeff Kirsher 
4292009d005SJack Morgenstein void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
4305a2cc190SJeff Kirsher {
4315a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
4322009d005SJack Morgenstein 	int index;
4332009d005SJack Morgenstein 
4342009d005SJack Morgenstein 	mutex_lock(&table->mutex);
4352009d005SJack Morgenstein 	if (mlx4_find_cached_vlan(dev, port, vlan, &index)) {
4362009d005SJack Morgenstein 		mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan);
4372009d005SJack Morgenstein 		goto out;
4382009d005SJack Morgenstein 	}
4395a2cc190SJeff Kirsher 
4405a2cc190SJeff Kirsher 	if (index < MLX4_VLAN_REGULAR) {
4415a2cc190SJeff Kirsher 		mlx4_warn(dev, "Trying to free special vlan index %d\n", index);
4425a2cc190SJeff Kirsher 		goto out;
4435a2cc190SJeff Kirsher 	}
4442009d005SJack Morgenstein 
4455a2cc190SJeff Kirsher 	if (--table->refs[index]) {
4462009d005SJack Morgenstein 		mlx4_dbg(dev, "Have %d more references for index %d,"
4472009d005SJack Morgenstein 			 "no need to modify vlan table\n", table->refs[index],
4482009d005SJack Morgenstein 			 index);
4495a2cc190SJeff Kirsher 		goto out;
4505a2cc190SJeff Kirsher 	}
4515a2cc190SJeff Kirsher 	table->entries[index] = 0;
4525a2cc190SJeff Kirsher 	mlx4_set_port_vlan_table(dev, port, table->entries);
4535a2cc190SJeff Kirsher 	--table->total;
4545a2cc190SJeff Kirsher out:
4555a2cc190SJeff Kirsher 	mutex_unlock(&table->mutex);
4565a2cc190SJeff Kirsher }
457ffe455adSEugenia Emantayev 
4582009d005SJack Morgenstein void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
459ffe455adSEugenia Emantayev {
460162226a1SJack Morgenstein 	u64 out_param = 0;
461ffe455adSEugenia Emantayev 
462ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
4632009d005SJack Morgenstein 		(void) mlx4_cmd_imm(dev, vlan, &out_param,
464acddd5ddSJack Morgenstein 				    ((u32) port) << 8 | (u32) RES_VLAN,
465162226a1SJack Morgenstein 				    RES_OP_RESERVE_AND_MAP,
466ffe455adSEugenia Emantayev 				    MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A,
467ffe455adSEugenia Emantayev 				    MLX4_CMD_WRAPPED);
468ffe455adSEugenia Emantayev 		return;
469ffe455adSEugenia Emantayev 	}
4702009d005SJack Morgenstein 	__mlx4_unregister_vlan(dev, port, vlan);
471ffe455adSEugenia Emantayev }
4725a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_vlan);
4735a2cc190SJeff Kirsher 
4745a2cc190SJeff Kirsher int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
4755a2cc190SJeff Kirsher {
4765a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
4775a2cc190SJeff Kirsher 	u8 *inbuf, *outbuf;
4785a2cc190SJeff Kirsher 	int err;
4795a2cc190SJeff Kirsher 
4805a2cc190SJeff Kirsher 	inmailbox = mlx4_alloc_cmd_mailbox(dev);
4815a2cc190SJeff Kirsher 	if (IS_ERR(inmailbox))
4825a2cc190SJeff Kirsher 		return PTR_ERR(inmailbox);
4835a2cc190SJeff Kirsher 
4845a2cc190SJeff Kirsher 	outmailbox = mlx4_alloc_cmd_mailbox(dev);
4855a2cc190SJeff Kirsher 	if (IS_ERR(outmailbox)) {
4865a2cc190SJeff Kirsher 		mlx4_free_cmd_mailbox(dev, inmailbox);
4875a2cc190SJeff Kirsher 		return PTR_ERR(outmailbox);
4885a2cc190SJeff Kirsher 	}
4895a2cc190SJeff Kirsher 
4905a2cc190SJeff Kirsher 	inbuf = inmailbox->buf;
4915a2cc190SJeff Kirsher 	outbuf = outmailbox->buf;
4925a2cc190SJeff Kirsher 	inbuf[0] = 1;
4935a2cc190SJeff Kirsher 	inbuf[1] = 1;
4945a2cc190SJeff Kirsher 	inbuf[2] = 1;
4955a2cc190SJeff Kirsher 	inbuf[3] = 1;
4965a2cc190SJeff Kirsher 	*(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015);
4975a2cc190SJeff Kirsher 	*(__be32 *) (&inbuf[20]) = cpu_to_be32(port);
4985a2cc190SJeff Kirsher 
4995a2cc190SJeff Kirsher 	err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3,
500f9baff50SJack Morgenstein 			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
501f9baff50SJack Morgenstein 			   MLX4_CMD_NATIVE);
5025a2cc190SJeff Kirsher 	if (!err)
5035a2cc190SJeff Kirsher 		*caps = *(__be32 *) (outbuf + 84);
5045a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, inmailbox);
5055a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, outmailbox);
5065a2cc190SJeff Kirsher 	return err;
5075a2cc190SJeff Kirsher }
5089cd59352SJack Morgenstein static struct mlx4_roce_gid_entry zgid_entry;
5095a2cc190SJeff Kirsher 
510449fc488SMatan Barak int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port)
511b6ffaeffSJack Morgenstein {
512449fc488SMatan Barak 	int vfs;
513449fc488SMatan Barak 	int slave_gid = slave;
514449fc488SMatan Barak 	unsigned i;
515449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
516449fc488SMatan Barak 	struct mlx4_active_ports actv_ports;
517449fc488SMatan Barak 	unsigned max_port_p_one;
518449fc488SMatan Barak 
519b6ffaeffSJack Morgenstein 	if (slave == 0)
520b6ffaeffSJack Morgenstein 		return MLX4_ROCE_PF_GIDS;
521449fc488SMatan Barak 
522449fc488SMatan Barak 	/* Slave is a VF */
523449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
524449fc488SMatan Barak 	actv_ports = mlx4_get_active_ports(dev, slave);
525449fc488SMatan Barak 	max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
526449fc488SMatan Barak 		bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
527449fc488SMatan Barak 
528449fc488SMatan Barak 	for (i = 1; i < max_port_p_one; i++) {
529449fc488SMatan Barak 		struct mlx4_active_ports exclusive_ports;
530449fc488SMatan Barak 		struct mlx4_slaves_pport slaves_pport_actv;
531449fc488SMatan Barak 		bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
532449fc488SMatan Barak 		set_bit(i - 1, exclusive_ports.ports);
533449fc488SMatan Barak 		if (i == port)
534449fc488SMatan Barak 			continue;
535449fc488SMatan Barak 		slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
536449fc488SMatan Barak 				    dev, &exclusive_ports);
537449fc488SMatan Barak 		slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
538449fc488SMatan Barak 					   dev->num_vfs + 1);
539449fc488SMatan Barak 	}
540449fc488SMatan Barak 	vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
541449fc488SMatan Barak 	if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs))
542449fc488SMatan Barak 		return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1;
543449fc488SMatan Barak 	return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs;
544b6ffaeffSJack Morgenstein }
545b6ffaeffSJack Morgenstein 
546449fc488SMatan Barak int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port)
547b6ffaeffSJack Morgenstein {
548b6ffaeffSJack Morgenstein 	int gids;
549449fc488SMatan Barak 	unsigned i;
550449fc488SMatan Barak 	int slave_gid = slave;
551b6ffaeffSJack Morgenstein 	int vfs;
552b6ffaeffSJack Morgenstein 
553449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
554449fc488SMatan Barak 	struct mlx4_active_ports actv_ports;
555449fc488SMatan Barak 	unsigned max_port_p_one;
556b6ffaeffSJack Morgenstein 
557b6ffaeffSJack Morgenstein 	if (slave == 0)
558b6ffaeffSJack Morgenstein 		return 0;
559b6ffaeffSJack Morgenstein 
560449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
561449fc488SMatan Barak 	actv_ports = mlx4_get_active_ports(dev, slave);
562449fc488SMatan Barak 	max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
563449fc488SMatan Barak 		bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
564449fc488SMatan Barak 
565449fc488SMatan Barak 	for (i = 1; i < max_port_p_one; i++) {
566449fc488SMatan Barak 		struct mlx4_active_ports exclusive_ports;
567449fc488SMatan Barak 		struct mlx4_slaves_pport slaves_pport_actv;
568449fc488SMatan Barak 		bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
569449fc488SMatan Barak 		set_bit(i - 1, exclusive_ports.ports);
570449fc488SMatan Barak 		if (i == port)
571449fc488SMatan Barak 			continue;
572449fc488SMatan Barak 		slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
573449fc488SMatan Barak 				    dev, &exclusive_ports);
574449fc488SMatan Barak 		slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
575449fc488SMatan Barak 					   dev->num_vfs + 1);
576b6ffaeffSJack Morgenstein 	}
577449fc488SMatan Barak 	gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
578449fc488SMatan Barak 	vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
579449fc488SMatan Barak 	if (slave_gid <= gids % vfs)
580449fc488SMatan Barak 		return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1);
581449fc488SMatan Barak 
582449fc488SMatan Barak 	return MLX4_ROCE_PF_GIDS + (gids % vfs) +
583449fc488SMatan Barak 		((gids / vfs) * (slave_gid - 1));
584449fc488SMatan Barak }
585449fc488SMatan Barak EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix);
586b6ffaeffSJack Morgenstein 
587ffe455adSEugenia Emantayev static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
588ffe455adSEugenia Emantayev 				u8 op_mod, struct mlx4_cmd_mailbox *inbox)
589ffe455adSEugenia Emantayev {
590ffe455adSEugenia Emantayev 	struct mlx4_priv *priv = mlx4_priv(dev);
591ffe455adSEugenia Emantayev 	struct mlx4_port_info *port_info;
592ffe455adSEugenia Emantayev 	struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
593ffe455adSEugenia Emantayev 	struct mlx4_slave_state *slave_st = &master->slave_state[slave];
594ffe455adSEugenia Emantayev 	struct mlx4_set_port_rqp_calc_context *qpn_context;
595ffe455adSEugenia Emantayev 	struct mlx4_set_port_general_context *gen_context;
596b6ffaeffSJack Morgenstein 	struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1;
597ffe455adSEugenia Emantayev 	int reset_qkey_viols;
598ffe455adSEugenia Emantayev 	int port;
599ffe455adSEugenia Emantayev 	int is_eth;
600b6ffaeffSJack Morgenstein 	int num_gids;
601b6ffaeffSJack Morgenstein 	int base;
602ffe455adSEugenia Emantayev 	u32 in_modifier;
603ffe455adSEugenia Emantayev 	u32 promisc;
604ffe455adSEugenia Emantayev 	u16 mtu, prev_mtu;
605ffe455adSEugenia Emantayev 	int err;
606b6ffaeffSJack Morgenstein 	int i, j;
607b6ffaeffSJack Morgenstein 	int offset;
608ffe455adSEugenia Emantayev 	__be32 agg_cap_mask;
609ffe455adSEugenia Emantayev 	__be32 slave_cap_mask;
610ffe455adSEugenia Emantayev 	__be32 new_cap_mask;
611ffe455adSEugenia Emantayev 
612ffe455adSEugenia Emantayev 	port = in_mod & 0xff;
613ffe455adSEugenia Emantayev 	in_modifier = in_mod >> 8;
614ffe455adSEugenia Emantayev 	is_eth = op_mod;
615ffe455adSEugenia Emantayev 	port_info = &priv->port[port];
616ffe455adSEugenia Emantayev 
617ffe455adSEugenia Emantayev 	/* Slaves cannot perform SET_PORT operations except changing MTU */
618ffe455adSEugenia Emantayev 	if (is_eth) {
619ffe455adSEugenia Emantayev 		if (slave != dev->caps.function &&
6209cd59352SJack Morgenstein 		    in_modifier != MLX4_SET_PORT_GENERAL &&
6219cd59352SJack Morgenstein 		    in_modifier != MLX4_SET_PORT_GID_TABLE) {
622ffe455adSEugenia Emantayev 			mlx4_warn(dev, "denying SET_PORT for slave:%d\n",
623ffe455adSEugenia Emantayev 					slave);
624ffe455adSEugenia Emantayev 			return -EINVAL;
625ffe455adSEugenia Emantayev 		}
626ffe455adSEugenia Emantayev 		switch (in_modifier) {
627ffe455adSEugenia Emantayev 		case MLX4_SET_PORT_RQP_CALC:
628ffe455adSEugenia Emantayev 			qpn_context = inbox->buf;
629ffe455adSEugenia Emantayev 			qpn_context->base_qpn =
630ffe455adSEugenia Emantayev 				cpu_to_be32(port_info->base_qpn);
631ffe455adSEugenia Emantayev 			qpn_context->n_mac = 0x7;
632ffe455adSEugenia Emantayev 			promisc = be32_to_cpu(qpn_context->promisc) >>
633ffe455adSEugenia Emantayev 				SET_PORT_PROMISC_SHIFT;
634ffe455adSEugenia Emantayev 			qpn_context->promisc = cpu_to_be32(
635ffe455adSEugenia Emantayev 				promisc << SET_PORT_PROMISC_SHIFT |
636ffe455adSEugenia Emantayev 				port_info->base_qpn);
637ffe455adSEugenia Emantayev 			promisc = be32_to_cpu(qpn_context->mcast) >>
638ffe455adSEugenia Emantayev 				SET_PORT_MC_PROMISC_SHIFT;
639ffe455adSEugenia Emantayev 			qpn_context->mcast = cpu_to_be32(
640ffe455adSEugenia Emantayev 				promisc << SET_PORT_MC_PROMISC_SHIFT |
641ffe455adSEugenia Emantayev 				port_info->base_qpn);
642ffe455adSEugenia Emantayev 			break;
643ffe455adSEugenia Emantayev 		case MLX4_SET_PORT_GENERAL:
644ffe455adSEugenia Emantayev 			gen_context = inbox->buf;
645ffe455adSEugenia Emantayev 			/* Mtu is configured as the max MTU among all the
646ffe455adSEugenia Emantayev 			 * the functions on the port. */
647ffe455adSEugenia Emantayev 			mtu = be16_to_cpu(gen_context->mtu);
648c59fec20SEugenia Emantayev 			mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] +
649c59fec20SEugenia Emantayev 				    ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
650ffe455adSEugenia Emantayev 			prev_mtu = slave_st->mtu[port];
651ffe455adSEugenia Emantayev 			slave_st->mtu[port] = mtu;
652ffe455adSEugenia Emantayev 			if (mtu > master->max_mtu[port])
653ffe455adSEugenia Emantayev 				master->max_mtu[port] = mtu;
654ffe455adSEugenia Emantayev 			if (mtu < prev_mtu && prev_mtu ==
655ffe455adSEugenia Emantayev 						master->max_mtu[port]) {
656ffe455adSEugenia Emantayev 				slave_st->mtu[port] = mtu;
657ffe455adSEugenia Emantayev 				master->max_mtu[port] = mtu;
658ffe455adSEugenia Emantayev 				for (i = 0; i < dev->num_slaves; i++) {
659ffe455adSEugenia Emantayev 					master->max_mtu[port] =
660ffe455adSEugenia Emantayev 					max(master->max_mtu[port],
661ffe455adSEugenia Emantayev 					    master->slave_state[i].mtu[port]);
662ffe455adSEugenia Emantayev 				}
663ffe455adSEugenia Emantayev 			}
664ffe455adSEugenia Emantayev 
665ffe455adSEugenia Emantayev 			gen_context->mtu = cpu_to_be16(master->max_mtu[port]);
666ffe455adSEugenia Emantayev 			break;
6679cd59352SJack Morgenstein 		case MLX4_SET_PORT_GID_TABLE:
668b6ffaeffSJack Morgenstein 			/* change to MULTIPLE entries: number of guest's gids
669b6ffaeffSJack Morgenstein 			 * need a FOR-loop here over number of gids the guest has.
670b6ffaeffSJack Morgenstein 			 * 1. Check no duplicates in gids passed by slave
671b6ffaeffSJack Morgenstein 			 */
672449fc488SMatan Barak 			num_gids = mlx4_get_slave_num_gids(dev, slave, port);
673449fc488SMatan Barak 			base = mlx4_get_base_gid_ix(dev, slave, port);
674b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
675b6ffaeffSJack Morgenstein 			for (i = 0; i < num_gids; gid_entry_mbox++, i++) {
676b6ffaeffSJack Morgenstein 				if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
677b6ffaeffSJack Morgenstein 					    sizeof(zgid_entry)))
678b6ffaeffSJack Morgenstein 					continue;
679b6ffaeffSJack Morgenstein 				gid_entry_mb1 = gid_entry_mbox + 1;
680b6ffaeffSJack Morgenstein 				for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) {
681b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mb1->raw,
682b6ffaeffSJack Morgenstein 						    zgid_entry.raw, sizeof(zgid_entry)))
683b6ffaeffSJack Morgenstein 						continue;
684b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw,
685b6ffaeffSJack Morgenstein 						    sizeof(gid_entry_mbox->raw))) {
686b6ffaeffSJack Morgenstein 						/* found duplicate */
687b6ffaeffSJack Morgenstein 						return -EINVAL;
688b6ffaeffSJack Morgenstein 					}
689b6ffaeffSJack Morgenstein 				}
690b6ffaeffSJack Morgenstein 			}
691b6ffaeffSJack Morgenstein 
692b6ffaeffSJack Morgenstein 			/* 2. Check that do not have duplicates in OTHER
693b6ffaeffSJack Morgenstein 			 *    entries in the port GID table
694b6ffaeffSJack Morgenstein 			 */
6959cd59352SJack Morgenstein 			for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
696b6ffaeffSJack Morgenstein 				if (i >= base && i < base + num_gids)
697b6ffaeffSJack Morgenstein 					continue; /* don't compare to slave's current gids */
698b6ffaeffSJack Morgenstein 				gid_entry_tbl = &priv->roce_gids[port - 1][i];
699b6ffaeffSJack Morgenstein 				if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry)))
700b6ffaeffSJack Morgenstein 					continue;
701b6ffaeffSJack Morgenstein 				gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
702b6ffaeffSJack Morgenstein 				for (j = 0; j < num_gids; gid_entry_mbox++, j++) {
703b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
704b6ffaeffSJack Morgenstein 						    sizeof(zgid_entry)))
705b6ffaeffSJack Morgenstein 						continue;
706b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw,
707b6ffaeffSJack Morgenstein 						    sizeof(gid_entry_tbl->raw))) {
708b6ffaeffSJack Morgenstein 						/* found duplicate */
7099cd59352SJack Morgenstein 						mlx4_warn(dev, "requested gid entry for slave:%d "
710b6ffaeffSJack Morgenstein 							  "is a duplicate of gid at index %d\n",
7119cd59352SJack Morgenstein 							  slave, i);
712b6ffaeffSJack Morgenstein 						return -EINVAL;
7139cd59352SJack Morgenstein 					}
7149cd59352SJack Morgenstein 				}
7159cd59352SJack Morgenstein 			}
716b6ffaeffSJack Morgenstein 
717b6ffaeffSJack Morgenstein 			/* insert slave GIDs with memcpy, starting at slave's base index */
718b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
719b6ffaeffSJack Morgenstein 			for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++)
720b6ffaeffSJack Morgenstein 				memcpy(priv->roce_gids[port - 1][offset].raw, gid_entry_mbox->raw, 16);
721b6ffaeffSJack Morgenstein 
722b6ffaeffSJack Morgenstein 			/* Now, copy roce port gids table to current mailbox for passing to FW */
723b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
724b6ffaeffSJack Morgenstein 			for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
725b6ffaeffSJack Morgenstein 				memcpy(gid_entry_mbox->raw, priv->roce_gids[port - 1][i].raw, 16);
726b6ffaeffSJack Morgenstein 
7279cd59352SJack Morgenstein 			break;
728ffe455adSEugenia Emantayev 		}
729ffe455adSEugenia Emantayev 		return mlx4_cmd(dev, inbox->dma, in_mod, op_mod,
730ffe455adSEugenia Emantayev 				MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
731ffe455adSEugenia Emantayev 				MLX4_CMD_NATIVE);
732ffe455adSEugenia Emantayev 	}
733ffe455adSEugenia Emantayev 
734ffe455adSEugenia Emantayev 	/* For IB, we only consider:
735ffe455adSEugenia Emantayev 	 * - The capability mask, which is set to the aggregate of all
736ffe455adSEugenia Emantayev 	 *   slave function capabilities
737ffe455adSEugenia Emantayev 	 * - The QKey violatin counter - reset according to each request.
738ffe455adSEugenia Emantayev 	 */
739ffe455adSEugenia Emantayev 
740ffe455adSEugenia Emantayev 	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
741ffe455adSEugenia Emantayev 		reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40;
742ffe455adSEugenia Emantayev 		new_cap_mask = ((__be32 *) inbox->buf)[2];
743ffe455adSEugenia Emantayev 	} else {
744ffe455adSEugenia Emantayev 		reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1;
745ffe455adSEugenia Emantayev 		new_cap_mask = ((__be32 *) inbox->buf)[1];
746ffe455adSEugenia Emantayev 	}
747ffe455adSEugenia Emantayev 
748efcd235dSJack Morgenstein 	/* slave may not set the IS_SM capability for the port */
749efcd235dSJack Morgenstein 	if (slave != mlx4_master_func_num(dev) &&
750efcd235dSJack Morgenstein 	    (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM))
751efcd235dSJack Morgenstein 		return -EINVAL;
752efcd235dSJack Morgenstein 
753efcd235dSJack Morgenstein 	/* No DEV_MGMT in multifunc mode */
754efcd235dSJack Morgenstein 	if (mlx4_is_mfunc(dev) &&
755efcd235dSJack Morgenstein 	    (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP))
756efcd235dSJack Morgenstein 		return -EINVAL;
757efcd235dSJack Morgenstein 
758ffe455adSEugenia Emantayev 	agg_cap_mask = 0;
759ffe455adSEugenia Emantayev 	slave_cap_mask =
760ffe455adSEugenia Emantayev 		priv->mfunc.master.slave_state[slave].ib_cap_mask[port];
761ffe455adSEugenia Emantayev 	priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask;
762ffe455adSEugenia Emantayev 	for (i = 0; i < dev->num_slaves; i++)
763ffe455adSEugenia Emantayev 		agg_cap_mask |=
764ffe455adSEugenia Emantayev 			priv->mfunc.master.slave_state[i].ib_cap_mask[port];
765ffe455adSEugenia Emantayev 
766ffe455adSEugenia Emantayev 	/* only clear mailbox for guests.  Master may be setting
767ffe455adSEugenia Emantayev 	* MTU or PKEY table size
768ffe455adSEugenia Emantayev 	*/
769ffe455adSEugenia Emantayev 	if (slave != dev->caps.function)
770ffe455adSEugenia Emantayev 		memset(inbox->buf, 0, 256);
771ffe455adSEugenia Emantayev 	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
772edc4a67eSJack Morgenstein 		*(u8 *) inbox->buf	   |= !!reset_qkey_viols << 6;
773ffe455adSEugenia Emantayev 		((__be32 *) inbox->buf)[2] = agg_cap_mask;
774ffe455adSEugenia Emantayev 	} else {
775edc4a67eSJack Morgenstein 		((u8 *) inbox->buf)[3]     |= !!reset_qkey_viols;
776ffe455adSEugenia Emantayev 		((__be32 *) inbox->buf)[1] = agg_cap_mask;
777ffe455adSEugenia Emantayev 	}
778ffe455adSEugenia Emantayev 
779ffe455adSEugenia Emantayev 	err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT,
780ffe455adSEugenia Emantayev 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
781ffe455adSEugenia Emantayev 	if (err)
782ffe455adSEugenia Emantayev 		priv->mfunc.master.slave_state[slave].ib_cap_mask[port] =
783ffe455adSEugenia Emantayev 			slave_cap_mask;
784ffe455adSEugenia Emantayev 	return err;
785ffe455adSEugenia Emantayev }
786ffe455adSEugenia Emantayev 
787ffe455adSEugenia Emantayev int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave,
788ffe455adSEugenia Emantayev 			  struct mlx4_vhcr *vhcr,
789ffe455adSEugenia Emantayev 			  struct mlx4_cmd_mailbox *inbox,
790ffe455adSEugenia Emantayev 			  struct mlx4_cmd_mailbox *outbox,
791ffe455adSEugenia Emantayev 			  struct mlx4_cmd_info *cmd)
792ffe455adSEugenia Emantayev {
793449fc488SMatan Barak 	int port = mlx4_slave_convert_port(
794449fc488SMatan Barak 			dev, slave, vhcr->in_modifier & 0xFF);
795449fc488SMatan Barak 
796449fc488SMatan Barak 	if (port < 0)
797449fc488SMatan Barak 		return -EINVAL;
798449fc488SMatan Barak 
799449fc488SMatan Barak 	vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) |
800449fc488SMatan Barak 			    (port & 0xFF);
801449fc488SMatan Barak 
802ffe455adSEugenia Emantayev 	return mlx4_common_set_port(dev, slave, vhcr->in_modifier,
803ffe455adSEugenia Emantayev 				    vhcr->op_modifier, inbox);
804ffe455adSEugenia Emantayev }
805ffe455adSEugenia Emantayev 
806096335b3SOr Gerlitz /* bit locations for set port command with zero op modifier */
807096335b3SOr Gerlitz enum {
808096335b3SOr Gerlitz 	MLX4_SET_PORT_VL_CAP	 = 4, /* bits 7:4 */
809096335b3SOr Gerlitz 	MLX4_SET_PORT_MTU_CAP	 = 12, /* bits 15:12 */
8106634961cSJack Morgenstein 	MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20,
811096335b3SOr Gerlitz 	MLX4_CHANGE_PORT_VL_CAP	 = 21,
812096335b3SOr Gerlitz 	MLX4_CHANGE_PORT_MTU_CAP = 22,
813096335b3SOr Gerlitz };
814096335b3SOr Gerlitz 
8156634961cSJack Morgenstein int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz)
8165a2cc190SJeff Kirsher {
8175a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *mailbox;
8186634961cSJack Morgenstein 	int err, vl_cap, pkey_tbl_flag = 0;
8195a2cc190SJeff Kirsher 
8205a2cc190SJeff Kirsher 	if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
8215a2cc190SJeff Kirsher 		return 0;
8225a2cc190SJeff Kirsher 
8235a2cc190SJeff Kirsher 	mailbox = mlx4_alloc_cmd_mailbox(dev);
8245a2cc190SJeff Kirsher 	if (IS_ERR(mailbox))
8255a2cc190SJeff Kirsher 		return PTR_ERR(mailbox);
8265a2cc190SJeff Kirsher 
8275a2cc190SJeff Kirsher 	((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port];
828096335b3SOr Gerlitz 
8296634961cSJack Morgenstein 	if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) {
8306634961cSJack Morgenstein 		pkey_tbl_flag = 1;
8316634961cSJack Morgenstein 		((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz);
8326634961cSJack Morgenstein 	}
8336634961cSJack Morgenstein 
834096335b3SOr Gerlitz 	/* IB VL CAP enum isn't used by the firmware, just numerical values */
835096335b3SOr Gerlitz 	for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) {
836096335b3SOr Gerlitz 		((__be32 *) mailbox->buf)[0] = cpu_to_be32(
837096335b3SOr Gerlitz 			(1 << MLX4_CHANGE_PORT_MTU_CAP) |
838096335b3SOr Gerlitz 			(1 << MLX4_CHANGE_PORT_VL_CAP)  |
8396634961cSJack Morgenstein 			(pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) |
840096335b3SOr Gerlitz 			(dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) |
841096335b3SOr Gerlitz 			(vl_cap << MLX4_SET_PORT_VL_CAP));
8425a2cc190SJeff Kirsher 		err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT,
843f9baff50SJack Morgenstein 				MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
844096335b3SOr Gerlitz 		if (err != -ENOMEM)
845096335b3SOr Gerlitz 			break;
846096335b3SOr Gerlitz 	}
8475a2cc190SJeff Kirsher 
8485a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, mailbox);
8495a2cc190SJeff Kirsher 	return err;
8505a2cc190SJeff Kirsher }
851ffe455adSEugenia Emantayev 
852cb9ffb76SJoerg Roedel int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
853ffe455adSEugenia Emantayev 			  u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx)
854ffe455adSEugenia Emantayev {
855ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
856ffe455adSEugenia Emantayev 	struct mlx4_set_port_general_context *context;
857ffe455adSEugenia Emantayev 	int err;
858ffe455adSEugenia Emantayev 	u32 in_mod;
859ffe455adSEugenia Emantayev 
860ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
861ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
862ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
863ffe455adSEugenia Emantayev 	context = mailbox->buf;
864ffe455adSEugenia Emantayev 	context->flags = SET_PORT_GEN_ALL_VALID;
865ffe455adSEugenia Emantayev 	context->mtu = cpu_to_be16(mtu);
866ffe455adSEugenia Emantayev 	context->pptx = (pptx * (!pfctx)) << 7;
867ffe455adSEugenia Emantayev 	context->pfctx = pfctx;
868ffe455adSEugenia Emantayev 	context->pprx = (pprx * (!pfcrx)) << 7;
869ffe455adSEugenia Emantayev 	context->pfcrx = pfcrx;
870ffe455adSEugenia Emantayev 
871ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
872ffe455adSEugenia Emantayev 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
873ffe455adSEugenia Emantayev 		       MLX4_CMD_TIME_CLASS_B,  MLX4_CMD_WRAPPED);
874ffe455adSEugenia Emantayev 
875ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
876ffe455adSEugenia Emantayev 	return err;
877ffe455adSEugenia Emantayev }
878ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_general);
879ffe455adSEugenia Emantayev 
880cb9ffb76SJoerg Roedel int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
881ffe455adSEugenia Emantayev 			   u8 promisc)
882ffe455adSEugenia Emantayev {
883ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
884ffe455adSEugenia Emantayev 	struct mlx4_set_port_rqp_calc_context *context;
885ffe455adSEugenia Emantayev 	int err;
886ffe455adSEugenia Emantayev 	u32 in_mod;
887ffe455adSEugenia Emantayev 	u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ?
888ffe455adSEugenia Emantayev 		MCAST_DIRECT : MCAST_DEFAULT;
889ffe455adSEugenia Emantayev 
890c96d97f4SHadar Hen Zion 	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
891ffe455adSEugenia Emantayev 		return 0;
892ffe455adSEugenia Emantayev 
893ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
894ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
895ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
896ffe455adSEugenia Emantayev 	context = mailbox->buf;
897ffe455adSEugenia Emantayev 	context->base_qpn = cpu_to_be32(base_qpn);
898ffe455adSEugenia Emantayev 	context->n_mac = dev->caps.log_num_macs;
899ffe455adSEugenia Emantayev 	context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT |
900ffe455adSEugenia Emantayev 				       base_qpn);
901ffe455adSEugenia Emantayev 	context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT |
902ffe455adSEugenia Emantayev 				     base_qpn);
903ffe455adSEugenia Emantayev 	context->intra_no_vlan = 0;
904ffe455adSEugenia Emantayev 	context->no_vlan = MLX4_NO_VLAN_IDX;
905ffe455adSEugenia Emantayev 	context->intra_vlan_miss = 0;
906ffe455adSEugenia Emantayev 	context->vlan_miss = MLX4_VLAN_MISS_IDX;
907ffe455adSEugenia Emantayev 
908ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port;
909ffe455adSEugenia Emantayev 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
910ffe455adSEugenia Emantayev 		       MLX4_CMD_TIME_CLASS_B,  MLX4_CMD_WRAPPED);
911ffe455adSEugenia Emantayev 
912ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
913ffe455adSEugenia Emantayev 	return err;
914ffe455adSEugenia Emantayev }
915ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc);
916ffe455adSEugenia Emantayev 
917e5395e92SAmir Vadai int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc)
918e5395e92SAmir Vadai {
919e5395e92SAmir Vadai 	struct mlx4_cmd_mailbox *mailbox;
920e5395e92SAmir Vadai 	struct mlx4_set_port_prio2tc_context *context;
921e5395e92SAmir Vadai 	int err;
922e5395e92SAmir Vadai 	u32 in_mod;
923e5395e92SAmir Vadai 	int i;
924e5395e92SAmir Vadai 
925e5395e92SAmir Vadai 	mailbox = mlx4_alloc_cmd_mailbox(dev);
926e5395e92SAmir Vadai 	if (IS_ERR(mailbox))
927e5395e92SAmir Vadai 		return PTR_ERR(mailbox);
928e5395e92SAmir Vadai 	context = mailbox->buf;
929e5395e92SAmir Vadai 	for (i = 0; i < MLX4_NUM_UP; i += 2)
930e5395e92SAmir Vadai 		context->prio2tc[i >> 1] = prio2tc[i] << 4 | prio2tc[i + 1];
931e5395e92SAmir Vadai 
932e5395e92SAmir Vadai 	in_mod = MLX4_SET_PORT_PRIO2TC << 8 | port;
933e5395e92SAmir Vadai 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
934e5395e92SAmir Vadai 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
935e5395e92SAmir Vadai 
936e5395e92SAmir Vadai 	mlx4_free_cmd_mailbox(dev, mailbox);
937e5395e92SAmir Vadai 	return err;
938e5395e92SAmir Vadai }
939e5395e92SAmir Vadai EXPORT_SYMBOL(mlx4_SET_PORT_PRIO2TC);
940e5395e92SAmir Vadai 
941e5395e92SAmir Vadai int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw,
942e5395e92SAmir Vadai 		u8 *pg, u16 *ratelimit)
943e5395e92SAmir Vadai {
944e5395e92SAmir Vadai 	struct mlx4_cmd_mailbox *mailbox;
945e5395e92SAmir Vadai 	struct mlx4_set_port_scheduler_context *context;
946e5395e92SAmir Vadai 	int err;
947e5395e92SAmir Vadai 	u32 in_mod;
948e5395e92SAmir Vadai 	int i;
949e5395e92SAmir Vadai 
950e5395e92SAmir Vadai 	mailbox = mlx4_alloc_cmd_mailbox(dev);
951e5395e92SAmir Vadai 	if (IS_ERR(mailbox))
952e5395e92SAmir Vadai 		return PTR_ERR(mailbox);
953e5395e92SAmir Vadai 	context = mailbox->buf;
954e5395e92SAmir Vadai 
955e5395e92SAmir Vadai 	for (i = 0; i < MLX4_NUM_TC; i++) {
956e5395e92SAmir Vadai 		struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i];
957e5395e92SAmir Vadai 		u16 r = ratelimit && ratelimit[i] ? ratelimit[i] :
958e5395e92SAmir Vadai 			MLX4_RATELIMIT_DEFAULT;
959e5395e92SAmir Vadai 
960e5395e92SAmir Vadai 		tc->pg = htons(pg[i]);
961e5395e92SAmir Vadai 		tc->bw_precentage = htons(tc_tx_bw[i]);
962e5395e92SAmir Vadai 
963e5395e92SAmir Vadai 		tc->max_bw_units = htons(MLX4_RATELIMIT_UNITS);
964e5395e92SAmir Vadai 		tc->max_bw_value = htons(r);
965e5395e92SAmir Vadai 	}
966e5395e92SAmir Vadai 
967e5395e92SAmir Vadai 	in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port;
968e5395e92SAmir Vadai 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
969e5395e92SAmir Vadai 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
970e5395e92SAmir Vadai 
971e5395e92SAmir Vadai 	mlx4_free_cmd_mailbox(dev, mailbox);
972e5395e92SAmir Vadai 	return err;
973e5395e92SAmir Vadai }
974e5395e92SAmir Vadai EXPORT_SYMBOL(mlx4_SET_PORT_SCHEDULER);
975e5395e92SAmir Vadai 
9767ffdf726SOr Gerlitz enum {
9777ffdf726SOr Gerlitz 	VXLAN_ENABLE_MODIFY	= 1 << 7,
9787ffdf726SOr Gerlitz 	VXLAN_STEERING_MODIFY	= 1 << 6,
9797ffdf726SOr Gerlitz 
9807ffdf726SOr Gerlitz 	VXLAN_ENABLE		= 1 << 7,
9817ffdf726SOr Gerlitz };
9827ffdf726SOr Gerlitz 
9837ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context {
9847ffdf726SOr Gerlitz 	u32	reserved1;
9857ffdf726SOr Gerlitz 	u8	modify_flags;
9867ffdf726SOr Gerlitz 	u8	reserved2;
9877ffdf726SOr Gerlitz 	u8	enable_flags;
9887ffdf726SOr Gerlitz 	u8	steering;
9897ffdf726SOr Gerlitz };
9907ffdf726SOr Gerlitz 
9911b136de1SOr Gerlitz int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable)
9927ffdf726SOr Gerlitz {
9937ffdf726SOr Gerlitz 	int err;
9947ffdf726SOr Gerlitz 	u32 in_mod;
9957ffdf726SOr Gerlitz 	struct mlx4_cmd_mailbox *mailbox;
9967ffdf726SOr Gerlitz 	struct mlx4_set_port_vxlan_context  *context;
9977ffdf726SOr Gerlitz 
9987ffdf726SOr Gerlitz 	mailbox = mlx4_alloc_cmd_mailbox(dev);
9997ffdf726SOr Gerlitz 	if (IS_ERR(mailbox))
10007ffdf726SOr Gerlitz 		return PTR_ERR(mailbox);
10017ffdf726SOr Gerlitz 	context = mailbox->buf;
10027ffdf726SOr Gerlitz 	memset(context, 0, sizeof(*context));
10037ffdf726SOr Gerlitz 
10047ffdf726SOr Gerlitz 	context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY;
10051b136de1SOr Gerlitz 	if (enable)
10067ffdf726SOr Gerlitz 		context->enable_flags = VXLAN_ENABLE;
10077ffdf726SOr Gerlitz 	context->steering  = steering;
10087ffdf726SOr Gerlitz 
10097ffdf726SOr Gerlitz 	in_mod = MLX4_SET_PORT_VXLAN << 8 | port;
10107ffdf726SOr Gerlitz 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
10117ffdf726SOr Gerlitz 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
10127ffdf726SOr Gerlitz 
10137ffdf726SOr Gerlitz 	mlx4_free_cmd_mailbox(dev, mailbox);
10147ffdf726SOr Gerlitz 	return err;
10157ffdf726SOr Gerlitz }
10167ffdf726SOr Gerlitz EXPORT_SYMBOL(mlx4_SET_PORT_VXLAN);
10177ffdf726SOr Gerlitz 
1018ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1019ffe455adSEugenia Emantayev 				struct mlx4_vhcr *vhcr,
1020ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *inbox,
1021ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *outbox,
1022ffe455adSEugenia Emantayev 				struct mlx4_cmd_info *cmd)
1023ffe455adSEugenia Emantayev {
1024ffe455adSEugenia Emantayev 	int err = 0;
1025ffe455adSEugenia Emantayev 
1026ffe455adSEugenia Emantayev 	return err;
1027ffe455adSEugenia Emantayev }
1028ffe455adSEugenia Emantayev 
1029ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port,
1030ffe455adSEugenia Emantayev 			u64 mac, u64 clear, u8 mode)
1031ffe455adSEugenia Emantayev {
1032ffe455adSEugenia Emantayev 	return mlx4_cmd(dev, (mac | (clear << 63)), port, mode,
1033ffe455adSEugenia Emantayev 			MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B,
1034ffe455adSEugenia Emantayev 			MLX4_CMD_WRAPPED);
1035ffe455adSEugenia Emantayev }
1036ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR);
1037ffe455adSEugenia Emantayev 
1038ffe455adSEugenia Emantayev int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1039ffe455adSEugenia Emantayev 			       struct mlx4_vhcr *vhcr,
1040ffe455adSEugenia Emantayev 			       struct mlx4_cmd_mailbox *inbox,
1041ffe455adSEugenia Emantayev 			       struct mlx4_cmd_mailbox *outbox,
1042ffe455adSEugenia Emantayev 			       struct mlx4_cmd_info *cmd)
1043ffe455adSEugenia Emantayev {
1044ffe455adSEugenia Emantayev 	int err = 0;
1045ffe455adSEugenia Emantayev 
1046ffe455adSEugenia Emantayev 	return err;
1047ffe455adSEugenia Emantayev }
1048ffe455adSEugenia Emantayev 
1049ffe455adSEugenia Emantayev int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave,
1050ffe455adSEugenia Emantayev 			       u32 in_mod, struct mlx4_cmd_mailbox *outbox)
1051ffe455adSEugenia Emantayev {
1052ffe455adSEugenia Emantayev 	return mlx4_cmd_box(dev, 0, outbox->dma, in_mod, 0,
1053ffe455adSEugenia Emantayev 			    MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B,
1054ffe455adSEugenia Emantayev 			    MLX4_CMD_NATIVE);
1055ffe455adSEugenia Emantayev }
1056ffe455adSEugenia Emantayev 
1057ffe455adSEugenia Emantayev int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave,
1058ffe455adSEugenia Emantayev 				struct mlx4_vhcr *vhcr,
1059ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *inbox,
1060ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *outbox,
1061ffe455adSEugenia Emantayev 				struct mlx4_cmd_info *cmd)
1062ffe455adSEugenia Emantayev {
106335fb9afbSEugenia Emantayev 	if (slave != dev->caps.function)
106435fb9afbSEugenia Emantayev 		return 0;
1065ffe455adSEugenia Emantayev 	return mlx4_common_dump_eth_stats(dev, slave,
1066ffe455adSEugenia Emantayev 					  vhcr->in_modifier, outbox);
1067ffe455adSEugenia Emantayev }
106893ece0c1SEugenia Emantayev 
106993ece0c1SEugenia Emantayev void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap)
107093ece0c1SEugenia Emantayev {
107193ece0c1SEugenia Emantayev 	if (!mlx4_is_mfunc(dev)) {
107293ece0c1SEugenia Emantayev 		*stats_bitmap = 0;
107393ece0c1SEugenia Emantayev 		return;
107493ece0c1SEugenia Emantayev 	}
107593ece0c1SEugenia Emantayev 
107693ece0c1SEugenia Emantayev 	*stats_bitmap = (MLX4_STATS_TRAFFIC_COUNTERS_MASK |
107793ece0c1SEugenia Emantayev 			 MLX4_STATS_TRAFFIC_DROPS_MASK |
107893ece0c1SEugenia Emantayev 			 MLX4_STATS_PORT_COUNTERS_MASK);
107993ece0c1SEugenia Emantayev 
108093ece0c1SEugenia Emantayev 	if (mlx4_is_master(dev))
108193ece0c1SEugenia Emantayev 		*stats_bitmap |= MLX4_STATS_ERROR_COUNTERS_MASK;
108293ece0c1SEugenia Emantayev }
108393ece0c1SEugenia Emantayev EXPORT_SYMBOL(mlx4_set_stats_bitmap);
10846ee51a4eSJack Morgenstein 
10859cd59352SJack Morgenstein int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
10869cd59352SJack Morgenstein 				 int *slave_id)
10876ee51a4eSJack Morgenstein {
10886ee51a4eSJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
10896ee51a4eSJack Morgenstein 	int i, found_ix = -1;
1090b6ffaeffSJack Morgenstein 	int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
1091449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
1092449fc488SMatan Barak 	unsigned num_vfs;
1093449fc488SMatan Barak 	int slave_gid;
10946ee51a4eSJack Morgenstein 
10956ee51a4eSJack Morgenstein 	if (!mlx4_is_mfunc(dev))
10966ee51a4eSJack Morgenstein 		return -EINVAL;
10976ee51a4eSJack Morgenstein 
1098449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1099449fc488SMatan Barak 	num_vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
1100449fc488SMatan Barak 
11016ee51a4eSJack Morgenstein 	for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
11026ee51a4eSJack Morgenstein 		if (!memcmp(priv->roce_gids[port - 1][i].raw, gid, 16)) {
11036ee51a4eSJack Morgenstein 			found_ix = i;
11046ee51a4eSJack Morgenstein 			break;
11056ee51a4eSJack Morgenstein 		}
11066ee51a4eSJack Morgenstein 	}
11076ee51a4eSJack Morgenstein 
1108b6ffaeffSJack Morgenstein 	if (found_ix >= 0) {
11090254bc82SMatan Barak 		/* Calculate a slave_gid which is the slave number in the gid
11100254bc82SMatan Barak 		 * table and not a globally unique slave number.
11110254bc82SMatan Barak 		 */
1112b6ffaeffSJack Morgenstein 		if (found_ix < MLX4_ROCE_PF_GIDS)
1113449fc488SMatan Barak 			slave_gid = 0;
1114449fc488SMatan Barak 		else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) *
1115449fc488SMatan Barak 			 (vf_gids / num_vfs + 1))
1116449fc488SMatan Barak 			slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) /
1117449fc488SMatan Barak 				     (vf_gids / num_vfs + 1)) + 1;
1118b6ffaeffSJack Morgenstein 		else
1119449fc488SMatan Barak 			slave_gid =
1120b6ffaeffSJack Morgenstein 			((found_ix - MLX4_ROCE_PF_GIDS -
1121449fc488SMatan Barak 			  ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) /
1122449fc488SMatan Barak 			 (vf_gids / num_vfs)) + vf_gids % num_vfs + 1;
1123449fc488SMatan Barak 
11240254bc82SMatan Barak 		/* Calculate the globally unique slave id */
1125449fc488SMatan Barak 		if (slave_gid) {
1126449fc488SMatan Barak 			struct mlx4_active_ports exclusive_ports;
1127449fc488SMatan Barak 			struct mlx4_active_ports actv_ports;
1128449fc488SMatan Barak 			struct mlx4_slaves_pport slaves_pport_actv;
1129449fc488SMatan Barak 			unsigned max_port_p_one;
11300254bc82SMatan Barak 			int num_vfs_before = 0;
11310254bc82SMatan Barak 			int candidate_slave_gid;
1132449fc488SMatan Barak 
11330254bc82SMatan Barak 			/* Calculate how many VFs are on the previous port, if exists */
1134449fc488SMatan Barak 			for (i = 1; i < port; i++) {
1135449fc488SMatan Barak 				bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
11360254bc82SMatan Barak 				set_bit(i - 1, exclusive_ports.ports);
1137449fc488SMatan Barak 				slaves_pport_actv =
1138449fc488SMatan Barak 					mlx4_phys_to_slaves_pport_actv(
1139449fc488SMatan Barak 							dev, &exclusive_ports);
11400254bc82SMatan Barak 				num_vfs_before += bitmap_weight(
1141449fc488SMatan Barak 						slaves_pport_actv.slaves,
1142449fc488SMatan Barak 						dev->num_vfs + 1);
1143449fc488SMatan Barak 			}
1144449fc488SMatan Barak 
11450254bc82SMatan Barak 			/* candidate_slave_gid isn't necessarily the correct slave, but
11460254bc82SMatan Barak 			 * it has the same number of ports and is assigned to the same
11470254bc82SMatan Barak 			 * ports as the real slave we're looking for. On dual port VF,
11480254bc82SMatan Barak 			 * slave_gid = [single port VFs on port <port>] +
11490254bc82SMatan Barak 			 * [offset of the current slave from the first dual port VF] +
11500254bc82SMatan Barak 			 * 1 (for the PF).
11510254bc82SMatan Barak 			 */
11520254bc82SMatan Barak 			candidate_slave_gid = slave_gid + num_vfs_before;
11530254bc82SMatan Barak 
11540254bc82SMatan Barak 			actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid);
1155449fc488SMatan Barak 			max_port_p_one = find_first_bit(
1156449fc488SMatan Barak 				actv_ports.ports, dev->caps.num_ports) +
1157449fc488SMatan Barak 				bitmap_weight(actv_ports.ports,
1158449fc488SMatan Barak 					      dev->caps.num_ports) + 1;
1159449fc488SMatan Barak 
11600254bc82SMatan Barak 			/* Calculate the real slave number */
1161449fc488SMatan Barak 			for (i = 1; i < max_port_p_one; i++) {
1162449fc488SMatan Barak 				if (i == port)
1163449fc488SMatan Barak 					continue;
1164449fc488SMatan Barak 				bitmap_zero(exclusive_ports.ports,
1165449fc488SMatan Barak 					    dev->caps.num_ports);
1166449fc488SMatan Barak 				set_bit(i - 1, exclusive_ports.ports);
1167449fc488SMatan Barak 				slaves_pport_actv =
1168449fc488SMatan Barak 					mlx4_phys_to_slaves_pport_actv(
1169449fc488SMatan Barak 						dev, &exclusive_ports);
1170449fc488SMatan Barak 				slave_gid += bitmap_weight(
1171449fc488SMatan Barak 						slaves_pport_actv.slaves,
1172449fc488SMatan Barak 						dev->num_vfs + 1);
1173449fc488SMatan Barak 			}
1174449fc488SMatan Barak 		}
1175449fc488SMatan Barak 		*slave_id = slave_gid;
1176b6ffaeffSJack Morgenstein 	}
11776ee51a4eSJack Morgenstein 
11786ee51a4eSJack Morgenstein 	return (found_ix >= 0) ? 0 : -EINVAL;
11796ee51a4eSJack Morgenstein }
11806ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid);
11816ee51a4eSJack Morgenstein 
11829cd59352SJack Morgenstein int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id,
11839cd59352SJack Morgenstein 				 u8 *gid)
11846ee51a4eSJack Morgenstein {
11856ee51a4eSJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
11866ee51a4eSJack Morgenstein 
11876ee51a4eSJack Morgenstein 	if (!mlx4_is_master(dev))
11886ee51a4eSJack Morgenstein 		return -EINVAL;
11896ee51a4eSJack Morgenstein 
11906ee51a4eSJack Morgenstein 	memcpy(gid, priv->roce_gids[port - 1][slave_id].raw, 16);
11916ee51a4eSJack Morgenstein 	return 0;
11926ee51a4eSJack Morgenstein }
11936ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
1194