15a2cc190SJeff Kirsher /*
25a2cc190SJeff Kirsher  * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
35a2cc190SJeff Kirsher  *
45a2cc190SJeff Kirsher  * This software is available to you under a choice of one of two
55a2cc190SJeff Kirsher  * licenses.  You may choose to be licensed under the terms of the GNU
65a2cc190SJeff Kirsher  * General Public License (GPL) Version 2, available from the file
75a2cc190SJeff Kirsher  * COPYING in the main directory of this source tree, or the
85a2cc190SJeff Kirsher  * OpenIB.org BSD license below:
95a2cc190SJeff Kirsher  *
105a2cc190SJeff Kirsher  *     Redistribution and use in source and binary forms, with or
115a2cc190SJeff Kirsher  *     without modification, are permitted provided that the following
125a2cc190SJeff Kirsher  *     conditions are met:
135a2cc190SJeff Kirsher  *
145a2cc190SJeff Kirsher  *      - Redistributions of source code must retain the above
155a2cc190SJeff Kirsher  *        copyright notice, this list of conditions and the following
165a2cc190SJeff Kirsher  *        disclaimer.
175a2cc190SJeff Kirsher  *
185a2cc190SJeff Kirsher  *      - Redistributions in binary form must reproduce the above
195a2cc190SJeff Kirsher  *        copyright notice, this list of conditions and the following
205a2cc190SJeff Kirsher  *        disclaimer in the documentation and/or other materials
215a2cc190SJeff Kirsher  *        provided with the distribution.
225a2cc190SJeff Kirsher  *
235a2cc190SJeff Kirsher  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
245a2cc190SJeff Kirsher  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
255a2cc190SJeff Kirsher  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
265a2cc190SJeff Kirsher  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
275a2cc190SJeff Kirsher  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
285a2cc190SJeff Kirsher  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
295a2cc190SJeff Kirsher  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
305a2cc190SJeff Kirsher  * SOFTWARE.
315a2cc190SJeff Kirsher  */
325a2cc190SJeff Kirsher 
335a2cc190SJeff Kirsher #include <linux/errno.h>
345a2cc190SJeff Kirsher #include <linux/if_ether.h>
35c59fec20SEugenia Emantayev #include <linux/if_vlan.h>
36ee40fa06SPaul Gortmaker #include <linux/export.h>
375a2cc190SJeff Kirsher 
385a2cc190SJeff Kirsher #include <linux/mlx4/cmd.h>
395a2cc190SJeff Kirsher 
405a2cc190SJeff Kirsher #include "mlx4.h"
41b4b6e842SEran Ben Elisha #include "mlx4_stats.h"
425a2cc190SJeff Kirsher 
435a2cc190SJeff Kirsher #define MLX4_MAC_VALID		(1ull << 63)
445a2cc190SJeff Kirsher 
455a2cc190SJeff Kirsher #define MLX4_VLAN_VALID		(1u << 31)
465a2cc190SJeff Kirsher #define MLX4_VLAN_MASK		0xfff
475a2cc190SJeff Kirsher 
485a2cc190SJeff Kirsher void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table)
495a2cc190SJeff Kirsher {
505a2cc190SJeff Kirsher 	int i;
515a2cc190SJeff Kirsher 
525a2cc190SJeff Kirsher 	mutex_init(&table->mutex);
535a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
545a2cc190SJeff Kirsher 		table->entries[i] = 0;
555a2cc190SJeff Kirsher 		table->refs[i]	 = 0;
565a2cc190SJeff Kirsher 	}
575a2cc190SJeff Kirsher 	table->max   = 1 << dev->caps.log_num_macs;
585a2cc190SJeff Kirsher 	table->total = 0;
595a2cc190SJeff Kirsher }
605a2cc190SJeff Kirsher 
615a2cc190SJeff Kirsher void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
625a2cc190SJeff Kirsher {
635a2cc190SJeff Kirsher 	int i;
645a2cc190SJeff Kirsher 
655a2cc190SJeff Kirsher 	mutex_init(&table->mutex);
665a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
675a2cc190SJeff Kirsher 		table->entries[i] = 0;
685a2cc190SJeff Kirsher 		table->refs[i]	 = 0;
695a2cc190SJeff Kirsher 	}
70e72ebf5aSYevgeny Petrilin 	table->max   = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR;
715a2cc190SJeff Kirsher 	table->total = 0;
725a2cc190SJeff Kirsher }
735a2cc190SJeff Kirsher 
74111c6094SJack Morgenstein void mlx4_init_roce_gid_table(struct mlx4_dev *dev,
75111c6094SJack Morgenstein 			      struct mlx4_roce_gid_table *table)
76111c6094SJack Morgenstein {
77111c6094SJack Morgenstein 	int i;
78111c6094SJack Morgenstein 
79111c6094SJack Morgenstein 	mutex_init(&table->mutex);
80111c6094SJack Morgenstein 	for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++)
81111c6094SJack Morgenstein 		memset(table->roce_gids[i].raw, 0, MLX4_ROCE_GID_ENTRY_SIZE);
82111c6094SJack Morgenstein }
83111c6094SJack Morgenstein 
845a2cc190SJeff Kirsher static int validate_index(struct mlx4_dev *dev,
855a2cc190SJeff Kirsher 			  struct mlx4_mac_table *table, int index)
865a2cc190SJeff Kirsher {
875a2cc190SJeff Kirsher 	int err = 0;
885a2cc190SJeff Kirsher 
895a2cc190SJeff Kirsher 	if (index < 0 || index >= table->max || !table->entries[index]) {
905a2cc190SJeff Kirsher 		mlx4_warn(dev, "No valid Mac entry for the given index\n");
915a2cc190SJeff Kirsher 		err = -EINVAL;
925a2cc190SJeff Kirsher 	}
935a2cc190SJeff Kirsher 	return err;
945a2cc190SJeff Kirsher }
955a2cc190SJeff Kirsher 
965a2cc190SJeff Kirsher static int find_index(struct mlx4_dev *dev,
975a2cc190SJeff Kirsher 		      struct mlx4_mac_table *table, u64 mac)
985a2cc190SJeff Kirsher {
995a2cc190SJeff Kirsher 	int i;
100ffe455adSEugenia Emantayev 
1015a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
102f4fd40b2SJack Morgenstein 		if (table->refs[i] &&
103f4fd40b2SJack Morgenstein 		    (MLX4_MAC_MASK & mac) ==
104ffe455adSEugenia Emantayev 		    (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))
1055a2cc190SJeff Kirsher 			return i;
1065a2cc190SJeff Kirsher 	}
1075a2cc190SJeff Kirsher 	/* Mac not found */
1085a2cc190SJeff Kirsher 	return -EINVAL;
1095a2cc190SJeff Kirsher }
1105a2cc190SJeff Kirsher 
111ffe455adSEugenia Emantayev static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
112ffe455adSEugenia Emantayev 				   __be64 *entries)
113ffe455adSEugenia Emantayev {
114ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
115ffe455adSEugenia Emantayev 	u32 in_mod;
116ffe455adSEugenia Emantayev 	int err;
117ffe455adSEugenia Emantayev 
118ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
119ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
120ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
121ffe455adSEugenia Emantayev 
122ffe455adSEugenia Emantayev 	memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE);
123ffe455adSEugenia Emantayev 
124ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port;
125ffe455adSEugenia Emantayev 
126a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
127a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
128a130b590SIdo Shamay 		       MLX4_CMD_NATIVE);
129ffe455adSEugenia Emantayev 
130ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
131ffe455adSEugenia Emantayev 	return err;
132ffe455adSEugenia Emantayev }
133ffe455adSEugenia Emantayev 
134297e0dadSMoni Shoua int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx)
135297e0dadSMoni Shoua {
136297e0dadSMoni Shoua 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
137297e0dadSMoni Shoua 	struct mlx4_mac_table *table = &info->mac_table;
138297e0dadSMoni Shoua 	int i;
139297e0dadSMoni Shoua 
140297e0dadSMoni Shoua 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
141297e0dadSMoni Shoua 		if (!table->refs[i])
142297e0dadSMoni Shoua 			continue;
143297e0dadSMoni Shoua 
144297e0dadSMoni Shoua 		if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
145297e0dadSMoni Shoua 			*idx = i;
146297e0dadSMoni Shoua 			return 0;
147297e0dadSMoni Shoua 		}
148297e0dadSMoni Shoua 	}
149297e0dadSMoni Shoua 
150297e0dadSMoni Shoua 	return -ENOENT;
151297e0dadSMoni Shoua }
152297e0dadSMoni Shoua EXPORT_SYMBOL_GPL(mlx4_find_cached_mac);
153297e0dadSMoni Shoua 
154ffe455adSEugenia Emantayev int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
155ffe455adSEugenia Emantayev {
156ffe455adSEugenia Emantayev 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
157ffe455adSEugenia Emantayev 	struct mlx4_mac_table *table = &info->mac_table;
158ffe455adSEugenia Emantayev 	int i, err = 0;
159ffe455adSEugenia Emantayev 	int free = -1;
160ffe455adSEugenia Emantayev 
161ffe455adSEugenia Emantayev 	mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d\n",
162ffe455adSEugenia Emantayev 		 (unsigned long long) mac, port);
163ffe455adSEugenia Emantayev 
164ffe455adSEugenia Emantayev 	mutex_lock(&table->mutex);
165ffe455adSEugenia Emantayev 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
166f4fd40b2SJack Morgenstein 		if (!table->refs[i]) {
167f4fd40b2SJack Morgenstein 			if (free < 0)
168ffe455adSEugenia Emantayev 				free = i;
169ffe455adSEugenia Emantayev 			continue;
170ffe455adSEugenia Emantayev 		}
171ffe455adSEugenia Emantayev 
172f4fd40b2SJack Morgenstein 		if ((MLX4_MAC_MASK & mac) ==
173f4fd40b2SJack Morgenstein 		     (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 {
247143b3efbSEugenia Emantayev 	struct mlx4_port_info *info;
248143b3efbSEugenia Emantayev 	struct mlx4_mac_table *table;
249ffe455adSEugenia Emantayev 	int index;
250ffe455adSEugenia Emantayev 
251143b3efbSEugenia Emantayev 	if (port < 1 || port > dev->caps.num_ports) {
252143b3efbSEugenia Emantayev 		mlx4_warn(dev, "invalid port number (%d), aborting...\n", port);
253143b3efbSEugenia Emantayev 		return;
254143b3efbSEugenia Emantayev 	}
255143b3efbSEugenia Emantayev 	info = &mlx4_priv(dev)->port[port];
256143b3efbSEugenia Emantayev 	table = &info->mac_table;
2575a2cc190SJeff Kirsher 	mutex_lock(&table->mutex);
2586ce71acdSRony Efraim 	index = find_index(dev, table, mac);
2595a2cc190SJeff Kirsher 
2605a2cc190SJeff Kirsher 	if (validate_index(dev, table, index))
2615a2cc190SJeff Kirsher 		goto out;
2626ce71acdSRony Efraim 	if (--table->refs[index]) {
2631a91de28SJoe Perches 		mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n",
2641a91de28SJoe Perches 			 index);
2656ce71acdSRony Efraim 		goto out;
2666ce71acdSRony Efraim 	}
2675a2cc190SJeff Kirsher 
2685a2cc190SJeff Kirsher 	table->entries[index] = 0;
2695a2cc190SJeff Kirsher 	mlx4_set_port_mac_table(dev, port, table->entries);
2705a2cc190SJeff Kirsher 	--table->total;
2715a2cc190SJeff Kirsher out:
2725a2cc190SJeff Kirsher 	mutex_unlock(&table->mutex);
2735a2cc190SJeff Kirsher }
274ffe455adSEugenia Emantayev EXPORT_SYMBOL_GPL(__mlx4_unregister_mac);
275ffe455adSEugenia Emantayev 
276ffe455adSEugenia Emantayev void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
277ffe455adSEugenia Emantayev {
278e7dbeba8SJack Morgenstein 	u64 out_param = 0;
279ffe455adSEugenia Emantayev 
280ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
281acddd5ddSJack Morgenstein 		if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) {
282acddd5ddSJack Morgenstein 			(void) mlx4_cmd_imm(dev, mac, &out_param,
283acddd5ddSJack Morgenstein 					    ((u32) port) << 8 | (u32) RES_MAC,
284acddd5ddSJack Morgenstein 					    RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
285acddd5ddSJack Morgenstein 					    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
286acddd5ddSJack Morgenstein 		} else {
287acddd5ddSJack Morgenstein 			/* use old unregister mac format */
288ffe455adSEugenia Emantayev 			set_param_l(&out_param, port);
289162344edSOr Gerlitz 			(void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC,
290ffe455adSEugenia Emantayev 					    RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
291ffe455adSEugenia Emantayev 					    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
292acddd5ddSJack Morgenstein 		}
293ffe455adSEugenia Emantayev 		return;
294ffe455adSEugenia Emantayev 	}
295ffe455adSEugenia Emantayev 	__mlx4_unregister_mac(dev, port, mac);
296ffe455adSEugenia Emantayev 	return;
297ffe455adSEugenia Emantayev }
2985a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
2995a2cc190SJeff Kirsher 
30016a10ffdSYan Burman int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
3015a2cc190SJeff Kirsher {
3025a2cc190SJeff Kirsher 	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
3035a2cc190SJeff Kirsher 	struct mlx4_mac_table *table = &info->mac_table;
304ffe455adSEugenia Emantayev 	int index = qpn - info->base_qpn;
305ffe455adSEugenia Emantayev 	int err = 0;
3065a2cc190SJeff Kirsher 
307ffe455adSEugenia Emantayev 	/* CX1 doesn't support multi-functions */
3085a2cc190SJeff Kirsher 	mutex_lock(&table->mutex);
3095a2cc190SJeff Kirsher 
3105a2cc190SJeff Kirsher 	err = validate_index(dev, table, index);
3115a2cc190SJeff Kirsher 	if (err)
3125a2cc190SJeff Kirsher 		goto out;
3135a2cc190SJeff Kirsher 
3145a2cc190SJeff Kirsher 	table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
3155a2cc190SJeff Kirsher 
3165a2cc190SJeff Kirsher 	err = mlx4_set_port_mac_table(dev, port, table->entries);
3175a2cc190SJeff Kirsher 	if (unlikely(err)) {
318ffe455adSEugenia Emantayev 		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
319ffe455adSEugenia Emantayev 			 (unsigned long long) new_mac);
3205a2cc190SJeff Kirsher 		table->entries[index] = 0;
3215a2cc190SJeff Kirsher 	}
3225a2cc190SJeff Kirsher out:
3235a2cc190SJeff Kirsher 	mutex_unlock(&table->mutex);
3245a2cc190SJeff Kirsher 	return err;
3255a2cc190SJeff Kirsher }
32616a10ffdSYan Burman EXPORT_SYMBOL_GPL(__mlx4_replace_mac);
327ffe455adSEugenia Emantayev 
3285a2cc190SJeff Kirsher static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
3295a2cc190SJeff Kirsher 				    __be32 *entries)
3305a2cc190SJeff Kirsher {
3315a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *mailbox;
3325a2cc190SJeff Kirsher 	u32 in_mod;
3335a2cc190SJeff Kirsher 	int err;
3345a2cc190SJeff Kirsher 
3355a2cc190SJeff Kirsher 	mailbox = mlx4_alloc_cmd_mailbox(dev);
3365a2cc190SJeff Kirsher 	if (IS_ERR(mailbox))
3375a2cc190SJeff Kirsher 		return PTR_ERR(mailbox);
3385a2cc190SJeff Kirsher 
3395a2cc190SJeff Kirsher 	memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE);
3405a2cc190SJeff Kirsher 	in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port;
341a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
342a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
343a130b590SIdo Shamay 		       MLX4_CMD_NATIVE);
3445a2cc190SJeff Kirsher 
3455a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, mailbox);
3465a2cc190SJeff Kirsher 
3475a2cc190SJeff Kirsher 	return err;
3485a2cc190SJeff Kirsher }
3495a2cc190SJeff Kirsher 
3505a2cc190SJeff Kirsher int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
3515a2cc190SJeff Kirsher {
3525a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
3535a2cc190SJeff Kirsher 	int i;
3545a2cc190SJeff Kirsher 
3555a2cc190SJeff Kirsher 	for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) {
3565a2cc190SJeff Kirsher 		if (table->refs[i] &&
3575a2cc190SJeff Kirsher 		    (vid == (MLX4_VLAN_MASK &
3585a2cc190SJeff Kirsher 			      be32_to_cpu(table->entries[i])))) {
3595a2cc190SJeff Kirsher 			/* VLAN already registered, increase reference count */
3605a2cc190SJeff Kirsher 			*idx = i;
3615a2cc190SJeff Kirsher 			return 0;
3625a2cc190SJeff Kirsher 		}
3635a2cc190SJeff Kirsher 	}
3645a2cc190SJeff Kirsher 
3655a2cc190SJeff Kirsher 	return -ENOENT;
3665a2cc190SJeff Kirsher }
3675a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
3685a2cc190SJeff Kirsher 
3693f7fb021SRony Efraim int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
370ffe455adSEugenia Emantayev 				int *index)
3715a2cc190SJeff Kirsher {
3725a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
3735a2cc190SJeff Kirsher 	int i, err = 0;
3745a2cc190SJeff Kirsher 	int free = -1;
3755a2cc190SJeff Kirsher 
3765a2cc190SJeff Kirsher 	mutex_lock(&table->mutex);
377e72ebf5aSYevgeny Petrilin 
378e72ebf5aSYevgeny Petrilin 	if (table->total == table->max) {
379e72ebf5aSYevgeny Petrilin 		/* No free vlan entries */
380e72ebf5aSYevgeny Petrilin 		err = -ENOSPC;
381e72ebf5aSYevgeny Petrilin 		goto out;
382e72ebf5aSYevgeny Petrilin 	}
383e72ebf5aSYevgeny Petrilin 
3845a2cc190SJeff Kirsher 	for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
3855a2cc190SJeff Kirsher 		if (free < 0 && (table->refs[i] == 0)) {
3865a2cc190SJeff Kirsher 			free = i;
3875a2cc190SJeff Kirsher 			continue;
3885a2cc190SJeff Kirsher 		}
3895a2cc190SJeff Kirsher 
3905a2cc190SJeff Kirsher 		if (table->refs[i] &&
3915a2cc190SJeff Kirsher 		    (vlan == (MLX4_VLAN_MASK &
3925a2cc190SJeff Kirsher 			      be32_to_cpu(table->entries[i])))) {
3935a2cc190SJeff Kirsher 			/* Vlan already registered, increase references count */
3945a2cc190SJeff Kirsher 			*index = i;
3955a2cc190SJeff Kirsher 			++table->refs[i];
3965a2cc190SJeff Kirsher 			goto out;
3975a2cc190SJeff Kirsher 		}
3985a2cc190SJeff Kirsher 	}
3995a2cc190SJeff Kirsher 
4005a2cc190SJeff Kirsher 	if (free < 0) {
4015a2cc190SJeff Kirsher 		err = -ENOMEM;
4025a2cc190SJeff Kirsher 		goto out;
4035a2cc190SJeff Kirsher 	}
4045a2cc190SJeff Kirsher 
405ffe455adSEugenia Emantayev 	/* Register new VLAN */
4065a2cc190SJeff Kirsher 	table->refs[free] = 1;
4075a2cc190SJeff Kirsher 	table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
4085a2cc190SJeff Kirsher 
4095a2cc190SJeff Kirsher 	err = mlx4_set_port_vlan_table(dev, port, table->entries);
4105a2cc190SJeff Kirsher 	if (unlikely(err)) {
4115a2cc190SJeff Kirsher 		mlx4_warn(dev, "Failed adding vlan: %u\n", vlan);
4125a2cc190SJeff Kirsher 		table->refs[free] = 0;
4135a2cc190SJeff Kirsher 		table->entries[free] = 0;
4145a2cc190SJeff Kirsher 		goto out;
4155a2cc190SJeff Kirsher 	}
4165a2cc190SJeff Kirsher 
4175a2cc190SJeff Kirsher 	*index = free;
4185a2cc190SJeff Kirsher 	++table->total;
4195a2cc190SJeff Kirsher out:
4205a2cc190SJeff Kirsher 	mutex_unlock(&table->mutex);
4215a2cc190SJeff Kirsher 	return err;
4225a2cc190SJeff Kirsher }
423ffe455adSEugenia Emantayev 
424ffe455adSEugenia Emantayev int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
425ffe455adSEugenia Emantayev {
426e7dbeba8SJack Morgenstein 	u64 out_param = 0;
427ffe455adSEugenia Emantayev 	int err;
428ffe455adSEugenia Emantayev 
429162226a1SJack Morgenstein 	if (vlan > 4095)
430162226a1SJack Morgenstein 		return -EINVAL;
431162226a1SJack Morgenstein 
432ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
433acddd5ddSJack Morgenstein 		err = mlx4_cmd_imm(dev, vlan, &out_param,
434acddd5ddSJack Morgenstein 				   ((u32) port) << 8 | (u32) RES_VLAN,
435ffe455adSEugenia Emantayev 				   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
436ffe455adSEugenia Emantayev 				   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
437ffe455adSEugenia Emantayev 		if (!err)
438ffe455adSEugenia Emantayev 			*index = get_param_l(&out_param);
439ffe455adSEugenia Emantayev 
440ffe455adSEugenia Emantayev 		return err;
441ffe455adSEugenia Emantayev 	}
442ffe455adSEugenia Emantayev 	return __mlx4_register_vlan(dev, port, vlan, index);
443ffe455adSEugenia Emantayev }
4445a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_register_vlan);
4455a2cc190SJeff Kirsher 
4462009d005SJack Morgenstein void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
4475a2cc190SJeff Kirsher {
4485a2cc190SJeff Kirsher 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
4492009d005SJack Morgenstein 	int index;
4502009d005SJack Morgenstein 
4512009d005SJack Morgenstein 	mutex_lock(&table->mutex);
4522009d005SJack Morgenstein 	if (mlx4_find_cached_vlan(dev, port, vlan, &index)) {
4532009d005SJack Morgenstein 		mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan);
4542009d005SJack Morgenstein 		goto out;
4552009d005SJack Morgenstein 	}
4565a2cc190SJeff Kirsher 
4575a2cc190SJeff Kirsher 	if (index < MLX4_VLAN_REGULAR) {
4585a2cc190SJeff Kirsher 		mlx4_warn(dev, "Trying to free special vlan index %d\n", index);
4595a2cc190SJeff Kirsher 		goto out;
4605a2cc190SJeff Kirsher 	}
4612009d005SJack Morgenstein 
4625a2cc190SJeff Kirsher 	if (--table->refs[index]) {
4631a91de28SJoe Perches 		mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n",
4641a91de28SJoe Perches 			 table->refs[index], index);
4655a2cc190SJeff Kirsher 		goto out;
4665a2cc190SJeff Kirsher 	}
4675a2cc190SJeff Kirsher 	table->entries[index] = 0;
4685a2cc190SJeff Kirsher 	mlx4_set_port_vlan_table(dev, port, table->entries);
4695a2cc190SJeff Kirsher 	--table->total;
4705a2cc190SJeff Kirsher out:
4715a2cc190SJeff Kirsher 	mutex_unlock(&table->mutex);
4725a2cc190SJeff Kirsher }
473ffe455adSEugenia Emantayev 
4742009d005SJack Morgenstein void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
475ffe455adSEugenia Emantayev {
476162226a1SJack Morgenstein 	u64 out_param = 0;
477ffe455adSEugenia Emantayev 
478ffe455adSEugenia Emantayev 	if (mlx4_is_mfunc(dev)) {
4792009d005SJack Morgenstein 		(void) mlx4_cmd_imm(dev, vlan, &out_param,
480acddd5ddSJack Morgenstein 				    ((u32) port) << 8 | (u32) RES_VLAN,
481162226a1SJack Morgenstein 				    RES_OP_RESERVE_AND_MAP,
482ffe455adSEugenia Emantayev 				    MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A,
483ffe455adSEugenia Emantayev 				    MLX4_CMD_WRAPPED);
484ffe455adSEugenia Emantayev 		return;
485ffe455adSEugenia Emantayev 	}
4862009d005SJack Morgenstein 	__mlx4_unregister_vlan(dev, port, vlan);
487ffe455adSEugenia Emantayev }
4885a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_unregister_vlan);
4895a2cc190SJeff Kirsher 
4905a2cc190SJeff Kirsher int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
4915a2cc190SJeff Kirsher {
4925a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
4935a2cc190SJeff Kirsher 	u8 *inbuf, *outbuf;
4945a2cc190SJeff Kirsher 	int err;
4955a2cc190SJeff Kirsher 
4965a2cc190SJeff Kirsher 	inmailbox = mlx4_alloc_cmd_mailbox(dev);
4975a2cc190SJeff Kirsher 	if (IS_ERR(inmailbox))
4985a2cc190SJeff Kirsher 		return PTR_ERR(inmailbox);
4995a2cc190SJeff Kirsher 
5005a2cc190SJeff Kirsher 	outmailbox = mlx4_alloc_cmd_mailbox(dev);
5015a2cc190SJeff Kirsher 	if (IS_ERR(outmailbox)) {
5025a2cc190SJeff Kirsher 		mlx4_free_cmd_mailbox(dev, inmailbox);
5035a2cc190SJeff Kirsher 		return PTR_ERR(outmailbox);
5045a2cc190SJeff Kirsher 	}
5055a2cc190SJeff Kirsher 
5065a2cc190SJeff Kirsher 	inbuf = inmailbox->buf;
5075a2cc190SJeff Kirsher 	outbuf = outmailbox->buf;
5085a2cc190SJeff Kirsher 	inbuf[0] = 1;
5095a2cc190SJeff Kirsher 	inbuf[1] = 1;
5105a2cc190SJeff Kirsher 	inbuf[2] = 1;
5115a2cc190SJeff Kirsher 	inbuf[3] = 1;
5125a2cc190SJeff Kirsher 	*(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015);
5135a2cc190SJeff Kirsher 	*(__be32 *) (&inbuf[20]) = cpu_to_be32(port);
5145a2cc190SJeff Kirsher 
5155a2cc190SJeff Kirsher 	err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3,
516f9baff50SJack Morgenstein 			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
517f9baff50SJack Morgenstein 			   MLX4_CMD_NATIVE);
5185a2cc190SJeff Kirsher 	if (!err)
5195a2cc190SJeff Kirsher 		*caps = *(__be32 *) (outbuf + 84);
5205a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, inmailbox);
5215a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, outmailbox);
5225a2cc190SJeff Kirsher 	return err;
5235a2cc190SJeff Kirsher }
5249cd59352SJack Morgenstein static struct mlx4_roce_gid_entry zgid_entry;
5255a2cc190SJeff Kirsher 
526449fc488SMatan Barak int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port)
527b6ffaeffSJack Morgenstein {
528449fc488SMatan Barak 	int vfs;
529449fc488SMatan Barak 	int slave_gid = slave;
530449fc488SMatan Barak 	unsigned i;
531449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
532449fc488SMatan Barak 	struct mlx4_active_ports actv_ports;
533449fc488SMatan Barak 	unsigned max_port_p_one;
534449fc488SMatan Barak 
535b6ffaeffSJack Morgenstein 	if (slave == 0)
536b6ffaeffSJack Morgenstein 		return MLX4_ROCE_PF_GIDS;
537449fc488SMatan Barak 
538449fc488SMatan Barak 	/* Slave is a VF */
539449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
540449fc488SMatan Barak 	actv_ports = mlx4_get_active_ports(dev, slave);
541449fc488SMatan Barak 	max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
542449fc488SMatan Barak 		bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
543449fc488SMatan Barak 
544449fc488SMatan Barak 	for (i = 1; i < max_port_p_one; i++) {
545449fc488SMatan Barak 		struct mlx4_active_ports exclusive_ports;
546449fc488SMatan Barak 		struct mlx4_slaves_pport slaves_pport_actv;
547449fc488SMatan Barak 		bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
548449fc488SMatan Barak 		set_bit(i - 1, exclusive_ports.ports);
549449fc488SMatan Barak 		if (i == port)
550449fc488SMatan Barak 			continue;
551449fc488SMatan Barak 		slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
552449fc488SMatan Barak 				    dev, &exclusive_ports);
553449fc488SMatan Barak 		slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
554872bf2fbSYishai Hadas 					   dev->persist->num_vfs + 1);
555449fc488SMatan Barak 	}
556872bf2fbSYishai Hadas 	vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1;
557449fc488SMatan Barak 	if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs))
558449fc488SMatan Barak 		return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1;
559449fc488SMatan Barak 	return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs;
560b6ffaeffSJack Morgenstein }
561b6ffaeffSJack Morgenstein 
562449fc488SMatan Barak int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port)
563b6ffaeffSJack Morgenstein {
564b6ffaeffSJack Morgenstein 	int gids;
565449fc488SMatan Barak 	unsigned i;
566449fc488SMatan Barak 	int slave_gid = slave;
567b6ffaeffSJack Morgenstein 	int vfs;
568b6ffaeffSJack Morgenstein 
569449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
570449fc488SMatan Barak 	struct mlx4_active_ports actv_ports;
571449fc488SMatan Barak 	unsigned max_port_p_one;
572b6ffaeffSJack Morgenstein 
573b6ffaeffSJack Morgenstein 	if (slave == 0)
574b6ffaeffSJack Morgenstein 		return 0;
575b6ffaeffSJack Morgenstein 
576449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
577449fc488SMatan Barak 	actv_ports = mlx4_get_active_ports(dev, slave);
578449fc488SMatan Barak 	max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
579449fc488SMatan Barak 		bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
580449fc488SMatan Barak 
581449fc488SMatan Barak 	for (i = 1; i < max_port_p_one; i++) {
582449fc488SMatan Barak 		struct mlx4_active_ports exclusive_ports;
583449fc488SMatan Barak 		struct mlx4_slaves_pport slaves_pport_actv;
584449fc488SMatan Barak 		bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
585449fc488SMatan Barak 		set_bit(i - 1, exclusive_ports.ports);
586449fc488SMatan Barak 		if (i == port)
587449fc488SMatan Barak 			continue;
588449fc488SMatan Barak 		slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
589449fc488SMatan Barak 				    dev, &exclusive_ports);
590449fc488SMatan Barak 		slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
591872bf2fbSYishai Hadas 					   dev->persist->num_vfs + 1);
592b6ffaeffSJack Morgenstein 	}
593449fc488SMatan Barak 	gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
594872bf2fbSYishai Hadas 	vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1;
595449fc488SMatan Barak 	if (slave_gid <= gids % vfs)
596449fc488SMatan Barak 		return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1);
597449fc488SMatan Barak 
598449fc488SMatan Barak 	return MLX4_ROCE_PF_GIDS + (gids % vfs) +
599449fc488SMatan Barak 		((gids / vfs) * (slave_gid - 1));
600449fc488SMatan Barak }
601449fc488SMatan Barak EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix);
602b6ffaeffSJack Morgenstein 
603111c6094SJack Morgenstein static int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave,
604111c6094SJack Morgenstein 				     int port, struct mlx4_cmd_mailbox *mailbox)
605111c6094SJack Morgenstein {
606111c6094SJack Morgenstein 	struct mlx4_roce_gid_entry *gid_entry_mbox;
607111c6094SJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
608111c6094SJack Morgenstein 	int num_gids, base, offset;
609111c6094SJack Morgenstein 	int i, err;
610111c6094SJack Morgenstein 
611111c6094SJack Morgenstein 	num_gids = mlx4_get_slave_num_gids(dev, slave, port);
612111c6094SJack Morgenstein 	base = mlx4_get_base_gid_ix(dev, slave, port);
613111c6094SJack Morgenstein 
614111c6094SJack Morgenstein 	memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE);
615111c6094SJack Morgenstein 
616111c6094SJack Morgenstein 	mutex_lock(&(priv->port[port].gid_table.mutex));
617111c6094SJack Morgenstein 	/* Zero-out gids belonging to that slave in the port GID table */
618111c6094SJack Morgenstein 	for (i = 0, offset = base; i < num_gids; offset++, i++)
619111c6094SJack Morgenstein 		memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
620111c6094SJack Morgenstein 		       zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE);
621111c6094SJack Morgenstein 
622111c6094SJack Morgenstein 	/* Now, copy roce port gids table to mailbox for passing to FW */
623111c6094SJack Morgenstein 	gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf;
624111c6094SJack Morgenstein 	for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
625111c6094SJack Morgenstein 		memcpy(gid_entry_mbox->raw,
626111c6094SJack Morgenstein 		       priv->port[port].gid_table.roce_gids[i].raw,
627111c6094SJack Morgenstein 		       MLX4_ROCE_GID_ENTRY_SIZE);
628111c6094SJack Morgenstein 
629111c6094SJack Morgenstein 	err = mlx4_cmd(dev, mailbox->dma,
630a130b590SIdo Shamay 		       ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8),
631a130b590SIdo Shamay 		       MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT,
632a130b590SIdo Shamay 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
633111c6094SJack Morgenstein 	mutex_unlock(&(priv->port[port].gid_table.mutex));
634111c6094SJack Morgenstein 	return err;
635111c6094SJack Morgenstein }
636111c6094SJack Morgenstein 
637111c6094SJack Morgenstein 
638111c6094SJack Morgenstein void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave)
639111c6094SJack Morgenstein {
640111c6094SJack Morgenstein 	struct mlx4_active_ports actv_ports;
641111c6094SJack Morgenstein 	struct mlx4_cmd_mailbox *mailbox;
642111c6094SJack Morgenstein 	int num_eth_ports, err;
643111c6094SJack Morgenstein 	int i;
644111c6094SJack Morgenstein 
645872bf2fbSYishai Hadas 	if (slave < 0 || slave > dev->persist->num_vfs)
646111c6094SJack Morgenstein 		return;
647111c6094SJack Morgenstein 
648111c6094SJack Morgenstein 	actv_ports = mlx4_get_active_ports(dev, slave);
649111c6094SJack Morgenstein 
650111c6094SJack Morgenstein 	for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) {
651111c6094SJack Morgenstein 		if (test_bit(i, actv_ports.ports)) {
652111c6094SJack Morgenstein 			if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
653111c6094SJack Morgenstein 				continue;
654111c6094SJack Morgenstein 			num_eth_ports++;
655111c6094SJack Morgenstein 		}
656111c6094SJack Morgenstein 	}
657111c6094SJack Morgenstein 
658111c6094SJack Morgenstein 	if (!num_eth_ports)
659111c6094SJack Morgenstein 		return;
660111c6094SJack Morgenstein 
661111c6094SJack Morgenstein 	/* have ETH ports.  Alloc mailbox for SET_PORT command */
662111c6094SJack Morgenstein 	mailbox = mlx4_alloc_cmd_mailbox(dev);
663111c6094SJack Morgenstein 	if (IS_ERR(mailbox))
664111c6094SJack Morgenstein 		return;
665111c6094SJack Morgenstein 
666111c6094SJack Morgenstein 	for (i = 0; i < dev->caps.num_ports; i++) {
667111c6094SJack Morgenstein 		if (test_bit(i, actv_ports.ports)) {
668111c6094SJack Morgenstein 			if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
669111c6094SJack Morgenstein 				continue;
670111c6094SJack Morgenstein 			err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox);
671111c6094SJack Morgenstein 			if (err)
672111c6094SJack Morgenstein 				mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n",
673111c6094SJack Morgenstein 					  slave, i + 1, err);
674111c6094SJack Morgenstein 		}
675111c6094SJack Morgenstein 	}
676111c6094SJack Morgenstein 
677111c6094SJack Morgenstein 	mlx4_free_cmd_mailbox(dev, mailbox);
678111c6094SJack Morgenstein 	return;
679111c6094SJack Morgenstein }
680111c6094SJack Morgenstein 
681ffe455adSEugenia Emantayev static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
682ffe455adSEugenia Emantayev 				u8 op_mod, struct mlx4_cmd_mailbox *inbox)
683ffe455adSEugenia Emantayev {
684ffe455adSEugenia Emantayev 	struct mlx4_priv *priv = mlx4_priv(dev);
685ffe455adSEugenia Emantayev 	struct mlx4_port_info *port_info;
686ffe455adSEugenia Emantayev 	struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
687ffe455adSEugenia Emantayev 	struct mlx4_slave_state *slave_st = &master->slave_state[slave];
688ffe455adSEugenia Emantayev 	struct mlx4_set_port_rqp_calc_context *qpn_context;
689ffe455adSEugenia Emantayev 	struct mlx4_set_port_general_context *gen_context;
690b6ffaeffSJack Morgenstein 	struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1;
691ffe455adSEugenia Emantayev 	int reset_qkey_viols;
692ffe455adSEugenia Emantayev 	int port;
693ffe455adSEugenia Emantayev 	int is_eth;
694b6ffaeffSJack Morgenstein 	int num_gids;
695b6ffaeffSJack Morgenstein 	int base;
696ffe455adSEugenia Emantayev 	u32 in_modifier;
697ffe455adSEugenia Emantayev 	u32 promisc;
698ffe455adSEugenia Emantayev 	u16 mtu, prev_mtu;
699ffe455adSEugenia Emantayev 	int err;
700b6ffaeffSJack Morgenstein 	int i, j;
701b6ffaeffSJack Morgenstein 	int offset;
702ffe455adSEugenia Emantayev 	__be32 agg_cap_mask;
703ffe455adSEugenia Emantayev 	__be32 slave_cap_mask;
704ffe455adSEugenia Emantayev 	__be32 new_cap_mask;
705ffe455adSEugenia Emantayev 
706ffe455adSEugenia Emantayev 	port = in_mod & 0xff;
707ffe455adSEugenia Emantayev 	in_modifier = in_mod >> 8;
708ffe455adSEugenia Emantayev 	is_eth = op_mod;
709ffe455adSEugenia Emantayev 	port_info = &priv->port[port];
710ffe455adSEugenia Emantayev 
711ffe455adSEugenia Emantayev 	/* Slaves cannot perform SET_PORT operations except changing MTU */
712ffe455adSEugenia Emantayev 	if (is_eth) {
713ffe455adSEugenia Emantayev 		if (slave != dev->caps.function &&
7149cd59352SJack Morgenstein 		    in_modifier != MLX4_SET_PORT_GENERAL &&
7159cd59352SJack Morgenstein 		    in_modifier != MLX4_SET_PORT_GID_TABLE) {
716ffe455adSEugenia Emantayev 			mlx4_warn(dev, "denying SET_PORT for slave:%d\n",
717ffe455adSEugenia Emantayev 					slave);
718ffe455adSEugenia Emantayev 			return -EINVAL;
719ffe455adSEugenia Emantayev 		}
720ffe455adSEugenia Emantayev 		switch (in_modifier) {
721ffe455adSEugenia Emantayev 		case MLX4_SET_PORT_RQP_CALC:
722ffe455adSEugenia Emantayev 			qpn_context = inbox->buf;
723ffe455adSEugenia Emantayev 			qpn_context->base_qpn =
724ffe455adSEugenia Emantayev 				cpu_to_be32(port_info->base_qpn);
725ffe455adSEugenia Emantayev 			qpn_context->n_mac = 0x7;
726ffe455adSEugenia Emantayev 			promisc = be32_to_cpu(qpn_context->promisc) >>
727ffe455adSEugenia Emantayev 				SET_PORT_PROMISC_SHIFT;
728ffe455adSEugenia Emantayev 			qpn_context->promisc = cpu_to_be32(
729ffe455adSEugenia Emantayev 				promisc << SET_PORT_PROMISC_SHIFT |
730ffe455adSEugenia Emantayev 				port_info->base_qpn);
731ffe455adSEugenia Emantayev 			promisc = be32_to_cpu(qpn_context->mcast) >>
732ffe455adSEugenia Emantayev 				SET_PORT_MC_PROMISC_SHIFT;
733ffe455adSEugenia Emantayev 			qpn_context->mcast = cpu_to_be32(
734ffe455adSEugenia Emantayev 				promisc << SET_PORT_MC_PROMISC_SHIFT |
735ffe455adSEugenia Emantayev 				port_info->base_qpn);
736ffe455adSEugenia Emantayev 			break;
737ffe455adSEugenia Emantayev 		case MLX4_SET_PORT_GENERAL:
738ffe455adSEugenia Emantayev 			gen_context = inbox->buf;
739ffe455adSEugenia Emantayev 			/* Mtu is configured as the max MTU among all the
740ffe455adSEugenia Emantayev 			 * the functions on the port. */
741ffe455adSEugenia Emantayev 			mtu = be16_to_cpu(gen_context->mtu);
742c59fec20SEugenia Emantayev 			mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] +
743c59fec20SEugenia Emantayev 				    ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
744ffe455adSEugenia Emantayev 			prev_mtu = slave_st->mtu[port];
745ffe455adSEugenia Emantayev 			slave_st->mtu[port] = mtu;
746ffe455adSEugenia Emantayev 			if (mtu > master->max_mtu[port])
747ffe455adSEugenia Emantayev 				master->max_mtu[port] = mtu;
748ffe455adSEugenia Emantayev 			if (mtu < prev_mtu && prev_mtu ==
749ffe455adSEugenia Emantayev 						master->max_mtu[port]) {
750ffe455adSEugenia Emantayev 				slave_st->mtu[port] = mtu;
751ffe455adSEugenia Emantayev 				master->max_mtu[port] = mtu;
752ffe455adSEugenia Emantayev 				for (i = 0; i < dev->num_slaves; i++) {
753ffe455adSEugenia Emantayev 					master->max_mtu[port] =
754ffe455adSEugenia Emantayev 					max(master->max_mtu[port],
755ffe455adSEugenia Emantayev 					    master->slave_state[i].mtu[port]);
756ffe455adSEugenia Emantayev 				}
757ffe455adSEugenia Emantayev 			}
758ffe455adSEugenia Emantayev 
759ffe455adSEugenia Emantayev 			gen_context->mtu = cpu_to_be16(master->max_mtu[port]);
760ffe455adSEugenia Emantayev 			break;
7619cd59352SJack Morgenstein 		case MLX4_SET_PORT_GID_TABLE:
762b6ffaeffSJack Morgenstein 			/* change to MULTIPLE entries: number of guest's gids
763b6ffaeffSJack Morgenstein 			 * need a FOR-loop here over number of gids the guest has.
764b6ffaeffSJack Morgenstein 			 * 1. Check no duplicates in gids passed by slave
765b6ffaeffSJack Morgenstein 			 */
766449fc488SMatan Barak 			num_gids = mlx4_get_slave_num_gids(dev, slave, port);
767449fc488SMatan Barak 			base = mlx4_get_base_gid_ix(dev, slave, port);
768b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
769b6ffaeffSJack Morgenstein 			for (i = 0; i < num_gids; gid_entry_mbox++, i++) {
770b6ffaeffSJack Morgenstein 				if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
771b6ffaeffSJack Morgenstein 					    sizeof(zgid_entry)))
772b6ffaeffSJack Morgenstein 					continue;
773b6ffaeffSJack Morgenstein 				gid_entry_mb1 = gid_entry_mbox + 1;
774b6ffaeffSJack Morgenstein 				for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) {
775b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mb1->raw,
776b6ffaeffSJack Morgenstein 						    zgid_entry.raw, sizeof(zgid_entry)))
777b6ffaeffSJack Morgenstein 						continue;
778b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw,
779b6ffaeffSJack Morgenstein 						    sizeof(gid_entry_mbox->raw))) {
780b6ffaeffSJack Morgenstein 						/* found duplicate */
781b6ffaeffSJack Morgenstein 						return -EINVAL;
782b6ffaeffSJack Morgenstein 					}
783b6ffaeffSJack Morgenstein 				}
784b6ffaeffSJack Morgenstein 			}
785b6ffaeffSJack Morgenstein 
786b6ffaeffSJack Morgenstein 			/* 2. Check that do not have duplicates in OTHER
787b6ffaeffSJack Morgenstein 			 *    entries in the port GID table
788b6ffaeffSJack Morgenstein 			 */
789111c6094SJack Morgenstein 
790111c6094SJack Morgenstein 			mutex_lock(&(priv->port[port].gid_table.mutex));
7919cd59352SJack Morgenstein 			for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
792b6ffaeffSJack Morgenstein 				if (i >= base && i < base + num_gids)
793b6ffaeffSJack Morgenstein 					continue; /* don't compare to slave's current gids */
794111c6094SJack Morgenstein 				gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i];
795b6ffaeffSJack Morgenstein 				if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry)))
796b6ffaeffSJack Morgenstein 					continue;
797b6ffaeffSJack Morgenstein 				gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
798b6ffaeffSJack Morgenstein 				for (j = 0; j < num_gids; gid_entry_mbox++, j++) {
799b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
800b6ffaeffSJack Morgenstein 						    sizeof(zgid_entry)))
801b6ffaeffSJack Morgenstein 						continue;
802b6ffaeffSJack Morgenstein 					if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw,
803b6ffaeffSJack Morgenstein 						    sizeof(gid_entry_tbl->raw))) {
804b6ffaeffSJack Morgenstein 						/* found duplicate */
8051a91de28SJoe Perches 						mlx4_warn(dev, "requested gid entry for slave:%d is a duplicate of gid at index %d\n",
8069cd59352SJack Morgenstein 							  slave, i);
807111c6094SJack Morgenstein 						mutex_unlock(&(priv->port[port].gid_table.mutex));
808b6ffaeffSJack Morgenstein 						return -EINVAL;
8099cd59352SJack Morgenstein 					}
8109cd59352SJack Morgenstein 				}
8119cd59352SJack Morgenstein 			}
812b6ffaeffSJack Morgenstein 
813b6ffaeffSJack Morgenstein 			/* insert slave GIDs with memcpy, starting at slave's base index */
814b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
815b6ffaeffSJack Morgenstein 			for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++)
816111c6094SJack Morgenstein 				memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
817111c6094SJack Morgenstein 				       gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE);
818b6ffaeffSJack Morgenstein 
819b6ffaeffSJack Morgenstein 			/* Now, copy roce port gids table to current mailbox for passing to FW */
820b6ffaeffSJack Morgenstein 			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
821b6ffaeffSJack Morgenstein 			for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
822111c6094SJack Morgenstein 				memcpy(gid_entry_mbox->raw,
823111c6094SJack Morgenstein 				       priv->port[port].gid_table.roce_gids[i].raw,
824111c6094SJack Morgenstein 				       MLX4_ROCE_GID_ENTRY_SIZE);
825b6ffaeffSJack Morgenstein 
826111c6094SJack Morgenstein 			err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
827111c6094SJack Morgenstein 				       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
828111c6094SJack Morgenstein 				       MLX4_CMD_NATIVE);
829111c6094SJack Morgenstein 			mutex_unlock(&(priv->port[port].gid_table.mutex));
830111c6094SJack Morgenstein 			return err;
831ffe455adSEugenia Emantayev 		}
832111c6094SJack Morgenstein 
833111c6094SJack Morgenstein 		return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
834ffe455adSEugenia Emantayev 				MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
835ffe455adSEugenia Emantayev 				MLX4_CMD_NATIVE);
836ffe455adSEugenia Emantayev 	}
837ffe455adSEugenia Emantayev 
838ffe455adSEugenia Emantayev 	/* For IB, we only consider:
839ffe455adSEugenia Emantayev 	 * - The capability mask, which is set to the aggregate of all
840ffe455adSEugenia Emantayev 	 *   slave function capabilities
841ffe455adSEugenia Emantayev 	 * - The QKey violatin counter - reset according to each request.
842ffe455adSEugenia Emantayev 	 */
843ffe455adSEugenia Emantayev 
844ffe455adSEugenia Emantayev 	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
845ffe455adSEugenia Emantayev 		reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40;
846ffe455adSEugenia Emantayev 		new_cap_mask = ((__be32 *) inbox->buf)[2];
847ffe455adSEugenia Emantayev 	} else {
848ffe455adSEugenia Emantayev 		reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1;
849ffe455adSEugenia Emantayev 		new_cap_mask = ((__be32 *) inbox->buf)[1];
850ffe455adSEugenia Emantayev 	}
851ffe455adSEugenia Emantayev 
852efcd235dSJack Morgenstein 	/* slave may not set the IS_SM capability for the port */
853efcd235dSJack Morgenstein 	if (slave != mlx4_master_func_num(dev) &&
854efcd235dSJack Morgenstein 	    (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM))
855efcd235dSJack Morgenstein 		return -EINVAL;
856efcd235dSJack Morgenstein 
857efcd235dSJack Morgenstein 	/* No DEV_MGMT in multifunc mode */
858efcd235dSJack Morgenstein 	if (mlx4_is_mfunc(dev) &&
859efcd235dSJack Morgenstein 	    (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP))
860efcd235dSJack Morgenstein 		return -EINVAL;
861efcd235dSJack Morgenstein 
862ffe455adSEugenia Emantayev 	agg_cap_mask = 0;
863ffe455adSEugenia Emantayev 	slave_cap_mask =
864ffe455adSEugenia Emantayev 		priv->mfunc.master.slave_state[slave].ib_cap_mask[port];
865ffe455adSEugenia Emantayev 	priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask;
866ffe455adSEugenia Emantayev 	for (i = 0; i < dev->num_slaves; i++)
867ffe455adSEugenia Emantayev 		agg_cap_mask |=
868ffe455adSEugenia Emantayev 			priv->mfunc.master.slave_state[i].ib_cap_mask[port];
869ffe455adSEugenia Emantayev 
870ffe455adSEugenia Emantayev 	/* only clear mailbox for guests.  Master may be setting
871ffe455adSEugenia Emantayev 	* MTU or PKEY table size
872ffe455adSEugenia Emantayev 	*/
873ffe455adSEugenia Emantayev 	if (slave != dev->caps.function)
874ffe455adSEugenia Emantayev 		memset(inbox->buf, 0, 256);
875ffe455adSEugenia Emantayev 	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
876edc4a67eSJack Morgenstein 		*(u8 *) inbox->buf	   |= !!reset_qkey_viols << 6;
877ffe455adSEugenia Emantayev 		((__be32 *) inbox->buf)[2] = agg_cap_mask;
878ffe455adSEugenia Emantayev 	} else {
879edc4a67eSJack Morgenstein 		((u8 *) inbox->buf)[3]     |= !!reset_qkey_viols;
880ffe455adSEugenia Emantayev 		((__be32 *) inbox->buf)[1] = agg_cap_mask;
881ffe455adSEugenia Emantayev 	}
882ffe455adSEugenia Emantayev 
883ffe455adSEugenia Emantayev 	err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT,
884ffe455adSEugenia Emantayev 		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
885ffe455adSEugenia Emantayev 	if (err)
886ffe455adSEugenia Emantayev 		priv->mfunc.master.slave_state[slave].ib_cap_mask[port] =
887ffe455adSEugenia Emantayev 			slave_cap_mask;
888ffe455adSEugenia Emantayev 	return err;
889ffe455adSEugenia Emantayev }
890ffe455adSEugenia Emantayev 
891ffe455adSEugenia Emantayev int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave,
892ffe455adSEugenia Emantayev 			  struct mlx4_vhcr *vhcr,
893ffe455adSEugenia Emantayev 			  struct mlx4_cmd_mailbox *inbox,
894ffe455adSEugenia Emantayev 			  struct mlx4_cmd_mailbox *outbox,
895ffe455adSEugenia Emantayev 			  struct mlx4_cmd_info *cmd)
896ffe455adSEugenia Emantayev {
897449fc488SMatan Barak 	int port = mlx4_slave_convert_port(
898449fc488SMatan Barak 			dev, slave, vhcr->in_modifier & 0xFF);
899449fc488SMatan Barak 
900449fc488SMatan Barak 	if (port < 0)
901449fc488SMatan Barak 		return -EINVAL;
902449fc488SMatan Barak 
903449fc488SMatan Barak 	vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) |
904449fc488SMatan Barak 			    (port & 0xFF);
905449fc488SMatan Barak 
906ffe455adSEugenia Emantayev 	return mlx4_common_set_port(dev, slave, vhcr->in_modifier,
907ffe455adSEugenia Emantayev 				    vhcr->op_modifier, inbox);
908ffe455adSEugenia Emantayev }
909ffe455adSEugenia Emantayev 
910096335b3SOr Gerlitz /* bit locations for set port command with zero op modifier */
911096335b3SOr Gerlitz enum {
912096335b3SOr Gerlitz 	MLX4_SET_PORT_VL_CAP	 = 4, /* bits 7:4 */
913096335b3SOr Gerlitz 	MLX4_SET_PORT_MTU_CAP	 = 12, /* bits 15:12 */
9146634961cSJack Morgenstein 	MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20,
915096335b3SOr Gerlitz 	MLX4_CHANGE_PORT_VL_CAP	 = 21,
916096335b3SOr Gerlitz 	MLX4_CHANGE_PORT_MTU_CAP = 22,
917096335b3SOr Gerlitz };
918096335b3SOr Gerlitz 
9196634961cSJack Morgenstein int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz)
9205a2cc190SJeff Kirsher {
9215a2cc190SJeff Kirsher 	struct mlx4_cmd_mailbox *mailbox;
9226634961cSJack Morgenstein 	int err, vl_cap, pkey_tbl_flag = 0;
9235a2cc190SJeff Kirsher 
9245a2cc190SJeff Kirsher 	if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
9255a2cc190SJeff Kirsher 		return 0;
9265a2cc190SJeff Kirsher 
9275a2cc190SJeff Kirsher 	mailbox = mlx4_alloc_cmd_mailbox(dev);
9285a2cc190SJeff Kirsher 	if (IS_ERR(mailbox))
9295a2cc190SJeff Kirsher 		return PTR_ERR(mailbox);
9305a2cc190SJeff Kirsher 
9315a2cc190SJeff Kirsher 	((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port];
932096335b3SOr Gerlitz 
9336634961cSJack Morgenstein 	if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) {
9346634961cSJack Morgenstein 		pkey_tbl_flag = 1;
9356634961cSJack Morgenstein 		((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz);
9366634961cSJack Morgenstein 	}
9376634961cSJack Morgenstein 
938096335b3SOr Gerlitz 	/* IB VL CAP enum isn't used by the firmware, just numerical values */
939096335b3SOr Gerlitz 	for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) {
940096335b3SOr Gerlitz 		((__be32 *) mailbox->buf)[0] = cpu_to_be32(
941096335b3SOr Gerlitz 			(1 << MLX4_CHANGE_PORT_MTU_CAP) |
942096335b3SOr Gerlitz 			(1 << MLX4_CHANGE_PORT_VL_CAP)  |
9436634961cSJack Morgenstein 			(pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) |
944096335b3SOr Gerlitz 			(dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) |
945096335b3SOr Gerlitz 			(vl_cap << MLX4_SET_PORT_VL_CAP));
946a130b590SIdo Shamay 		err = mlx4_cmd(dev, mailbox->dma, port,
947a130b590SIdo Shamay 			       MLX4_SET_PORT_IB_OPCODE, MLX4_CMD_SET_PORT,
948f9baff50SJack Morgenstein 			       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
949096335b3SOr Gerlitz 		if (err != -ENOMEM)
950096335b3SOr Gerlitz 			break;
951096335b3SOr Gerlitz 	}
9525a2cc190SJeff Kirsher 
9535a2cc190SJeff Kirsher 	mlx4_free_cmd_mailbox(dev, mailbox);
9545a2cc190SJeff Kirsher 	return err;
9555a2cc190SJeff Kirsher }
956ffe455adSEugenia Emantayev 
957cb9ffb76SJoerg Roedel int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
958ffe455adSEugenia Emantayev 			  u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx)
959ffe455adSEugenia Emantayev {
960ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
961ffe455adSEugenia Emantayev 	struct mlx4_set_port_general_context *context;
962ffe455adSEugenia Emantayev 	int err;
963ffe455adSEugenia Emantayev 	u32 in_mod;
964ffe455adSEugenia Emantayev 
965ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
966ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
967ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
968ffe455adSEugenia Emantayev 	context = mailbox->buf;
969ffe455adSEugenia Emantayev 	context->flags = SET_PORT_GEN_ALL_VALID;
970ffe455adSEugenia Emantayev 	context->mtu = cpu_to_be16(mtu);
971ffe455adSEugenia Emantayev 	context->pptx = (pptx * (!pfctx)) << 7;
972ffe455adSEugenia Emantayev 	context->pfctx = pfctx;
973ffe455adSEugenia Emantayev 	context->pprx = (pprx * (!pfcrx)) << 7;
974ffe455adSEugenia Emantayev 	context->pfcrx = pfcrx;
975ffe455adSEugenia Emantayev 
976ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
977a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
978a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
979a130b590SIdo Shamay 		       MLX4_CMD_WRAPPED);
980ffe455adSEugenia Emantayev 
981ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
982ffe455adSEugenia Emantayev 	return err;
983ffe455adSEugenia Emantayev }
984ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_general);
985ffe455adSEugenia Emantayev 
986cb9ffb76SJoerg Roedel int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
987ffe455adSEugenia Emantayev 			   u8 promisc)
988ffe455adSEugenia Emantayev {
989ffe455adSEugenia Emantayev 	struct mlx4_cmd_mailbox *mailbox;
990ffe455adSEugenia Emantayev 	struct mlx4_set_port_rqp_calc_context *context;
991ffe455adSEugenia Emantayev 	int err;
992ffe455adSEugenia Emantayev 	u32 in_mod;
993ffe455adSEugenia Emantayev 	u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ?
994ffe455adSEugenia Emantayev 		MCAST_DIRECT : MCAST_DEFAULT;
995ffe455adSEugenia Emantayev 
996c96d97f4SHadar Hen Zion 	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
997ffe455adSEugenia Emantayev 		return 0;
998ffe455adSEugenia Emantayev 
999ffe455adSEugenia Emantayev 	mailbox = mlx4_alloc_cmd_mailbox(dev);
1000ffe455adSEugenia Emantayev 	if (IS_ERR(mailbox))
1001ffe455adSEugenia Emantayev 		return PTR_ERR(mailbox);
1002ffe455adSEugenia Emantayev 	context = mailbox->buf;
1003ffe455adSEugenia Emantayev 	context->base_qpn = cpu_to_be32(base_qpn);
1004ffe455adSEugenia Emantayev 	context->n_mac = dev->caps.log_num_macs;
1005ffe455adSEugenia Emantayev 	context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT |
1006ffe455adSEugenia Emantayev 				       base_qpn);
1007ffe455adSEugenia Emantayev 	context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT |
1008ffe455adSEugenia Emantayev 				     base_qpn);
1009ffe455adSEugenia Emantayev 	context->intra_no_vlan = 0;
1010ffe455adSEugenia Emantayev 	context->no_vlan = MLX4_NO_VLAN_IDX;
1011ffe455adSEugenia Emantayev 	context->intra_vlan_miss = 0;
1012ffe455adSEugenia Emantayev 	context->vlan_miss = MLX4_VLAN_MISS_IDX;
1013ffe455adSEugenia Emantayev 
1014ffe455adSEugenia Emantayev 	in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port;
1015a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1016a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1017a130b590SIdo Shamay 		       MLX4_CMD_WRAPPED);
1018ffe455adSEugenia Emantayev 
1019ffe455adSEugenia Emantayev 	mlx4_free_cmd_mailbox(dev, mailbox);
1020ffe455adSEugenia Emantayev 	return err;
1021ffe455adSEugenia Emantayev }
1022ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc);
1023ffe455adSEugenia Emantayev 
10247ffdf726SOr Gerlitz enum {
10257ffdf726SOr Gerlitz 	VXLAN_ENABLE_MODIFY	= 1 << 7,
10267ffdf726SOr Gerlitz 	VXLAN_STEERING_MODIFY	= 1 << 6,
10277ffdf726SOr Gerlitz 
10287ffdf726SOr Gerlitz 	VXLAN_ENABLE		= 1 << 7,
10297ffdf726SOr Gerlitz };
10307ffdf726SOr Gerlitz 
10317ffdf726SOr Gerlitz struct mlx4_set_port_vxlan_context {
10327ffdf726SOr Gerlitz 	u32	reserved1;
10337ffdf726SOr Gerlitz 	u8	modify_flags;
10347ffdf726SOr Gerlitz 	u8	reserved2;
10357ffdf726SOr Gerlitz 	u8	enable_flags;
10367ffdf726SOr Gerlitz 	u8	steering;
10377ffdf726SOr Gerlitz };
10387ffdf726SOr Gerlitz 
10391b136de1SOr Gerlitz int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable)
10407ffdf726SOr Gerlitz {
10417ffdf726SOr Gerlitz 	int err;
10427ffdf726SOr Gerlitz 	u32 in_mod;
10437ffdf726SOr Gerlitz 	struct mlx4_cmd_mailbox *mailbox;
10447ffdf726SOr Gerlitz 	struct mlx4_set_port_vxlan_context  *context;
10457ffdf726SOr Gerlitz 
10467ffdf726SOr Gerlitz 	mailbox = mlx4_alloc_cmd_mailbox(dev);
10477ffdf726SOr Gerlitz 	if (IS_ERR(mailbox))
10487ffdf726SOr Gerlitz 		return PTR_ERR(mailbox);
10497ffdf726SOr Gerlitz 	context = mailbox->buf;
10507ffdf726SOr Gerlitz 	memset(context, 0, sizeof(*context));
10517ffdf726SOr Gerlitz 
10527ffdf726SOr Gerlitz 	context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY;
10531b136de1SOr Gerlitz 	if (enable)
10547ffdf726SOr Gerlitz 		context->enable_flags = VXLAN_ENABLE;
10557ffdf726SOr Gerlitz 	context->steering  = steering;
10567ffdf726SOr Gerlitz 
10577ffdf726SOr Gerlitz 	in_mod = MLX4_SET_PORT_VXLAN << 8 | port;
1058a130b590SIdo Shamay 	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1059a130b590SIdo Shamay 		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1060a130b590SIdo Shamay 		       MLX4_CMD_NATIVE);
10617ffdf726SOr Gerlitz 
10627ffdf726SOr Gerlitz 	mlx4_free_cmd_mailbox(dev, mailbox);
10637ffdf726SOr Gerlitz 	return err;
10647ffdf726SOr Gerlitz }
10657ffdf726SOr Gerlitz EXPORT_SYMBOL(mlx4_SET_PORT_VXLAN);
10667ffdf726SOr Gerlitz 
1067ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1068ffe455adSEugenia Emantayev 				struct mlx4_vhcr *vhcr,
1069ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *inbox,
1070ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *outbox,
1071ffe455adSEugenia Emantayev 				struct mlx4_cmd_info *cmd)
1072ffe455adSEugenia Emantayev {
1073ffe455adSEugenia Emantayev 	int err = 0;
1074ffe455adSEugenia Emantayev 
1075ffe455adSEugenia Emantayev 	return err;
1076ffe455adSEugenia Emantayev }
1077ffe455adSEugenia Emantayev 
1078ffe455adSEugenia Emantayev int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port,
1079ffe455adSEugenia Emantayev 			u64 mac, u64 clear, u8 mode)
1080ffe455adSEugenia Emantayev {
1081ffe455adSEugenia Emantayev 	return mlx4_cmd(dev, (mac | (clear << 63)), port, mode,
1082ffe455adSEugenia Emantayev 			MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B,
1083ffe455adSEugenia Emantayev 			MLX4_CMD_WRAPPED);
1084ffe455adSEugenia Emantayev }
1085ffe455adSEugenia Emantayev EXPORT_SYMBOL(mlx4_SET_MCAST_FLTR);
1086ffe455adSEugenia Emantayev 
1087ffe455adSEugenia Emantayev int mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1088ffe455adSEugenia Emantayev 			       struct mlx4_vhcr *vhcr,
1089ffe455adSEugenia Emantayev 			       struct mlx4_cmd_mailbox *inbox,
1090ffe455adSEugenia Emantayev 			       struct mlx4_cmd_mailbox *outbox,
1091ffe455adSEugenia Emantayev 			       struct mlx4_cmd_info *cmd)
1092ffe455adSEugenia Emantayev {
1093ffe455adSEugenia Emantayev 	int err = 0;
1094ffe455adSEugenia Emantayev 
1095ffe455adSEugenia Emantayev 	return err;
1096ffe455adSEugenia Emantayev }
1097ffe455adSEugenia Emantayev 
1098ffe455adSEugenia Emantayev int mlx4_common_dump_eth_stats(struct mlx4_dev *dev, int slave,
1099ffe455adSEugenia Emantayev 			       u32 in_mod, struct mlx4_cmd_mailbox *outbox)
1100ffe455adSEugenia Emantayev {
1101ffe455adSEugenia Emantayev 	return mlx4_cmd_box(dev, 0, outbox->dma, in_mod, 0,
1102ffe455adSEugenia Emantayev 			    MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B,
1103ffe455adSEugenia Emantayev 			    MLX4_CMD_NATIVE);
1104ffe455adSEugenia Emantayev }
1105ffe455adSEugenia Emantayev 
1106ffe455adSEugenia Emantayev int mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave,
1107ffe455adSEugenia Emantayev 				struct mlx4_vhcr *vhcr,
1108ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *inbox,
1109ffe455adSEugenia Emantayev 				struct mlx4_cmd_mailbox *outbox,
1110ffe455adSEugenia Emantayev 				struct mlx4_cmd_info *cmd)
1111ffe455adSEugenia Emantayev {
111235fb9afbSEugenia Emantayev 	if (slave != dev->caps.function)
111335fb9afbSEugenia Emantayev 		return 0;
1114ffe455adSEugenia Emantayev 	return mlx4_common_dump_eth_stats(dev, slave,
1115ffe455adSEugenia Emantayev 					  vhcr->in_modifier, outbox);
1116ffe455adSEugenia Emantayev }
111793ece0c1SEugenia Emantayev 
11189cd59352SJack Morgenstein int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
11199cd59352SJack Morgenstein 				 int *slave_id)
11206ee51a4eSJack Morgenstein {
11216ee51a4eSJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
11226ee51a4eSJack Morgenstein 	int i, found_ix = -1;
1123b6ffaeffSJack Morgenstein 	int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
1124449fc488SMatan Barak 	struct mlx4_slaves_pport slaves_pport;
1125449fc488SMatan Barak 	unsigned num_vfs;
1126449fc488SMatan Barak 	int slave_gid;
11276ee51a4eSJack Morgenstein 
11286ee51a4eSJack Morgenstein 	if (!mlx4_is_mfunc(dev))
11296ee51a4eSJack Morgenstein 		return -EINVAL;
11306ee51a4eSJack Morgenstein 
1131449fc488SMatan Barak 	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1132872bf2fbSYishai Hadas 	num_vfs = bitmap_weight(slaves_pport.slaves,
1133872bf2fbSYishai Hadas 				dev->persist->num_vfs + 1) - 1;
1134449fc488SMatan Barak 
11356ee51a4eSJack Morgenstein 	for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
1136111c6094SJack Morgenstein 		if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid,
1137111c6094SJack Morgenstein 			    MLX4_ROCE_GID_ENTRY_SIZE)) {
11386ee51a4eSJack Morgenstein 			found_ix = i;
11396ee51a4eSJack Morgenstein 			break;
11406ee51a4eSJack Morgenstein 		}
11416ee51a4eSJack Morgenstein 	}
11426ee51a4eSJack Morgenstein 
1143b6ffaeffSJack Morgenstein 	if (found_ix >= 0) {
11440254bc82SMatan Barak 		/* Calculate a slave_gid which is the slave number in the gid
11450254bc82SMatan Barak 		 * table and not a globally unique slave number.
11460254bc82SMatan Barak 		 */
1147b6ffaeffSJack Morgenstein 		if (found_ix < MLX4_ROCE_PF_GIDS)
1148449fc488SMatan Barak 			slave_gid = 0;
1149449fc488SMatan Barak 		else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) *
1150449fc488SMatan Barak 			 (vf_gids / num_vfs + 1))
1151449fc488SMatan Barak 			slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) /
1152449fc488SMatan Barak 				     (vf_gids / num_vfs + 1)) + 1;
1153b6ffaeffSJack Morgenstein 		else
1154449fc488SMatan Barak 			slave_gid =
1155b6ffaeffSJack Morgenstein 			((found_ix - MLX4_ROCE_PF_GIDS -
1156449fc488SMatan Barak 			  ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) /
1157449fc488SMatan Barak 			 (vf_gids / num_vfs)) + vf_gids % num_vfs + 1;
1158449fc488SMatan Barak 
11590254bc82SMatan Barak 		/* Calculate the globally unique slave id */
1160449fc488SMatan Barak 		if (slave_gid) {
1161449fc488SMatan Barak 			struct mlx4_active_ports exclusive_ports;
1162449fc488SMatan Barak 			struct mlx4_active_ports actv_ports;
1163449fc488SMatan Barak 			struct mlx4_slaves_pport slaves_pport_actv;
1164449fc488SMatan Barak 			unsigned max_port_p_one;
11650254bc82SMatan Barak 			int num_vfs_before = 0;
11660254bc82SMatan Barak 			int candidate_slave_gid;
1167449fc488SMatan Barak 
11680254bc82SMatan Barak 			/* Calculate how many VFs are on the previous port, if exists */
1169449fc488SMatan Barak 			for (i = 1; i < port; i++) {
1170449fc488SMatan Barak 				bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
11710254bc82SMatan Barak 				set_bit(i - 1, exclusive_ports.ports);
1172449fc488SMatan Barak 				slaves_pport_actv =
1173449fc488SMatan Barak 					mlx4_phys_to_slaves_pport_actv(
1174449fc488SMatan Barak 							dev, &exclusive_ports);
11750254bc82SMatan Barak 				num_vfs_before += bitmap_weight(
1176449fc488SMatan Barak 						slaves_pport_actv.slaves,
1177872bf2fbSYishai Hadas 						dev->persist->num_vfs + 1);
1178449fc488SMatan Barak 			}
1179449fc488SMatan Barak 
11800254bc82SMatan Barak 			/* candidate_slave_gid isn't necessarily the correct slave, but
11810254bc82SMatan Barak 			 * it has the same number of ports and is assigned to the same
11820254bc82SMatan Barak 			 * ports as the real slave we're looking for. On dual port VF,
11830254bc82SMatan Barak 			 * slave_gid = [single port VFs on port <port>] +
11840254bc82SMatan Barak 			 * [offset of the current slave from the first dual port VF] +
11850254bc82SMatan Barak 			 * 1 (for the PF).
11860254bc82SMatan Barak 			 */
11870254bc82SMatan Barak 			candidate_slave_gid = slave_gid + num_vfs_before;
11880254bc82SMatan Barak 
11890254bc82SMatan Barak 			actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid);
1190449fc488SMatan Barak 			max_port_p_one = find_first_bit(
1191449fc488SMatan Barak 				actv_ports.ports, dev->caps.num_ports) +
1192449fc488SMatan Barak 				bitmap_weight(actv_ports.ports,
1193449fc488SMatan Barak 					      dev->caps.num_ports) + 1;
1194449fc488SMatan Barak 
11950254bc82SMatan Barak 			/* Calculate the real slave number */
1196449fc488SMatan Barak 			for (i = 1; i < max_port_p_one; i++) {
1197449fc488SMatan Barak 				if (i == port)
1198449fc488SMatan Barak 					continue;
1199449fc488SMatan Barak 				bitmap_zero(exclusive_ports.ports,
1200449fc488SMatan Barak 					    dev->caps.num_ports);
1201449fc488SMatan Barak 				set_bit(i - 1, exclusive_ports.ports);
1202449fc488SMatan Barak 				slaves_pport_actv =
1203449fc488SMatan Barak 					mlx4_phys_to_slaves_pport_actv(
1204449fc488SMatan Barak 						dev, &exclusive_ports);
1205449fc488SMatan Barak 				slave_gid += bitmap_weight(
1206449fc488SMatan Barak 						slaves_pport_actv.slaves,
1207872bf2fbSYishai Hadas 						dev->persist->num_vfs + 1);
1208449fc488SMatan Barak 			}
1209449fc488SMatan Barak 		}
1210449fc488SMatan Barak 		*slave_id = slave_gid;
1211b6ffaeffSJack Morgenstein 	}
12126ee51a4eSJack Morgenstein 
12136ee51a4eSJack Morgenstein 	return (found_ix >= 0) ? 0 : -EINVAL;
12146ee51a4eSJack Morgenstein }
12156ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid);
12166ee51a4eSJack Morgenstein 
12179cd59352SJack Morgenstein int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id,
12189cd59352SJack Morgenstein 				 u8 *gid)
12196ee51a4eSJack Morgenstein {
12206ee51a4eSJack Morgenstein 	struct mlx4_priv *priv = mlx4_priv(dev);
12216ee51a4eSJack Morgenstein 
12226ee51a4eSJack Morgenstein 	if (!mlx4_is_master(dev))
12236ee51a4eSJack Morgenstein 		return -EINVAL;
12246ee51a4eSJack Morgenstein 
1225111c6094SJack Morgenstein 	memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw,
1226111c6094SJack Morgenstein 	       MLX4_ROCE_GID_ENTRY_SIZE);
12276ee51a4eSJack Morgenstein 	return 0;
12286ee51a4eSJack Morgenstein }
12296ee51a4eSJack Morgenstein EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
123032a173c7SSaeed Mahameed 
123132a173c7SSaeed Mahameed /* Cable Module Info */
123232a173c7SSaeed Mahameed #define MODULE_INFO_MAX_READ 48
123332a173c7SSaeed Mahameed 
123432a173c7SSaeed Mahameed #define I2C_ADDR_LOW  0x50
123532a173c7SSaeed Mahameed #define I2C_ADDR_HIGH 0x51
123632a173c7SSaeed Mahameed #define I2C_PAGE_SIZE 256
123732a173c7SSaeed Mahameed 
123832a173c7SSaeed Mahameed /* Module Info Data */
123932a173c7SSaeed Mahameed struct mlx4_cable_info {
124032a173c7SSaeed Mahameed 	u8	i2c_addr;
124132a173c7SSaeed Mahameed 	u8	page_num;
124232a173c7SSaeed Mahameed 	__be16	dev_mem_address;
124332a173c7SSaeed Mahameed 	__be16	reserved1;
124432a173c7SSaeed Mahameed 	__be16	size;
124532a173c7SSaeed Mahameed 	__be32	reserved2[2];
124632a173c7SSaeed Mahameed 	u8	data[MODULE_INFO_MAX_READ];
124732a173c7SSaeed Mahameed };
124832a173c7SSaeed Mahameed 
124932a173c7SSaeed Mahameed enum cable_info_err {
125032a173c7SSaeed Mahameed 	 CABLE_INF_INV_PORT      = 0x1,
125132a173c7SSaeed Mahameed 	 CABLE_INF_OP_NOSUP      = 0x2,
125232a173c7SSaeed Mahameed 	 CABLE_INF_NOT_CONN      = 0x3,
125332a173c7SSaeed Mahameed 	 CABLE_INF_NO_EEPRM      = 0x4,
125432a173c7SSaeed Mahameed 	 CABLE_INF_PAGE_ERR      = 0x5,
125532a173c7SSaeed Mahameed 	 CABLE_INF_INV_ADDR      = 0x6,
125632a173c7SSaeed Mahameed 	 CABLE_INF_I2C_ADDR      = 0x7,
125732a173c7SSaeed Mahameed 	 CABLE_INF_QSFP_VIO      = 0x8,
125832a173c7SSaeed Mahameed 	 CABLE_INF_I2C_BUSY      = 0x9,
125932a173c7SSaeed Mahameed };
126032a173c7SSaeed Mahameed 
126132a173c7SSaeed Mahameed #define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF)
126232a173c7SSaeed Mahameed 
126332a173c7SSaeed Mahameed static inline const char *cable_info_mad_err_str(u16 mad_status)
126432a173c7SSaeed Mahameed {
126532a173c7SSaeed Mahameed 	u8 err = MAD_STATUS_2_CABLE_ERR(mad_status);
126632a173c7SSaeed Mahameed 
126732a173c7SSaeed Mahameed 	switch (err) {
126832a173c7SSaeed Mahameed 	case CABLE_INF_INV_PORT:
126932a173c7SSaeed Mahameed 		return "invalid port selected";
127032a173c7SSaeed Mahameed 	case CABLE_INF_OP_NOSUP:
127132a173c7SSaeed Mahameed 		return "operation not supported for this port (the port is of type CX4 or internal)";
127232a173c7SSaeed Mahameed 	case CABLE_INF_NOT_CONN:
127332a173c7SSaeed Mahameed 		return "cable is not connected";
127432a173c7SSaeed Mahameed 	case CABLE_INF_NO_EEPRM:
127532a173c7SSaeed Mahameed 		return "the connected cable has no EPROM (passive copper cable)";
127632a173c7SSaeed Mahameed 	case CABLE_INF_PAGE_ERR:
127732a173c7SSaeed Mahameed 		return "page number is greater than 15";
127832a173c7SSaeed Mahameed 	case CABLE_INF_INV_ADDR:
127932a173c7SSaeed Mahameed 		return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)";
128032a173c7SSaeed Mahameed 	case CABLE_INF_I2C_ADDR:
128132a173c7SSaeed Mahameed 		return "invalid I2C slave address";
128232a173c7SSaeed Mahameed 	case CABLE_INF_QSFP_VIO:
128332a173c7SSaeed Mahameed 		return "at least one cable violates the QSFP specification and ignores the modsel signal";
128432a173c7SSaeed Mahameed 	case CABLE_INF_I2C_BUSY:
128532a173c7SSaeed Mahameed 		return "I2C bus is constantly busy";
128632a173c7SSaeed Mahameed 	}
128732a173c7SSaeed Mahameed 	return "Unknown Error";
128832a173c7SSaeed Mahameed }
128932a173c7SSaeed Mahameed 
129032a173c7SSaeed Mahameed /**
129132a173c7SSaeed Mahameed  * mlx4_get_module_info - Read cable module eeprom data
129232a173c7SSaeed Mahameed  * @dev: mlx4_dev.
129332a173c7SSaeed Mahameed  * @port: port number.
129432a173c7SSaeed Mahameed  * @offset: byte offset in eeprom to start reading data from.
129532a173c7SSaeed Mahameed  * @size: num of bytes to read.
129632a173c7SSaeed Mahameed  * @data: output buffer to put the requested data into.
129732a173c7SSaeed Mahameed  *
129832a173c7SSaeed Mahameed  * Reads cable module eeprom data, puts the outcome data into
129932a173c7SSaeed Mahameed  * data pointer paramer.
130032a173c7SSaeed Mahameed  * Returns num of read bytes on success or a negative error
130132a173c7SSaeed Mahameed  * code.
130232a173c7SSaeed Mahameed  */
130332a173c7SSaeed Mahameed int mlx4_get_module_info(struct mlx4_dev *dev, u8 port,
130432a173c7SSaeed Mahameed 			 u16 offset, u16 size, u8 *data)
130532a173c7SSaeed Mahameed {
130632a173c7SSaeed Mahameed 	struct mlx4_cmd_mailbox *inbox, *outbox;
130732a173c7SSaeed Mahameed 	struct mlx4_mad_ifc *inmad, *outmad;
130832a173c7SSaeed Mahameed 	struct mlx4_cable_info *cable_info;
130932a173c7SSaeed Mahameed 	u16 i2c_addr;
131032a173c7SSaeed Mahameed 	int ret;
131132a173c7SSaeed Mahameed 
131232a173c7SSaeed Mahameed 	if (size > MODULE_INFO_MAX_READ)
131332a173c7SSaeed Mahameed 		size = MODULE_INFO_MAX_READ;
131432a173c7SSaeed Mahameed 
131532a173c7SSaeed Mahameed 	inbox = mlx4_alloc_cmd_mailbox(dev);
131632a173c7SSaeed Mahameed 	if (IS_ERR(inbox))
131732a173c7SSaeed Mahameed 		return PTR_ERR(inbox);
131832a173c7SSaeed Mahameed 
131932a173c7SSaeed Mahameed 	outbox = mlx4_alloc_cmd_mailbox(dev);
132032a173c7SSaeed Mahameed 	if (IS_ERR(outbox)) {
132132a173c7SSaeed Mahameed 		mlx4_free_cmd_mailbox(dev, inbox);
132232a173c7SSaeed Mahameed 		return PTR_ERR(outbox);
132332a173c7SSaeed Mahameed 	}
132432a173c7SSaeed Mahameed 
132532a173c7SSaeed Mahameed 	inmad = (struct mlx4_mad_ifc *)(inbox->buf);
132632a173c7SSaeed Mahameed 	outmad = (struct mlx4_mad_ifc *)(outbox->buf);
132732a173c7SSaeed Mahameed 
132832a173c7SSaeed Mahameed 	inmad->method = 0x1; /* Get */
132932a173c7SSaeed Mahameed 	inmad->class_version = 0x1;
133032a173c7SSaeed Mahameed 	inmad->mgmt_class = 0x1;
133132a173c7SSaeed Mahameed 	inmad->base_version = 0x1;
133232a173c7SSaeed Mahameed 	inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */
133332a173c7SSaeed Mahameed 
133432a173c7SSaeed Mahameed 	if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE)
133532a173c7SSaeed Mahameed 		/* Cross pages reads are not allowed
133632a173c7SSaeed Mahameed 		 * read until offset 256 in low page
133732a173c7SSaeed Mahameed 		 */
133832a173c7SSaeed Mahameed 		size -= offset + size - I2C_PAGE_SIZE;
133932a173c7SSaeed Mahameed 
134032a173c7SSaeed Mahameed 	i2c_addr = I2C_ADDR_LOW;
134132a173c7SSaeed Mahameed 	if (offset >= I2C_PAGE_SIZE) {
134232a173c7SSaeed Mahameed 		/* Reset offset to high page */
134332a173c7SSaeed Mahameed 		i2c_addr = I2C_ADDR_HIGH;
134432a173c7SSaeed Mahameed 		offset -= I2C_PAGE_SIZE;
134532a173c7SSaeed Mahameed 	}
134632a173c7SSaeed Mahameed 
134732a173c7SSaeed Mahameed 	cable_info = (struct mlx4_cable_info *)inmad->data;
134832a173c7SSaeed Mahameed 	cable_info->dev_mem_address = cpu_to_be16(offset);
134932a173c7SSaeed Mahameed 	cable_info->page_num = 0;
135032a173c7SSaeed Mahameed 	cable_info->i2c_addr = i2c_addr;
135132a173c7SSaeed Mahameed 	cable_info->size = cpu_to_be16(size);
135232a173c7SSaeed Mahameed 
135332a173c7SSaeed Mahameed 	ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
135432a173c7SSaeed Mahameed 			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
135532a173c7SSaeed Mahameed 			   MLX4_CMD_NATIVE);
135632a173c7SSaeed Mahameed 	if (ret)
135732a173c7SSaeed Mahameed 		goto out;
135832a173c7SSaeed Mahameed 
135932a173c7SSaeed Mahameed 	if (be16_to_cpu(outmad->status)) {
136032a173c7SSaeed Mahameed 		/* Mad returned with bad status */
136132a173c7SSaeed Mahameed 		ret = be16_to_cpu(outmad->status);
136232a173c7SSaeed Mahameed 		mlx4_warn(dev,
136332a173c7SSaeed Mahameed 			  "MLX4_CMD_MAD_IFC Get Module info attr(%x) port(%d) i2c_addr(%x) offset(%d) size(%d): Response Mad Status(%x) - %s\n",
136432a173c7SSaeed Mahameed 			  0xFF60, port, i2c_addr, offset, size,
136532a173c7SSaeed Mahameed 			  ret, cable_info_mad_err_str(ret));
136632a173c7SSaeed Mahameed 
136732a173c7SSaeed Mahameed 		if (i2c_addr == I2C_ADDR_HIGH &&
136832a173c7SSaeed Mahameed 		    MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR)
136932a173c7SSaeed Mahameed 			/* Some SFP cables do not support i2c slave
137032a173c7SSaeed Mahameed 			 * address 0x51 (high page), abort silently.
137132a173c7SSaeed Mahameed 			 */
137232a173c7SSaeed Mahameed 			ret = 0;
137332a173c7SSaeed Mahameed 		else
137432a173c7SSaeed Mahameed 			ret = -ret;
137532a173c7SSaeed Mahameed 		goto out;
137632a173c7SSaeed Mahameed 	}
137732a173c7SSaeed Mahameed 	cable_info = (struct mlx4_cable_info *)outmad->data;
137832a173c7SSaeed Mahameed 	memcpy(data, cable_info->data, size);
137932a173c7SSaeed Mahameed 	ret = size;
138032a173c7SSaeed Mahameed out:
138132a173c7SSaeed Mahameed 	mlx4_free_cmd_mailbox(dev, inbox);
138232a173c7SSaeed Mahameed 	mlx4_free_cmd_mailbox(dev, outbox);
138332a173c7SSaeed Mahameed 	return ret;
138432a173c7SSaeed Mahameed }
138532a173c7SSaeed Mahameed EXPORT_SYMBOL(mlx4_get_module_info);
1386