1219820Sjeff/*
2272027Shselasky * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved.
3219820Sjeff *
4219820Sjeff * This software is available to you under a choice of one of two
5219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
6219820Sjeff * General Public License (GPL) Version 2, available from the file
7219820Sjeff * COPYING in the main directory of this source tree, or the
8219820Sjeff * OpenIB.org BSD license below:
9219820Sjeff *
10219820Sjeff *     Redistribution and use in source and binary forms, with or
11219820Sjeff *     without modification, are permitted provided that the following
12219820Sjeff *     conditions are met:
13219820Sjeff *
14219820Sjeff *      - Redistributions of source code must retain the above
15219820Sjeff *        copyright notice, this list of conditions and the following
16219820Sjeff *        disclaimer.
17219820Sjeff *
18219820Sjeff *      - Redistributions in binary form must reproduce the above
19219820Sjeff *        copyright notice, this list of conditions and the following
20219820Sjeff *        disclaimer in the documentation and/or other materials
21219820Sjeff *        provided with the distribution.
22219820Sjeff *
23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30219820Sjeff * SOFTWARE.
31219820Sjeff */
32219820Sjeff
33300676Shselasky#define	LINUXKPI_PARAM_PREFIX mlx4_
34300676Shselasky
35219820Sjeff#include <linux/errno.h>
36219820Sjeff#include <linux/if_ether.h>
37272027Shselasky#include <linux/module.h>
38272027Shselasky#include <linux/err.h>
39219820Sjeff
40306486Shselasky#include <dev/mlx4/cmd.h>
41255932Salfred#include <linux/moduleparam.h>
42329159Shselasky
43329159Shselasky#include <rdma/ib_verbs.h>
44329159Shselasky
45219820Sjeff#include "mlx4.h"
46306486Shselasky#include <dev/mlx4/stats.h>
47219820Sjeff
48219820Sjeff#define MLX4_MAC_VALID		(1ull << 63)
49219820Sjeff
50219820Sjeff#define MLX4_VLAN_VALID		(1u << 31)
51219820Sjeff#define MLX4_VLAN_MASK		0xfff
52219820Sjeff
53329159Shselasky#define MLX4_STATS_TRAFFIC_COUNTERS_MASK	0xfULL
54329159Shselasky#define MLX4_STATS_TRAFFIC_DROPS_MASK		0xc0ULL
55329159Shselasky#define MLX4_STATS_ERROR_COUNTERS_MASK		0x1ffc30ULL
56329159Shselasky#define MLX4_STATS_PORT_COUNTERS_MASK		0x1fe00000ULL
57329159Shselasky
58329159Shselasky#define MLX4_FLAG_V_IGNORE_FCS_MASK		0x2
59329159Shselasky#define MLX4_IGNORE_FCS_MASK			0x1
60329159Shselasky#define MLX4_TC_MAX_NUMBER			8
61329159Shselasky
62219820Sjeffvoid mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table)
63219820Sjeff{
64219820Sjeff	int i;
65219820Sjeff
66219820Sjeff	mutex_init(&table->mutex);
67219820Sjeff	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
68219820Sjeff		table->entries[i] = 0;
69219820Sjeff		table->refs[i]	 = 0;
70329159Shselasky		table->is_dup[i] = false;
71219820Sjeff	}
72219820Sjeff	table->max   = 1 << dev->caps.log_num_macs;
73219820Sjeff	table->total = 0;
74219820Sjeff}
75219820Sjeff
76219820Sjeffvoid mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
77219820Sjeff{
78219820Sjeff	int i;
79219820Sjeff
80219820Sjeff	mutex_init(&table->mutex);
81219820Sjeff	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
82219820Sjeff		table->entries[i] = 0;
83219820Sjeff		table->refs[i]	 = 0;
84329159Shselasky		table->is_dup[i] = false;
85219820Sjeff	}
86255932Salfred	table->max   = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR;
87219820Sjeff	table->total = 0;
88219820Sjeff}
89219820Sjeff
90329159Shselaskyvoid mlx4_init_roce_gid_table(struct mlx4_dev *dev,
91329159Shselasky			      struct mlx4_roce_gid_table *table)
92329159Shselasky{
93329159Shselasky	int i;
94329159Shselasky
95329159Shselasky	mutex_init(&table->mutex);
96329159Shselasky	for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++)
97329159Shselasky		memset(table->roce_gids[i].raw, 0, MLX4_ROCE_GID_ENTRY_SIZE);
98329159Shselasky}
99329159Shselasky
100255932Salfredstatic int validate_index(struct mlx4_dev *dev,
101255932Salfred			  struct mlx4_mac_table *table, int index)
102255932Salfred{
103255932Salfred	int err = 0;
104255932Salfred
105329159Shselasky	if (index < 0 || index >= table->max || !table->entries[index]) {
106255932Salfred		mlx4_warn(dev, "No valid Mac entry for the given index\n");
107255932Salfred		err = -EINVAL;
108255932Salfred	}
109255932Salfred	return err;
110255932Salfred}
111255932Salfred
112255932Salfredstatic int find_index(struct mlx4_dev *dev,
113255932Salfred		      struct mlx4_mac_table *table, u64 mac)
114255932Salfred{
115255932Salfred	int i;
116255932Salfred
117255932Salfred	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
118329159Shselasky		if (table->refs[i] &&
119329159Shselasky		    (MLX4_MAC_MASK & mac) ==
120255932Salfred		    (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))
121255932Salfred			return i;
122255932Salfred	}
123255932Salfred	/* Mac not found */
124255932Salfred	return -EINVAL;
125255932Salfred}
126255932Salfred
127219820Sjeffstatic int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
128219820Sjeff				   __be64 *entries)
129219820Sjeff{
130219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
131219820Sjeff	u32 in_mod;
132219820Sjeff	int err;
133219820Sjeff
134219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
135219820Sjeff	if (IS_ERR(mailbox))
136219820Sjeff		return PTR_ERR(mailbox);
137219820Sjeff
138219820Sjeff	memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE);
139219820Sjeff
140219820Sjeff	in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port;
141255932Salfred
142329159Shselasky	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
143329159Shselasky		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
144329159Shselasky		       MLX4_CMD_NATIVE);
145219820Sjeff
146219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
147219820Sjeff	return err;
148219820Sjeff}
149219820Sjeff
150329159Shselaskyint mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx)
151329159Shselasky{
152329159Shselasky	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
153329159Shselasky	struct mlx4_mac_table *table = &info->mac_table;
154329159Shselasky	int i;
155329159Shselasky
156329159Shselasky	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
157329159Shselasky		if (!table->refs[i])
158329159Shselasky			continue;
159329159Shselasky
160329159Shselasky		if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
161329159Shselasky			*idx = i;
162329159Shselasky			return 0;
163329159Shselasky		}
164329159Shselasky	}
165329159Shselasky
166329159Shselasky	return -ENOENT;
167329159Shselasky}
168329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_find_cached_mac);
169329159Shselasky
170329159Shselaskystatic bool mlx4_need_mf_bond(struct mlx4_dev *dev)
171329159Shselasky{
172329159Shselasky	int i, num_eth_ports = 0;
173329159Shselasky
174329159Shselasky	if (!mlx4_is_mfunc(dev))
175329159Shselasky		return false;
176329159Shselasky	mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
177329159Shselasky		++num_eth_ports;
178329159Shselasky
179329159Shselasky	return (num_eth_ports ==  2) ? true : false;
180329159Shselasky}
181329159Shselasky
182255932Salfredint __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
183219820Sjeff{
184255932Salfred	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
185255932Salfred	struct mlx4_mac_table *table = &info->mac_table;
186219820Sjeff	int i, err = 0;
187219820Sjeff	int free = -1;
188329159Shselasky	int free_for_dup = -1;
189329159Shselasky	bool dup = mlx4_is_mf_bonded(dev);
190329159Shselasky	u8 dup_port = (port == 1) ? 2 : 1;
191329159Shselasky	struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
192329159Shselasky	bool need_mf_bond = mlx4_need_mf_bond(dev);
193329159Shselasky	bool can_mf_bond = true;
194219820Sjeff
195329159Shselasky	mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d %s duplicate\n",
196329159Shselasky		 (unsigned long long)mac, port,
197329159Shselasky		 dup ? "with" : "without");
198255932Salfred
199329159Shselasky	if (need_mf_bond) {
200329159Shselasky		if (port == 1) {
201329159Shselasky			mutex_lock(&table->mutex);
202329159Shselasky			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
203329159Shselasky		} else {
204329159Shselasky			mutex_lock(&dup_table->mutex);
205329159Shselasky			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
206329159Shselasky		}
207329159Shselasky	} else {
208329159Shselasky		mutex_lock(&table->mutex);
209329159Shselasky	}
210329159Shselasky
211329159Shselasky	if (need_mf_bond) {
212329159Shselasky		int index_at_port = -1;
213329159Shselasky		int index_at_dup_port = -1;
214329159Shselasky
215329159Shselasky		for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
216329159Shselasky			if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))))
217329159Shselasky				index_at_port = i;
218329159Shselasky			if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]))))
219329159Shselasky				index_at_dup_port = i;
220329159Shselasky		}
221329159Shselasky
222329159Shselasky		/* check that same mac is not in the tables at different indices */
223329159Shselasky		if ((index_at_port != index_at_dup_port) &&
224329159Shselasky		    (index_at_port >= 0) &&
225329159Shselasky		    (index_at_dup_port >= 0))
226329159Shselasky			can_mf_bond = false;
227329159Shselasky
228329159Shselasky		/* If the mac is already in the primary table, the slot must be
229329159Shselasky		 * available in the duplicate table as well.
230329159Shselasky		 */
231329159Shselasky		if (index_at_port >= 0 && index_at_dup_port < 0 &&
232329159Shselasky		    dup_table->refs[index_at_port]) {
233329159Shselasky			can_mf_bond = false;
234329159Shselasky		}
235329159Shselasky		/* If the mac is already in the duplicate table, check that the
236329159Shselasky		 * corresponding index is not occupied in the primary table, or
237329159Shselasky		 * the primary table already contains the mac at the same index.
238329159Shselasky		 * Otherwise, you cannot bond (primary contains a different mac
239329159Shselasky		 * at that index).
240329159Shselasky		 */
241329159Shselasky		if (index_at_dup_port >= 0) {
242329159Shselasky			if (!table->refs[index_at_dup_port] ||
243329159Shselasky			    ((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[index_at_dup_port]))))
244329159Shselasky				free_for_dup = index_at_dup_port;
245329159Shselasky			else
246329159Shselasky				can_mf_bond = false;
247329159Shselasky		}
248329159Shselasky	}
249329159Shselasky
250255932Salfred	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
251329159Shselasky		if (!table->refs[i]) {
252329159Shselasky			if (free < 0)
253329159Shselasky				free = i;
254329159Shselasky			if (free_for_dup < 0 && need_mf_bond && can_mf_bond) {
255329159Shselasky				if (!dup_table->refs[i])
256329159Shselasky					free_for_dup = i;
257329159Shselasky			}
258219820Sjeff			continue;
259219820Sjeff		}
260219820Sjeff
261329159Shselasky		if ((MLX4_MAC_MASK & mac) ==
262329159Shselasky		     (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
263329159Shselasky			/* MAC already registered, increment ref count */
264272027Shselasky			err = i;
265219820Sjeff			++table->refs[i];
266329159Shselasky			if (dup) {
267329159Shselasky				u64 dup_mac = MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]);
268329159Shselasky
269329159Shselasky				if (dup_mac != mac || !dup_table->is_dup[i]) {
270329159Shselasky					mlx4_warn(dev, "register mac: expect duplicate mac 0x%llx on port %d index %d\n",
271329159Shselasky						  (long long)mac, dup_port, i);
272329159Shselasky				}
273329159Shselasky			}
274219820Sjeff			goto out;
275219820Sjeff		}
276219820Sjeff	}
277219820Sjeff
278329159Shselasky	if (need_mf_bond && (free_for_dup < 0)) {
279329159Shselasky		if (dup) {
280329159Shselasky			mlx4_warn(dev, "Fail to allocate duplicate MAC table entry\n");
281329159Shselasky			mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n");
282329159Shselasky			dup = false;
283329159Shselasky		}
284329159Shselasky		can_mf_bond = false;
285329159Shselasky	}
286329159Shselasky
287329159Shselasky	if (need_mf_bond && can_mf_bond)
288329159Shselasky		free = free_for_dup;
289329159Shselasky
290219820Sjeff	mlx4_dbg(dev, "Free MAC index is %d\n", free);
291219820Sjeff
292219820Sjeff	if (table->total == table->max) {
293219820Sjeff		/* No free mac entries */
294219820Sjeff		err = -ENOSPC;
295219820Sjeff		goto out;
296219820Sjeff	}
297219820Sjeff
298219820Sjeff	/* Register new MAC */
299219820Sjeff	table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
300219820Sjeff
301219820Sjeff	err = mlx4_set_port_mac_table(dev, port, table->entries);
302219820Sjeff	if (unlikely(err)) {
303255932Salfred		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
304255932Salfred			 (unsigned long long) mac);
305219820Sjeff		table->entries[free] = 0;
306219820Sjeff		goto out;
307219820Sjeff	}
308255932Salfred	table->refs[free] = 1;
309329159Shselasky	table->is_dup[free] = false;
310329159Shselasky	++table->total;
311329159Shselasky	if (dup) {
312329159Shselasky		dup_table->refs[free] = 0;
313329159Shselasky		dup_table->is_dup[free] = true;
314329159Shselasky		dup_table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
315219820Sjeff
316329159Shselasky		err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries);
317329159Shselasky		if (unlikely(err)) {
318329159Shselasky			mlx4_warn(dev, "Failed adding duplicate mac: 0x%llx\n", (long long)mac);
319329159Shselasky			dup_table->is_dup[free] = false;
320329159Shselasky			dup_table->entries[free] = 0;
321329159Shselasky			goto out;
322329159Shselasky		}
323329159Shselasky		++dup_table->total;
324329159Shselasky	}
325255932Salfred	err = free;
326219820Sjeffout:
327329159Shselasky	if (need_mf_bond) {
328329159Shselasky		if (port == 2) {
329329159Shselasky			mutex_unlock(&table->mutex);
330329159Shselasky			mutex_unlock(&dup_table->mutex);
331329159Shselasky		} else {
332329159Shselasky			mutex_unlock(&dup_table->mutex);
333329159Shselasky			mutex_unlock(&table->mutex);
334329159Shselasky		}
335329159Shselasky	} else {
336329159Shselasky		mutex_unlock(&table->mutex);
337329159Shselasky	}
338219820Sjeff	return err;
339219820Sjeff}
340255932SalfredEXPORT_SYMBOL_GPL(__mlx4_register_mac);
341255932Salfred
342255932Salfredint mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
343255932Salfred{
344255932Salfred	u64 out_param = 0;
345272027Shselasky	int err = -EINVAL;
346255932Salfred
347255932Salfred	if (mlx4_is_mfunc(dev)) {
348272027Shselasky		if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) {
349272027Shselasky			err = mlx4_cmd_imm(dev, mac, &out_param,
350272027Shselasky					   ((u32) port) << 8 | (u32) RES_MAC,
351272027Shselasky					   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
352272027Shselasky					   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
353272027Shselasky		}
354272027Shselasky		if (err && err == -EINVAL && mlx4_is_slave(dev)) {
355272027Shselasky			/* retry using old REG_MAC format */
356272027Shselasky			set_param_l(&out_param, port);
357272027Shselasky			err = mlx4_cmd_imm(dev, mac, &out_param, RES_MAC,
358272027Shselasky					   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
359272027Shselasky					   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
360272027Shselasky			if (!err)
361272027Shselasky				dev->flags |= MLX4_FLAG_OLD_REG_MAC;
362272027Shselasky		}
363255932Salfred		if (err)
364255932Salfred			return err;
365255932Salfred
366255932Salfred		return get_param_l(&out_param);
367255932Salfred	}
368255932Salfred	return __mlx4_register_mac(dev, port, mac);
369255932Salfred}
370219820SjeffEXPORT_SYMBOL_GPL(mlx4_register_mac);
371219820Sjeff
372255932Salfredint mlx4_get_base_qpn(struct mlx4_dev *dev, u8 port)
373219820Sjeff{
374255932Salfred	return dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] +
375255932Salfred			(port - 1) * (1 << dev->caps.log_num_macs);
376255932Salfred}
377255932SalfredEXPORT_SYMBOL_GPL(mlx4_get_base_qpn);
378219820Sjeff
379255932Salfredvoid __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
380255932Salfred{
381255932Salfred	struct mlx4_port_info *info;
382255932Salfred	struct mlx4_mac_table *table;
383255932Salfred	int index;
384329159Shselasky	bool dup = mlx4_is_mf_bonded(dev);
385329159Shselasky	u8 dup_port = (port == 1) ? 2 : 1;
386329159Shselasky	struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
387255932Salfred
388255932Salfred	if (port < 1 || port > dev->caps.num_ports) {
389255932Salfred		mlx4_warn(dev, "invalid port number (%d), aborting...\n", port);
390255932Salfred		return;
391255932Salfred	}
392255932Salfred	info = &mlx4_priv(dev)->port[port];
393255932Salfred	table = &info->mac_table;
394255932Salfred
395329159Shselasky	if (dup) {
396329159Shselasky		if (port == 1) {
397329159Shselasky			mutex_lock(&table->mutex);
398329159Shselasky			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
399329159Shselasky		} else {
400329159Shselasky			mutex_lock(&dup_table->mutex);
401329159Shselasky			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
402329159Shselasky		}
403329159Shselasky	} else {
404329159Shselasky		mutex_lock(&table->mutex);
405329159Shselasky	}
406329159Shselasky
407255932Salfred	index = find_index(dev, table, mac);
408255932Salfred
409255932Salfred	if (validate_index(dev, table, index))
410219820Sjeff		goto out;
411255932Salfred
412329159Shselasky	if (--table->refs[index] || table->is_dup[index]) {
413329159Shselasky		mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n",
414329159Shselasky			 index);
415329159Shselasky		if (!table->refs[index])
416329159Shselasky			dup_table->is_dup[index] = false;
417219820Sjeff		goto out;
418219820Sjeff	}
419255932Salfred
420219820Sjeff	table->entries[index] = 0;
421329159Shselasky	if (mlx4_set_port_mac_table(dev, port, table->entries))
422329159Shselasky		mlx4_warn(dev, "Fail to set mac in port %d during unregister\n", port);
423219820Sjeff	--table->total;
424329159Shselasky
425329159Shselasky	if (dup) {
426329159Shselasky		dup_table->is_dup[index] = false;
427329159Shselasky		if (dup_table->refs[index])
428329159Shselasky			goto out;
429329159Shselasky		dup_table->entries[index] = 0;
430329159Shselasky		if (mlx4_set_port_mac_table(dev, dup_port, dup_table->entries))
431329159Shselasky			mlx4_warn(dev, "Fail to set mac in duplicate port %d during unregister\n", dup_port);
432329159Shselasky
433329159Shselasky		--table->total;
434329159Shselasky	}
435219820Sjeffout:
436329159Shselasky	if (dup) {
437329159Shselasky		if (port == 2) {
438329159Shselasky			mutex_unlock(&table->mutex);
439329159Shselasky			mutex_unlock(&dup_table->mutex);
440329159Shselasky		} else {
441329159Shselasky			mutex_unlock(&dup_table->mutex);
442329159Shselasky			mutex_unlock(&table->mutex);
443329159Shselasky		}
444329159Shselasky	} else {
445329159Shselasky		mutex_unlock(&table->mutex);
446329159Shselasky	}
447219820Sjeff}
448255932SalfredEXPORT_SYMBOL_GPL(__mlx4_unregister_mac);
449255932Salfred
450255932Salfredvoid mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
451255932Salfred{
452255932Salfred	u64 out_param = 0;
453255932Salfred
454255932Salfred	if (mlx4_is_mfunc(dev)) {
455272027Shselasky		if (!(dev->flags & MLX4_FLAG_OLD_REG_MAC)) {
456272027Shselasky			(void) mlx4_cmd_imm(dev, mac, &out_param,
457272027Shselasky					    ((u32) port) << 8 | (u32) RES_MAC,
458272027Shselasky					    RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
459272027Shselasky					    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
460272027Shselasky		} else {
461272027Shselasky			/* use old unregister mac format */
462272027Shselasky			set_param_l(&out_param, port);
463272027Shselasky			(void) mlx4_cmd_imm(dev, mac, &out_param, RES_MAC,
464272027Shselasky					    RES_OP_RESERVE_AND_MAP, MLX4_CMD_FREE_RES,
465272027Shselasky					    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
466272027Shselasky		}
467255932Salfred		return;
468255932Salfred	}
469255932Salfred	__mlx4_unregister_mac(dev, port, mac);
470255932Salfred	return;
471255932Salfred}
472219820SjeffEXPORT_SYMBOL_GPL(mlx4_unregister_mac);
473219820Sjeff
474255932Salfredint __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
475255932Salfred{
476255932Salfred	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
477255932Salfred	struct mlx4_mac_table *table = &info->mac_table;
478255932Salfred	int index = qpn - info->base_qpn;
479255932Salfred	int err = 0;
480329159Shselasky	bool dup = mlx4_is_mf_bonded(dev);
481329159Shselasky	u8 dup_port = (port == 1) ? 2 : 1;
482329159Shselasky	struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
483255932Salfred
484255932Salfred	/* CX1 doesn't support multi-functions */
485329159Shselasky	if (dup) {
486329159Shselasky		if (port == 1) {
487329159Shselasky			mutex_lock(&table->mutex);
488329159Shselasky			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
489329159Shselasky		} else {
490329159Shselasky			mutex_lock(&dup_table->mutex);
491329159Shselasky			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
492329159Shselasky		}
493329159Shselasky	} else {
494329159Shselasky		mutex_lock(&table->mutex);
495329159Shselasky	}
496255932Salfred
497255932Salfred	err = validate_index(dev, table, index);
498255932Salfred	if (err)
499255932Salfred		goto out;
500255932Salfred
501255932Salfred	table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
502255932Salfred
503255932Salfred	err = mlx4_set_port_mac_table(dev, port, table->entries);
504255932Salfred	if (unlikely(err)) {
505255932Salfred		mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
506255932Salfred			 (unsigned long long) new_mac);
507255932Salfred		table->entries[index] = 0;
508329159Shselasky	} else {
509329159Shselasky		if (dup) {
510329159Shselasky			dup_table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
511329159Shselasky
512329159Shselasky			err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries);
513329159Shselasky			if (unlikely(err)) {
514329159Shselasky				mlx4_err(dev, "Failed adding duplicate MAC: 0x%llx\n",
515329159Shselasky					 (unsigned long long)new_mac);
516329159Shselasky				dup_table->entries[index] = 0;
517329159Shselasky			}
518329159Shselasky		}
519255932Salfred	}
520255932Salfredout:
521329159Shselasky	if (dup) {
522329159Shselasky		if (port == 2) {
523329159Shselasky			mutex_unlock(&table->mutex);
524329159Shselasky			mutex_unlock(&dup_table->mutex);
525329159Shselasky		} else {
526329159Shselasky			mutex_unlock(&dup_table->mutex);
527329159Shselasky			mutex_unlock(&table->mutex);
528329159Shselasky		}
529329159Shselasky	} else {
530329159Shselasky		mutex_unlock(&table->mutex);
531329159Shselasky	}
532255932Salfred	return err;
533255932Salfred}
534255932SalfredEXPORT_SYMBOL_GPL(__mlx4_replace_mac);
535255932Salfred
536219820Sjeffstatic int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
537219820Sjeff				    __be32 *entries)
538219820Sjeff{
539219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
540219820Sjeff	u32 in_mod;
541219820Sjeff	int err;
542219820Sjeff
543219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
544219820Sjeff	if (IS_ERR(mailbox))
545219820Sjeff		return PTR_ERR(mailbox);
546219820Sjeff
547219820Sjeff	memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE);
548219820Sjeff	in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port;
549329159Shselasky	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
550329159Shselasky		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
551329159Shselasky		       MLX4_CMD_NATIVE);
552219820Sjeff
553219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
554219820Sjeff
555219820Sjeff	return err;
556219820Sjeff}
557219820Sjeff
558219820Sjeffint mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
559219820Sjeff{
560219820Sjeff	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
561219820Sjeff	int i;
562219820Sjeff
563219820Sjeff	for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) {
564219820Sjeff		if (table->refs[i] &&
565219820Sjeff		    (vid == (MLX4_VLAN_MASK &
566219820Sjeff			      be32_to_cpu(table->entries[i])))) {
567255932Salfred			/* VLAN already registered, increase reference count */
568219820Sjeff			*idx = i;
569219820Sjeff			return 0;
570219820Sjeff		}
571219820Sjeff	}
572219820Sjeff
573219820Sjeff	return -ENOENT;
574219820Sjeff}
575219820SjeffEXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
576219820Sjeff
577255932Salfredint __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
578255932Salfred				int *index)
579219820Sjeff{
580219820Sjeff	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
581219820Sjeff	int i, err = 0;
582219820Sjeff	int free = -1;
583329159Shselasky	int free_for_dup = -1;
584329159Shselasky	bool dup = mlx4_is_mf_bonded(dev);
585329159Shselasky	u8 dup_port = (port == 1) ? 2 : 1;
586329159Shselasky	struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table;
587329159Shselasky	bool need_mf_bond = mlx4_need_mf_bond(dev);
588329159Shselasky	bool can_mf_bond = true;
589219820Sjeff
590329159Shselasky	mlx4_dbg(dev, "Registering VLAN: %d for port %d %s duplicate\n",
591329159Shselasky		 vlan, port,
592329159Shselasky		 dup ? "with" : "without");
593255932Salfred
594329159Shselasky	if (need_mf_bond) {
595329159Shselasky		if (port == 1) {
596329159Shselasky			mutex_lock(&table->mutex);
597329159Shselasky			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
598329159Shselasky		} else {
599329159Shselasky			mutex_lock(&dup_table->mutex);
600329159Shselasky			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
601329159Shselasky		}
602329159Shselasky	} else {
603329159Shselasky		mutex_lock(&table->mutex);
604329159Shselasky	}
605329159Shselasky
606255932Salfred	if (table->total == table->max) {
607255932Salfred		/* No free vlan entries */
608255932Salfred		err = -ENOSPC;
609255932Salfred		goto out;
610255932Salfred	}
611255932Salfred
612329159Shselasky	if (need_mf_bond) {
613329159Shselasky		int index_at_port = -1;
614329159Shselasky		int index_at_dup_port = -1;
615329159Shselasky
616329159Shselasky		for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
617329159Shselasky			if (vlan == (MLX4_VLAN_MASK & be32_to_cpu(table->entries[i])))
618329159Shselasky				index_at_port = i;
619329159Shselasky			if (vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i])))
620329159Shselasky				index_at_dup_port = i;
621329159Shselasky		}
622329159Shselasky		/* check that same vlan is not in the tables at different indices */
623329159Shselasky		if ((index_at_port != index_at_dup_port) &&
624329159Shselasky		    (index_at_port >= 0) &&
625329159Shselasky		    (index_at_dup_port >= 0))
626329159Shselasky			can_mf_bond = false;
627329159Shselasky
628329159Shselasky		/* If the vlan is already in the primary table, the slot must be
629329159Shselasky		 * available in the duplicate table as well.
630329159Shselasky		 */
631329159Shselasky		if (index_at_port >= 0 && index_at_dup_port < 0 &&
632329159Shselasky		    dup_table->refs[index_at_port]) {
633329159Shselasky			can_mf_bond = false;
634329159Shselasky		}
635329159Shselasky		/* If the vlan is already in the duplicate table, check that the
636329159Shselasky		 * corresponding index is not occupied in the primary table, or
637329159Shselasky		 * the primary table already contains the vlan at the same index.
638329159Shselasky		 * Otherwise, you cannot bond (primary contains a different vlan
639329159Shselasky		 * at that index).
640329159Shselasky		 */
641329159Shselasky		if (index_at_dup_port >= 0) {
642329159Shselasky			if (!table->refs[index_at_dup_port] ||
643329159Shselasky			    (vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[index_at_dup_port]))))
644329159Shselasky				free_for_dup = index_at_dup_port;
645329159Shselasky			else
646329159Shselasky				can_mf_bond = false;
647329159Shselasky		}
648329159Shselasky	}
649329159Shselasky
650219820Sjeff	for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
651329159Shselasky		if (!table->refs[i]) {
652329159Shselasky			if (free < 0)
653329159Shselasky				free = i;
654329159Shselasky			if (free_for_dup < 0 && need_mf_bond && can_mf_bond) {
655329159Shselasky				if (!dup_table->refs[i])
656329159Shselasky					free_for_dup = i;
657329159Shselasky			}
658219820Sjeff		}
659219820Sjeff
660329159Shselasky		if ((table->refs[i] || table->is_dup[i]) &&
661219820Sjeff		    (vlan == (MLX4_VLAN_MASK &
662219820Sjeff			      be32_to_cpu(table->entries[i])))) {
663255932Salfred			/* Vlan already registered, increase references count */
664329159Shselasky			mlx4_dbg(dev, "vlan %u is already registered.\n", vlan);
665219820Sjeff			*index = i;
666219820Sjeff			++table->refs[i];
667329159Shselasky			if (dup) {
668329159Shselasky				u16 dup_vlan = MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i]);
669329159Shselasky
670329159Shselasky				if (dup_vlan != vlan || !dup_table->is_dup[i]) {
671329159Shselasky					mlx4_warn(dev, "register vlan: expected duplicate vlan %u on port %d index %d\n",
672329159Shselasky						  vlan, dup_port, i);
673329159Shselasky				}
674329159Shselasky			}
675219820Sjeff			goto out;
676219820Sjeff		}
677219820Sjeff	}
678219820Sjeff
679329159Shselasky	if (need_mf_bond && (free_for_dup < 0)) {
680329159Shselasky		if (dup) {
681329159Shselasky			mlx4_warn(dev, "Fail to allocate duplicate VLAN table entry\n");
682329159Shselasky			mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n");
683329159Shselasky			dup = false;
684329159Shselasky		}
685329159Shselasky		can_mf_bond = false;
686329159Shselasky	}
687329159Shselasky
688329159Shselasky	if (need_mf_bond && can_mf_bond)
689329159Shselasky		free = free_for_dup;
690329159Shselasky
691219820Sjeff	if (free < 0) {
692219820Sjeff		err = -ENOMEM;
693219820Sjeff		goto out;
694219820Sjeff	}
695219820Sjeff
696255932Salfred	/* Register new VLAN */
697219820Sjeff	table->refs[free] = 1;
698329159Shselasky	table->is_dup[free] = false;
699219820Sjeff	table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
700219820Sjeff
701219820Sjeff	err = mlx4_set_port_vlan_table(dev, port, table->entries);
702219820Sjeff	if (unlikely(err)) {
703219820Sjeff		mlx4_warn(dev, "Failed adding vlan: %u\n", vlan);
704219820Sjeff		table->refs[free] = 0;
705219820Sjeff		table->entries[free] = 0;
706219820Sjeff		goto out;
707219820Sjeff	}
708329159Shselasky	++table->total;
709329159Shselasky	if (dup) {
710329159Shselasky		dup_table->refs[free] = 0;
711329159Shselasky		dup_table->is_dup[free] = true;
712329159Shselasky		dup_table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
713219820Sjeff
714329159Shselasky		err = mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries);
715329159Shselasky		if (unlikely(err)) {
716329159Shselasky			mlx4_warn(dev, "Failed adding duplicate vlan: %u\n", vlan);
717329159Shselasky			dup_table->is_dup[free] = false;
718329159Shselasky			dup_table->entries[free] = 0;
719329159Shselasky			goto out;
720329159Shselasky		}
721329159Shselasky		++dup_table->total;
722329159Shselasky	}
723329159Shselasky
724219820Sjeff	*index = free;
725219820Sjeffout:
726329159Shselasky	if (need_mf_bond) {
727329159Shselasky		if (port == 2) {
728329159Shselasky			mutex_unlock(&table->mutex);
729329159Shselasky			mutex_unlock(&dup_table->mutex);
730329159Shselasky		} else {
731329159Shselasky			mutex_unlock(&dup_table->mutex);
732329159Shselasky			mutex_unlock(&table->mutex);
733329159Shselasky		}
734329159Shselasky	} else {
735329159Shselasky		mutex_unlock(&table->mutex);
736329159Shselasky	}
737219820Sjeff	return err;
738219820Sjeff}
739255932Salfred
740255932Salfredint mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
741255932Salfred{
742255932Salfred	u64 out_param = 0;
743255932Salfred	int err;
744255932Salfred
745255932Salfred	if (vlan > 4095)
746255932Salfred		return -EINVAL;
747255932Salfred
748255932Salfred	if (mlx4_is_mfunc(dev)) {
749255932Salfred		err = mlx4_cmd_imm(dev, vlan, &out_param,
750255932Salfred				   ((u32) port) << 8 | (u32) RES_VLAN,
751255932Salfred				   RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
752255932Salfred				   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
753255932Salfred		if (!err)
754255932Salfred			*index = get_param_l(&out_param);
755255932Salfred
756255932Salfred		return err;
757255932Salfred	}
758255932Salfred	return __mlx4_register_vlan(dev, port, vlan, index);
759255932Salfred}
760219820SjeffEXPORT_SYMBOL_GPL(mlx4_register_vlan);
761219820Sjeff
762255932Salfredvoid __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
763219820Sjeff{
764219820Sjeff	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
765255932Salfred	int index;
766329159Shselasky	bool dup = mlx4_is_mf_bonded(dev);
767329159Shselasky	u8 dup_port = (port == 1) ? 2 : 1;
768329159Shselasky	struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table;
769219820Sjeff
770329159Shselasky	if (dup) {
771329159Shselasky		if (port == 1) {
772329159Shselasky			mutex_lock(&table->mutex);
773329159Shselasky			mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
774329159Shselasky		} else {
775329159Shselasky			mutex_lock(&dup_table->mutex);
776329159Shselasky			mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
777329159Shselasky		}
778329159Shselasky	} else {
779329159Shselasky		mutex_lock(&table->mutex);
780329159Shselasky	}
781329159Shselasky
782255932Salfred	if (mlx4_find_cached_vlan(dev, port, vlan, &index)) {
783255932Salfred		mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan);
784255932Salfred		goto out;
785255932Salfred	}
786255932Salfred
787219820Sjeff	if (index < MLX4_VLAN_REGULAR) {
788219820Sjeff		mlx4_warn(dev, "Trying to free special vlan index %d\n", index);
789255932Salfred		goto out;
790219820Sjeff	}
791219820Sjeff
792329159Shselasky	if (--table->refs[index] || table->is_dup[index]) {
793329159Shselasky		mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n",
794329159Shselasky			 table->refs[index], index);
795329159Shselasky		if (!table->refs[index])
796329159Shselasky			dup_table->is_dup[index] = false;
797219820Sjeff		goto out;
798219820Sjeff	}
799219820Sjeff	table->entries[index] = 0;
800329159Shselasky	if (mlx4_set_port_vlan_table(dev, port, table->entries))
801329159Shselasky		mlx4_warn(dev, "Fail to set vlan in port %d during unregister\n", port);
802219820Sjeff	--table->total;
803329159Shselasky	if (dup) {
804329159Shselasky		dup_table->is_dup[index] = false;
805329159Shselasky		if (dup_table->refs[index])
806329159Shselasky			goto out;
807329159Shselasky		dup_table->entries[index] = 0;
808329159Shselasky		if (mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries))
809329159Shselasky			mlx4_warn(dev, "Fail to set vlan in duplicate port %d during unregister\n", dup_port);
810329159Shselasky		--dup_table->total;
811329159Shselasky	}
812219820Sjeffout:
813329159Shselasky	if (dup) {
814329159Shselasky		if (port == 2) {
815329159Shselasky			mutex_unlock(&table->mutex);
816329159Shselasky			mutex_unlock(&dup_table->mutex);
817329159Shselasky		} else {
818329159Shselasky			mutex_unlock(&dup_table->mutex);
819329159Shselasky			mutex_unlock(&table->mutex);
820329159Shselasky		}
821329159Shselasky	} else {
822329159Shselasky		mutex_unlock(&table->mutex);
823329159Shselasky	}
824219820Sjeff}
825255932Salfred
826255932Salfredvoid mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
827255932Salfred{
828255932Salfred	u64 out_param = 0;
829255932Salfred
830255932Salfred	if (mlx4_is_mfunc(dev)) {
831255932Salfred		(void) mlx4_cmd_imm(dev, vlan, &out_param,
832255932Salfred				    ((u32) port) << 8 | (u32) RES_VLAN,
833255932Salfred				    RES_OP_RESERVE_AND_MAP,
834255932Salfred				    MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A,
835255932Salfred				    MLX4_CMD_WRAPPED);
836255932Salfred		return;
837255932Salfred	}
838255932Salfred	__mlx4_unregister_vlan(dev, port, vlan);
839255932Salfred}
840219820SjeffEXPORT_SYMBOL_GPL(mlx4_unregister_vlan);
841219820Sjeff
842329159Shselaskyint mlx4_bond_mac_table(struct mlx4_dev *dev)
843329159Shselasky{
844329159Shselasky	struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table;
845329159Shselasky	struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table;
846329159Shselasky	int ret = 0;
847329159Shselasky	int i;
848329159Shselasky	bool update1 = false;
849329159Shselasky	bool update2 = false;
850329159Shselasky
851329159Shselasky	mutex_lock(&t1->mutex);
852329159Shselasky	mutex_lock(&t2->mutex);
853329159Shselasky	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
854329159Shselasky		if ((t1->entries[i] != t2->entries[i]) &&
855329159Shselasky		    t1->entries[i] && t2->entries[i]) {
856329159Shselasky			mlx4_warn(dev, "can't duplicate entry %d in mac table\n", i);
857329159Shselasky			ret = -EINVAL;
858329159Shselasky			goto unlock;
859329159Shselasky		}
860329159Shselasky	}
861329159Shselasky
862329159Shselasky	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
863329159Shselasky		if (t1->entries[i] && !t2->entries[i]) {
864329159Shselasky			t2->entries[i] = t1->entries[i];
865329159Shselasky			t2->is_dup[i] = true;
866329159Shselasky			update2 = true;
867329159Shselasky		} else if (!t1->entries[i] && t2->entries[i]) {
868329159Shselasky			t1->entries[i] = t2->entries[i];
869329159Shselasky			t1->is_dup[i] = true;
870329159Shselasky			update1 = true;
871329159Shselasky		} else if (t1->entries[i] && t2->entries[i]) {
872329159Shselasky			t1->is_dup[i] = true;
873329159Shselasky			t2->is_dup[i] = true;
874329159Shselasky		}
875329159Shselasky	}
876329159Shselasky
877329159Shselasky	if (update1) {
878329159Shselasky		ret = mlx4_set_port_mac_table(dev, 1, t1->entries);
879329159Shselasky		if (ret)
880329159Shselasky			mlx4_warn(dev, "failed to set MAC table for port 1 (%d)\n", ret);
881329159Shselasky	}
882329159Shselasky	if (!ret && update2) {
883329159Shselasky		ret = mlx4_set_port_mac_table(dev, 2, t2->entries);
884329159Shselasky		if (ret)
885329159Shselasky			mlx4_warn(dev, "failed to set MAC table for port 2 (%d)\n", ret);
886329159Shselasky	}
887329159Shselasky
888329159Shselasky	if (ret)
889329159Shselasky		mlx4_warn(dev, "failed to create mirror MAC tables\n");
890329159Shselaskyunlock:
891329159Shselasky	mutex_unlock(&t2->mutex);
892329159Shselasky	mutex_unlock(&t1->mutex);
893329159Shselasky	return ret;
894329159Shselasky}
895329159Shselasky
896329159Shselaskyint mlx4_unbond_mac_table(struct mlx4_dev *dev)
897329159Shselasky{
898329159Shselasky	struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table;
899329159Shselasky	struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table;
900329159Shselasky	int ret = 0;
901329159Shselasky	int ret1;
902329159Shselasky	int i;
903329159Shselasky	bool update1 = false;
904329159Shselasky	bool update2 = false;
905329159Shselasky
906329159Shselasky	mutex_lock(&t1->mutex);
907329159Shselasky	mutex_lock(&t2->mutex);
908329159Shselasky	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
909329159Shselasky		if (t1->entries[i] != t2->entries[i]) {
910329159Shselasky			mlx4_warn(dev, "mac table is in an unexpected state when trying to unbond\n");
911329159Shselasky			ret = -EINVAL;
912329159Shselasky			goto unlock;
913329159Shselasky		}
914329159Shselasky	}
915329159Shselasky
916329159Shselasky	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
917329159Shselasky		if (!t1->entries[i])
918329159Shselasky			continue;
919329159Shselasky		t1->is_dup[i] = false;
920329159Shselasky		if (!t1->refs[i]) {
921329159Shselasky			t1->entries[i] = 0;
922329159Shselasky			update1 = true;
923329159Shselasky		}
924329159Shselasky		t2->is_dup[i] = false;
925329159Shselasky		if (!t2->refs[i]) {
926329159Shselasky			t2->entries[i] = 0;
927329159Shselasky			update2 = true;
928329159Shselasky		}
929329159Shselasky	}
930329159Shselasky
931329159Shselasky	if (update1) {
932329159Shselasky		ret = mlx4_set_port_mac_table(dev, 1, t1->entries);
933329159Shselasky		if (ret)
934329159Shselasky			mlx4_warn(dev, "failed to unmirror MAC tables for port 1(%d)\n", ret);
935329159Shselasky	}
936329159Shselasky	if (update2) {
937329159Shselasky		ret1 = mlx4_set_port_mac_table(dev, 2, t2->entries);
938329159Shselasky		if (ret1) {
939329159Shselasky			mlx4_warn(dev, "failed to unmirror MAC tables for port 2(%d)\n", ret1);
940329159Shselasky			ret = ret1;
941329159Shselasky		}
942329159Shselasky	}
943329159Shselaskyunlock:
944329159Shselasky	mutex_unlock(&t2->mutex);
945329159Shselasky	mutex_unlock(&t1->mutex);
946329159Shselasky	return ret;
947329159Shselasky}
948329159Shselasky
949329159Shselaskyint mlx4_bond_vlan_table(struct mlx4_dev *dev)
950329159Shselasky{
951329159Shselasky	struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table;
952329159Shselasky	struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table;
953329159Shselasky	int ret = 0;
954329159Shselasky	int i;
955329159Shselasky	bool update1 = false;
956329159Shselasky	bool update2 = false;
957329159Shselasky
958329159Shselasky	mutex_lock(&t1->mutex);
959329159Shselasky	mutex_lock(&t2->mutex);
960329159Shselasky	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
961329159Shselasky		if ((t1->entries[i] != t2->entries[i]) &&
962329159Shselasky		    t1->entries[i] && t2->entries[i]) {
963329159Shselasky			mlx4_warn(dev, "can't duplicate entry %d in vlan table\n", i);
964329159Shselasky			ret = -EINVAL;
965329159Shselasky			goto unlock;
966329159Shselasky		}
967329159Shselasky	}
968329159Shselasky
969329159Shselasky	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
970329159Shselasky		if (t1->entries[i] && !t2->entries[i]) {
971329159Shselasky			t2->entries[i] = t1->entries[i];
972329159Shselasky			t2->is_dup[i] = true;
973329159Shselasky			update2 = true;
974329159Shselasky		} else if (!t1->entries[i] && t2->entries[i]) {
975329159Shselasky			t1->entries[i] = t2->entries[i];
976329159Shselasky			t1->is_dup[i] = true;
977329159Shselasky			update1 = true;
978329159Shselasky		} else if (t1->entries[i] && t2->entries[i]) {
979329159Shselasky			t1->is_dup[i] = true;
980329159Shselasky			t2->is_dup[i] = true;
981329159Shselasky		}
982329159Shselasky	}
983329159Shselasky
984329159Shselasky	if (update1) {
985329159Shselasky		ret = mlx4_set_port_vlan_table(dev, 1, t1->entries);
986329159Shselasky		if (ret)
987329159Shselasky			mlx4_warn(dev, "failed to set VLAN table for port 1 (%d)\n", ret);
988329159Shselasky	}
989329159Shselasky	if (!ret && update2) {
990329159Shselasky		ret = mlx4_set_port_vlan_table(dev, 2, t2->entries);
991329159Shselasky		if (ret)
992329159Shselasky			mlx4_warn(dev, "failed to set VLAN table for port 2 (%d)\n", ret);
993329159Shselasky	}
994329159Shselasky
995329159Shselasky	if (ret)
996329159Shselasky		mlx4_warn(dev, "failed to create mirror VLAN tables\n");
997329159Shselaskyunlock:
998329159Shselasky	mutex_unlock(&t2->mutex);
999329159Shselasky	mutex_unlock(&t1->mutex);
1000329159Shselasky	return ret;
1001329159Shselasky}
1002329159Shselasky
1003329159Shselaskyint mlx4_unbond_vlan_table(struct mlx4_dev *dev)
1004329159Shselasky{
1005329159Shselasky	struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table;
1006329159Shselasky	struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table;
1007329159Shselasky	int ret = 0;
1008329159Shselasky	int ret1;
1009329159Shselasky	int i;
1010329159Shselasky	bool update1 = false;
1011329159Shselasky	bool update2 = false;
1012329159Shselasky
1013329159Shselasky	mutex_lock(&t1->mutex);
1014329159Shselasky	mutex_lock(&t2->mutex);
1015329159Shselasky	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
1016329159Shselasky		if (t1->entries[i] != t2->entries[i]) {
1017329159Shselasky			mlx4_warn(dev, "vlan table is in an unexpected state when trying to unbond\n");
1018329159Shselasky			ret = -EINVAL;
1019329159Shselasky			goto unlock;
1020329159Shselasky		}
1021329159Shselasky	}
1022329159Shselasky
1023329159Shselasky	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
1024329159Shselasky		if (!t1->entries[i])
1025329159Shselasky			continue;
1026329159Shselasky		t1->is_dup[i] = false;
1027329159Shselasky		if (!t1->refs[i]) {
1028329159Shselasky			t1->entries[i] = 0;
1029329159Shselasky			update1 = true;
1030329159Shselasky		}
1031329159Shselasky		t2->is_dup[i] = false;
1032329159Shselasky		if (!t2->refs[i]) {
1033329159Shselasky			t2->entries[i] = 0;
1034329159Shselasky			update2 = true;
1035329159Shselasky		}
1036329159Shselasky	}
1037329159Shselasky
1038329159Shselasky	if (update1) {
1039329159Shselasky		ret = mlx4_set_port_vlan_table(dev, 1, t1->entries);
1040329159Shselasky		if (ret)
1041329159Shselasky			mlx4_warn(dev, "failed to unmirror VLAN tables for port 1(%d)\n", ret);
1042329159Shselasky	}
1043329159Shselasky	if (update2) {
1044329159Shselasky		ret1 = mlx4_set_port_vlan_table(dev, 2, t2->entries);
1045329159Shselasky		if (ret1) {
1046329159Shselasky			mlx4_warn(dev, "failed to unmirror VLAN tables for port 2(%d)\n", ret1);
1047329159Shselasky			ret = ret1;
1048329159Shselasky		}
1049329159Shselasky	}
1050329159Shselaskyunlock:
1051329159Shselasky	mutex_unlock(&t2->mutex);
1052329159Shselasky	mutex_unlock(&t1->mutex);
1053329159Shselasky	return ret;
1054329159Shselasky}
1055329159Shselasky
1056219820Sjeffint mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
1057219820Sjeff{
1058219820Sjeff	struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
1059219820Sjeff	u8 *inbuf, *outbuf;
1060219820Sjeff	int err;
1061219820Sjeff
1062219820Sjeff	inmailbox = mlx4_alloc_cmd_mailbox(dev);
1063219820Sjeff	if (IS_ERR(inmailbox))
1064219820Sjeff		return PTR_ERR(inmailbox);
1065219820Sjeff
1066219820Sjeff	outmailbox = mlx4_alloc_cmd_mailbox(dev);
1067219820Sjeff	if (IS_ERR(outmailbox)) {
1068219820Sjeff		mlx4_free_cmd_mailbox(dev, inmailbox);
1069219820Sjeff		return PTR_ERR(outmailbox);
1070219820Sjeff	}
1071219820Sjeff
1072219820Sjeff	inbuf = inmailbox->buf;
1073219820Sjeff	outbuf = outmailbox->buf;
1074219820Sjeff	inbuf[0] = 1;
1075219820Sjeff	inbuf[1] = 1;
1076219820Sjeff	inbuf[2] = 1;
1077219820Sjeff	inbuf[3] = 1;
1078219820Sjeff	*(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015);
1079219820Sjeff	*(__be32 *) (&inbuf[20]) = cpu_to_be32(port);
1080219820Sjeff
1081219820Sjeff	err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3,
1082255932Salfred			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
1083255932Salfred			   MLX4_CMD_NATIVE);
1084219820Sjeff	if (!err)
1085219820Sjeff		*caps = *(__be32 *) (outbuf + 84);
1086219820Sjeff	mlx4_free_cmd_mailbox(dev, inmailbox);
1087219820Sjeff	mlx4_free_cmd_mailbox(dev, outmailbox);
1088219820Sjeff	return err;
1089219820Sjeff}
1090255932Salfredstatic struct mlx4_roce_gid_entry zgid_entry;
1091219820Sjeff
1092329159Shselaskyint mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port)
1093219820Sjeff{
1094329159Shselasky	int vfs;
1095329159Shselasky	int slave_gid = slave;
1096329159Shselasky	unsigned i;
1097329159Shselasky	struct mlx4_slaves_pport slaves_pport;
1098329159Shselasky	struct mlx4_active_ports actv_ports;
1099329159Shselasky	unsigned max_port_p_one;
1100329159Shselasky
1101255932Salfred	if (slave == 0)
1102255932Salfred		return MLX4_ROCE_PF_GIDS;
1103329159Shselasky
1104329159Shselasky	/* Slave is a VF */
1105329159Shselasky	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1106329159Shselasky	actv_ports = mlx4_get_active_ports(dev, slave);
1107329159Shselasky	max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
1108329159Shselasky		bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
1109329159Shselasky
1110329159Shselasky	for (i = 1; i < max_port_p_one; i++) {
1111329159Shselasky		struct mlx4_active_ports exclusive_ports;
1112329159Shselasky		struct mlx4_slaves_pport slaves_pport_actv;
1113329159Shselasky		bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
1114329159Shselasky		set_bit(i - 1, exclusive_ports.ports);
1115329159Shselasky		if (i == port)
1116329159Shselasky			continue;
1117329159Shselasky		slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
1118329159Shselasky				    dev, &exclusive_ports);
1119329159Shselasky		slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
1120329159Shselasky					   dev->persist->num_vfs + 1);
1121329159Shselasky	}
1122329159Shselasky	vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1;
1123329159Shselasky	if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs))
1124329159Shselasky		return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1;
1125329159Shselasky	return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs;
1126255932Salfred}
1127255932Salfred
1128329159Shselaskyint mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port)
1129255932Salfred{
1130255932Salfred	int gids;
1131329159Shselasky	unsigned i;
1132329159Shselasky	int slave_gid = slave;
1133255932Salfred	int vfs;
1134255932Salfred
1135329159Shselasky	struct mlx4_slaves_pport slaves_pport;
1136329159Shselasky	struct mlx4_active_ports actv_ports;
1137329159Shselasky	unsigned max_port_p_one;
1138255932Salfred
1139255932Salfred	if (slave == 0)
1140255932Salfred		return 0;
1141255932Salfred
1142329159Shselasky	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1143329159Shselasky	actv_ports = mlx4_get_active_ports(dev, slave);
1144329159Shselasky	max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
1145329159Shselasky		bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
1146329159Shselasky
1147329159Shselasky	for (i = 1; i < max_port_p_one; i++) {
1148329159Shselasky		struct mlx4_active_ports exclusive_ports;
1149329159Shselasky		struct mlx4_slaves_pport slaves_pport_actv;
1150329159Shselasky		bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
1151329159Shselasky		set_bit(i - 1, exclusive_ports.ports);
1152329159Shselasky		if (i == port)
1153329159Shselasky			continue;
1154329159Shselasky		slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
1155329159Shselasky				    dev, &exclusive_ports);
1156329159Shselasky		slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
1157329159Shselasky					   dev->persist->num_vfs + 1);
1158329159Shselasky	}
1159329159Shselasky	gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
1160329159Shselasky	vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1;
1161329159Shselasky	if (slave_gid <= gids % vfs)
1162329159Shselasky		return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1);
1163329159Shselasky
1164329159Shselasky	return MLX4_ROCE_PF_GIDS + (gids % vfs) +
1165329159Shselasky		((gids / vfs) * (slave_gid - 1));
1166255932Salfred}
1167329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix);
1168255932Salfred
1169329159Shselaskystatic int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave,
1170329159Shselasky				     int port, struct mlx4_cmd_mailbox *mailbox)
1171329159Shselasky{
1172329159Shselasky	struct mlx4_roce_gid_entry *gid_entry_mbox;
1173329159Shselasky	struct mlx4_priv *priv = mlx4_priv(dev);
1174329159Shselasky	int num_gids, base, offset;
1175329159Shselasky	int i, err;
1176329159Shselasky
1177329159Shselasky	num_gids = mlx4_get_slave_num_gids(dev, slave, port);
1178329159Shselasky	base = mlx4_get_base_gid_ix(dev, slave, port);
1179329159Shselasky
1180329159Shselasky	memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE);
1181329159Shselasky
1182329159Shselasky	mutex_lock(&(priv->port[port].gid_table.mutex));
1183329159Shselasky	/* Zero-out gids belonging to that slave in the port GID table */
1184329159Shselasky	for (i = 0, offset = base; i < num_gids; offset++, i++)
1185329159Shselasky		memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
1186329159Shselasky		       zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE);
1187329159Shselasky
1188329159Shselasky	/* Now, copy roce port gids table to mailbox for passing to FW */
1189329159Shselasky	gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf;
1190329159Shselasky	for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
1191329159Shselasky		memcpy(gid_entry_mbox->raw,
1192329159Shselasky		       priv->port[port].gid_table.roce_gids[i].raw,
1193329159Shselasky		       MLX4_ROCE_GID_ENTRY_SIZE);
1194329159Shselasky
1195329159Shselasky	err = mlx4_cmd(dev, mailbox->dma,
1196329159Shselasky		       ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8),
1197329159Shselasky		       MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT,
1198329159Shselasky		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
1199329159Shselasky	mutex_unlock(&(priv->port[port].gid_table.mutex));
1200329159Shselasky	return err;
1201329159Shselasky}
1202329159Shselasky
1203329159Shselasky
1204329159Shselaskyvoid mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave)
1205329159Shselasky{
1206329159Shselasky	struct mlx4_active_ports actv_ports;
1207329159Shselasky	struct mlx4_cmd_mailbox *mailbox;
1208329159Shselasky	int num_eth_ports, err;
1209329159Shselasky	int i;
1210329159Shselasky
1211329159Shselasky	if (slave < 0 || slave > dev->persist->num_vfs)
1212329159Shselasky		return;
1213329159Shselasky
1214329159Shselasky	actv_ports = mlx4_get_active_ports(dev, slave);
1215329159Shselasky
1216329159Shselasky	for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) {
1217329159Shselasky		if (test_bit(i, actv_ports.ports)) {
1218329159Shselasky			if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
1219329159Shselasky				continue;
1220329159Shselasky			num_eth_ports++;
1221329159Shselasky		}
1222329159Shselasky	}
1223329159Shselasky
1224329159Shselasky	if (!num_eth_ports)
1225329159Shselasky		return;
1226329159Shselasky
1227329159Shselasky	/* have ETH ports.  Alloc mailbox for SET_PORT command */
1228329159Shselasky	mailbox = mlx4_alloc_cmd_mailbox(dev);
1229329159Shselasky	if (IS_ERR(mailbox))
1230329159Shselasky		return;
1231329159Shselasky
1232329159Shselasky	for (i = 0; i < dev->caps.num_ports; i++) {
1233329159Shselasky		if (test_bit(i, actv_ports.ports)) {
1234329159Shselasky			if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
1235329159Shselasky				continue;
1236329159Shselasky			err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox);
1237329159Shselasky			if (err)
1238329159Shselasky				mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n",
1239329159Shselasky					  slave, i + 1, err);
1240329159Shselasky		}
1241329159Shselasky	}
1242329159Shselasky
1243329159Shselasky	mlx4_free_cmd_mailbox(dev, mailbox);
1244329159Shselasky	return;
1245329159Shselasky}
1246329159Shselasky
1247255932Salfredstatic int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
1248255932Salfred				u8 op_mod, struct mlx4_cmd_mailbox *inbox)
1249255932Salfred{
1250255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
1251255932Salfred	struct mlx4_port_info *port_info;
1252255932Salfred	struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
1253255932Salfred	struct mlx4_slave_state *slave_st = &master->slave_state[slave];
1254255932Salfred	struct mlx4_set_port_rqp_calc_context *qpn_context;
1255255932Salfred	struct mlx4_set_port_general_context *gen_context;
1256255932Salfred	struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1;
1257255932Salfred	int reset_qkey_viols;
1258255932Salfred	int port;
1259255932Salfred	int is_eth;
1260255932Salfred	int num_gids;
1261255932Salfred	int base;
1262255932Salfred	u32 in_modifier;
1263255932Salfred	u32 promisc;
1264255932Salfred	u16 mtu, prev_mtu;
1265219820Sjeff	int err;
1266255932Salfred	int i, j;
1267255932Salfred	int offset;
1268255932Salfred	__be32 agg_cap_mask;
1269255932Salfred	__be32 slave_cap_mask;
1270255932Salfred	__be32 new_cap_mask;
1271219820Sjeff
1272255932Salfred	port = in_mod & 0xff;
1273329159Shselasky	in_modifier = in_mod >> 8;
1274255932Salfred	is_eth = op_mod;
1275255932Salfred	port_info = &priv->port[port];
1276255932Salfred
1277255932Salfred	/* Slaves cannot perform SET_PORT operations except changing MTU */
1278255932Salfred	if (is_eth) {
1279255932Salfred		if (slave != dev->caps.function &&
1280255932Salfred		    in_modifier != MLX4_SET_PORT_GENERAL &&
1281255932Salfred		    in_modifier != MLX4_SET_PORT_GID_TABLE) {
1282329159Shselasky			mlx4_warn(dev, "denying SET_PORT for slave:%d\n",
1283329159Shselasky					slave);
1284255932Salfred			return -EINVAL;
1285255932Salfred		}
1286255932Salfred		switch (in_modifier) {
1287255932Salfred		case MLX4_SET_PORT_RQP_CALC:
1288255932Salfred			qpn_context = inbox->buf;
1289255932Salfred			qpn_context->base_qpn =
1290255932Salfred				cpu_to_be32(port_info->base_qpn);
1291255932Salfred			qpn_context->n_mac = 0x7;
1292255932Salfred			promisc = be32_to_cpu(qpn_context->promisc) >>
1293255932Salfred				SET_PORT_PROMISC_SHIFT;
1294255932Salfred			qpn_context->promisc = cpu_to_be32(
1295255932Salfred				promisc << SET_PORT_PROMISC_SHIFT |
1296255932Salfred				port_info->base_qpn);
1297255932Salfred			promisc = be32_to_cpu(qpn_context->mcast) >>
1298255932Salfred				SET_PORT_MC_PROMISC_SHIFT;
1299255932Salfred			qpn_context->mcast = cpu_to_be32(
1300255932Salfred				promisc << SET_PORT_MC_PROMISC_SHIFT |
1301255932Salfred				port_info->base_qpn);
1302255932Salfred			break;
1303255932Salfred		case MLX4_SET_PORT_GENERAL:
1304255932Salfred			gen_context = inbox->buf;
1305255932Salfred			/* Mtu is configured as the max MTU among all the
1306255932Salfred			 * the functions on the port. */
1307255932Salfred			mtu = be16_to_cpu(gen_context->mtu);
1308272027Shselasky			mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] +
1309272027Shselasky				    ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
1310255932Salfred			prev_mtu = slave_st->mtu[port];
1311255932Salfred			slave_st->mtu[port] = mtu;
1312255932Salfred			if (mtu > master->max_mtu[port])
1313255932Salfred				master->max_mtu[port] = mtu;
1314255932Salfred			if (mtu < prev_mtu && prev_mtu ==
1315255932Salfred						master->max_mtu[port]) {
1316255932Salfred				slave_st->mtu[port] = mtu;
1317255932Salfred				master->max_mtu[port] = mtu;
1318255932Salfred				for (i = 0; i < dev->num_slaves; i++) {
1319255932Salfred					master->max_mtu[port] =
1320255932Salfred					max(master->max_mtu[port],
1321255932Salfred					    master->slave_state[i].mtu[port]);
1322255932Salfred				}
1323255932Salfred			}
1324255932Salfred
1325255932Salfred			gen_context->mtu = cpu_to_be16(master->max_mtu[port]);
1326329159Shselasky			/* Slave cannot change Global Pause configuration */
1327329159Shselasky			if (slave != mlx4_master_func_num(dev) &&
1328329159Shselasky			    ((gen_context->pptx != master->pptx) ||
1329329159Shselasky			     (gen_context->pprx != master->pprx))) {
1330329159Shselasky				gen_context->pptx = master->pptx;
1331329159Shselasky				gen_context->pprx = master->pprx;
1332329159Shselasky				mlx4_warn(dev,
1333329159Shselasky					  "denying Global Pause change for slave:%d\n",
1334329159Shselasky					  slave);
1335329159Shselasky			} else {
1336329159Shselasky				master->pptx = gen_context->pptx;
1337329159Shselasky				master->pprx = gen_context->pprx;
1338329159Shselasky			}
1339255932Salfred			break;
1340255932Salfred		case MLX4_SET_PORT_GID_TABLE:
1341255932Salfred			/* change to MULTIPLE entries: number of guest's gids
1342255932Salfred			 * need a FOR-loop here over number of gids the guest has.
1343255932Salfred			 * 1. Check no duplicates in gids passed by slave
1344255932Salfred			 */
1345329159Shselasky			num_gids = mlx4_get_slave_num_gids(dev, slave, port);
1346329159Shselasky			base = mlx4_get_base_gid_ix(dev, slave, port);
1347329159Shselasky			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1348255932Salfred			for (i = 0; i < num_gids; gid_entry_mbox++, i++) {
1349255932Salfred				if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
1350255932Salfred					    sizeof(zgid_entry)))
1351255932Salfred					continue;
1352255932Salfred				gid_entry_mb1 = gid_entry_mbox + 1;
1353255932Salfred				for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) {
1354255932Salfred					if (!memcmp(gid_entry_mb1->raw,
1355255932Salfred						    zgid_entry.raw, sizeof(zgid_entry)))
1356255932Salfred						continue;
1357255932Salfred					if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw,
1358255932Salfred						    sizeof(gid_entry_mbox->raw))) {
1359255932Salfred						/* found duplicate */
1360255932Salfred						return -EINVAL;
1361255932Salfred					}
1362255932Salfred				}
1363255932Salfred			}
1364255932Salfred
1365255932Salfred			/* 2. Check that do not have duplicates in OTHER
1366255932Salfred			 *    entries in the port GID table
1367255932Salfred			 */
1368329159Shselasky
1369329159Shselasky			mutex_lock(&(priv->port[port].gid_table.mutex));
1370255932Salfred			for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
1371255932Salfred				if (i >= base && i < base + num_gids)
1372255932Salfred					continue; /* don't compare to slave's current gids */
1373329159Shselasky				gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i];
1374255932Salfred				if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry)))
1375255932Salfred					continue;
1376329159Shselasky				gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1377255932Salfred				for (j = 0; j < num_gids; gid_entry_mbox++, j++) {
1378255932Salfred					if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
1379255932Salfred						    sizeof(zgid_entry)))
1380255932Salfred						continue;
1381255932Salfred					if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw,
1382255932Salfred						    sizeof(gid_entry_tbl->raw))) {
1383255932Salfred						/* found duplicate */
1384329159Shselasky						mlx4_warn(dev, "requested gid entry for slave:%d is a duplicate of gid at index %d\n",
1385255932Salfred							  slave, i);
1386329159Shselasky						mutex_unlock(&(priv->port[port].gid_table.mutex));
1387255932Salfred						return -EINVAL;
1388255932Salfred					}
1389255932Salfred				}
1390255932Salfred			}
1391255932Salfred
1392255932Salfred			/* insert slave GIDs with memcpy, starting at slave's base index */
1393329159Shselasky			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1394255932Salfred			for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++)
1395329159Shselasky				memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
1396329159Shselasky				       gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE);
1397255932Salfred
1398255932Salfred			/* Now, copy roce port gids table to current mailbox for passing to FW */
1399329159Shselasky			gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
1400255932Salfred			for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
1401329159Shselasky				memcpy(gid_entry_mbox->raw,
1402329159Shselasky				       priv->port[port].gid_table.roce_gids[i].raw,
1403329159Shselasky				       MLX4_ROCE_GID_ENTRY_SIZE);
1404255932Salfred
1405329159Shselasky			err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
1406329159Shselasky				       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1407329159Shselasky				       MLX4_CMD_NATIVE);
1408329159Shselasky			mutex_unlock(&(priv->port[port].gid_table.mutex));
1409329159Shselasky			return err;
1410255932Salfred		}
1411329159Shselasky
1412272027Shselasky		return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
1413255932Salfred				MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1414255932Salfred				MLX4_CMD_NATIVE);
1415255932Salfred	}
1416255932Salfred
1417329159Shselasky	/* Slaves are not allowed to SET_PORT beacon (LED) blink */
1418329159Shselasky	if (op_mod == MLX4_SET_PORT_BEACON_OPCODE) {
1419329159Shselasky		mlx4_warn(dev, "denying SET_PORT Beacon slave:%d\n", slave);
1420329159Shselasky		return -EPERM;
1421329159Shselasky	}
1422329159Shselasky
1423255932Salfred	/* For IB, we only consider:
1424255932Salfred	 * - The capability mask, which is set to the aggregate of all
1425255932Salfred	 *   slave function capabilities
1426255932Salfred	 * - The QKey violatin counter - reset according to each request.
1427255932Salfred	 */
1428255932Salfred
1429255932Salfred	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
1430255932Salfred		reset_qkey_viols = (*(u8 *) inbox->buf) & 0x40;
1431255932Salfred		new_cap_mask = ((__be32 *) inbox->buf)[2];
1432255932Salfred	} else {
1433255932Salfred		reset_qkey_viols = ((u8 *) inbox->buf)[3] & 0x1;
1434255932Salfred		new_cap_mask = ((__be32 *) inbox->buf)[1];
1435255932Salfred	}
1436255932Salfred
1437255932Salfred	/* slave may not set the IS_SM capability for the port */
1438255932Salfred	if (slave != mlx4_master_func_num(dev) &&
1439255932Salfred	    (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_IS_SM))
1440255932Salfred		return -EINVAL;
1441255932Salfred
1442255932Salfred	/* No DEV_MGMT in multifunc mode */
1443255932Salfred	if (mlx4_is_mfunc(dev) &&
1444255932Salfred	    (be32_to_cpu(new_cap_mask) & MLX4_PORT_CAP_DEV_MGMT_SUP))
1445255932Salfred		return -EINVAL;
1446255932Salfred
1447255932Salfred	agg_cap_mask = 0;
1448255932Salfred	slave_cap_mask =
1449255932Salfred		priv->mfunc.master.slave_state[slave].ib_cap_mask[port];
1450255932Salfred	priv->mfunc.master.slave_state[slave].ib_cap_mask[port] = new_cap_mask;
1451255932Salfred	for (i = 0; i < dev->num_slaves; i++)
1452255932Salfred		agg_cap_mask |=
1453255932Salfred			priv->mfunc.master.slave_state[i].ib_cap_mask[port];
1454255932Salfred
1455255932Salfred	/* only clear mailbox for guests.  Master may be setting
1456255932Salfred	* MTU or PKEY table size
1457255932Salfred	*/
1458255932Salfred	if (slave != dev->caps.function)
1459255932Salfred		memset(inbox->buf, 0, 256);
1460255932Salfred	if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
1461255932Salfred		*(u8 *) inbox->buf	   |= !!reset_qkey_viols << 6;
1462255932Salfred		((__be32 *) inbox->buf)[2] = agg_cap_mask;
1463255932Salfred	} else {
1464255932Salfred		((u8 *) inbox->buf)[3]     |= !!reset_qkey_viols;
1465255932Salfred		((__be32 *) inbox->buf)[1] = agg_cap_mask;
1466255932Salfred	}
1467255932Salfred
1468255932Salfred	err = mlx4_cmd(dev, inbox->dma, port, is_eth, MLX4_CMD_SET_PORT,
1469255932Salfred		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
1470255932Salfred	if (err)
1471255932Salfred		priv->mfunc.master.slave_state[slave].ib_cap_mask[port] =
1472255932Salfred			slave_cap_mask;
1473255932Salfred	return err;
1474255932Salfred}
1475255932Salfred
1476255932Salfredint mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave,
1477255932Salfred			  struct mlx4_vhcr *vhcr,
1478255932Salfred			  struct mlx4_cmd_mailbox *inbox,
1479255932Salfred			  struct mlx4_cmd_mailbox *outbox,
1480255932Salfred			  struct mlx4_cmd_info *cmd)
1481255932Salfred{
1482329159Shselasky	int port = mlx4_slave_convert_port(
1483329159Shselasky			dev, slave, vhcr->in_modifier & 0xFF);
1484329159Shselasky
1485329159Shselasky	if (port < 0)
1486329159Shselasky		return -EINVAL;
1487329159Shselasky
1488329159Shselasky	vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) |
1489329159Shselasky			    (port & 0xFF);
1490329159Shselasky
1491255932Salfred	return mlx4_common_set_port(dev, slave, vhcr->in_modifier,
1492255932Salfred				    vhcr->op_modifier, inbox);
1493255932Salfred}
1494255932Salfred
1495255932Salfred/* bit locations for set port command with zero op modifier */
1496255932Salfredenum {
1497255932Salfred	MLX4_SET_PORT_VL_CAP	 = 4, /* bits 7:4 */
1498255932Salfred	MLX4_SET_PORT_MTU_CAP	 = 12, /* bits 15:12 */
1499255932Salfred	MLX4_CHANGE_PORT_PKEY_TBL_SZ = 20,
1500255932Salfred	MLX4_CHANGE_PORT_VL_CAP	 = 21,
1501255932Salfred	MLX4_CHANGE_PORT_MTU_CAP = 22,
1502255932Salfred};
1503255932Salfred
1504255932Salfredint mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz)
1505255932Salfred{
1506255932Salfred	struct mlx4_cmd_mailbox *mailbox;
1507329159Shselasky	int err, vl_cap, pkey_tbl_flag = 0;
1508255932Salfred
1509329159Shselasky	if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
1510219820Sjeff		return 0;
1511219820Sjeff
1512219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
1513219820Sjeff	if (IS_ERR(mailbox))
1514219820Sjeff		return PTR_ERR(mailbox);
1515219820Sjeff
1516329159Shselasky	((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port];
1517219820Sjeff
1518329159Shselasky	if (pkey_tbl_sz >= 0 && mlx4_is_master(dev)) {
1519329159Shselasky		pkey_tbl_flag = 1;
1520329159Shselasky		((__be16 *) mailbox->buf)[20] = cpu_to_be16(pkey_tbl_sz);
1521329159Shselasky	}
1522219820Sjeff
1523329159Shselasky	/* IB VL CAP enum isn't used by the firmware, just numerical values */
1524329159Shselasky	for (vl_cap = 8; vl_cap >= 1; vl_cap >>= 1) {
1525329159Shselasky		((__be32 *) mailbox->buf)[0] = cpu_to_be32(
1526329159Shselasky			(1 << MLX4_CHANGE_PORT_MTU_CAP) |
1527329159Shselasky			(1 << MLX4_CHANGE_PORT_VL_CAP)  |
1528329159Shselasky			(pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) |
1529329159Shselasky			(dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) |
1530329159Shselasky			(vl_cap << MLX4_SET_PORT_VL_CAP));
1531329159Shselasky		err = mlx4_cmd(dev, mailbox->dma, port,
1532329159Shselasky			       MLX4_SET_PORT_IB_OPCODE, MLX4_CMD_SET_PORT,
1533329159Shselasky			       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
1534329159Shselasky		if (err != -ENOMEM)
1535329159Shselasky			break;
1536255932Salfred	}
1537255932Salfred
1538219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
1539219820Sjeff	return err;
1540219820Sjeff}
1541255932Salfred
1542329159Shselasky#define SET_PORT_ROCE_2_FLAGS          0x10
1543329159Shselasky#define MLX4_SET_PORT_ROCE_V1_V2       0x2
1544255932Salfredint mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu,
1545255932Salfred			  u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx)
1546255932Salfred{
1547255932Salfred	struct mlx4_cmd_mailbox *mailbox;
1548255932Salfred	struct mlx4_set_port_general_context *context;
1549255932Salfred	int err;
1550255932Salfred	u32 in_mod;
1551255932Salfred
1552255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
1553255932Salfred	if (IS_ERR(mailbox))
1554255932Salfred		return PTR_ERR(mailbox);
1555255932Salfred	context = mailbox->buf;
1556255932Salfred	context->flags = SET_PORT_GEN_ALL_VALID;
1557255932Salfred	context->mtu = cpu_to_be16(mtu);
1558255932Salfred	context->pptx = (pptx * (!pfctx)) << 7;
1559255932Salfred	context->pfctx = pfctx;
1560255932Salfred	context->pprx = (pprx * (!pfcrx)) << 7;
1561255932Salfred	context->pfcrx = pfcrx;
1562255932Salfred
1563329159Shselasky	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2) {
1564329159Shselasky		context->flags |= SET_PORT_ROCE_2_FLAGS;
1565329159Shselasky		context->roce_mode |=
1566329159Shselasky			MLX4_SET_PORT_ROCE_V1_V2 << 4;
1567329159Shselasky	}
1568255932Salfred	in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
1569329159Shselasky	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1570329159Shselasky		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1571329159Shselasky		       MLX4_CMD_WRAPPED);
1572255932Salfred
1573255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
1574255932Salfred	return err;
1575255932Salfred}
1576255932SalfredEXPORT_SYMBOL(mlx4_SET_PORT_general);
1577255932Salfred
1578255932Salfredint mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
1579255932Salfred			   u8 promisc)
1580255932Salfred{
1581255932Salfred	struct mlx4_cmd_mailbox *mailbox;
1582255932Salfred	struct mlx4_set_port_rqp_calc_context *context;
1583255932Salfred	int err;
1584255932Salfred	u32 in_mod;
1585255932Salfred	u32 m_promisc = (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) ?
1586255932Salfred		MCAST_DIRECT : MCAST_DEFAULT;
1587272027Shselasky
1588255932Salfred	if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
1589255932Salfred		return 0;
1590255932Salfred
1591255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
1592255932Salfred	if (IS_ERR(mailbox))
1593255932Salfred		return PTR_ERR(mailbox);
1594255932Salfred	context = mailbox->buf;
1595255932Salfred	context->base_qpn = cpu_to_be32(base_qpn);
1596272027Shselasky	context->n_mac = dev->caps.log_num_macs;
1597255932Salfred	context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT |
1598255932Salfred				       base_qpn);
1599255932Salfred	context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT |
1600255932Salfred				     base_qpn);
1601255932Salfred	context->intra_no_vlan = 0;
1602255932Salfred	context->no_vlan = MLX4_NO_VLAN_IDX;
1603255932Salfred	context->intra_vlan_miss = 0;
1604255932Salfred	context->vlan_miss = MLX4_VLAN_MISS_IDX;
1605255932Salfred
1606255932Salfred	in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port;
1607329159Shselasky	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1608329159Shselasky		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1609329159Shselasky		       MLX4_CMD_WRAPPED);
1610255932Salfred
1611255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
1612255932Salfred	return err;
1613255932Salfred}
1614255932SalfredEXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc);
1615255932Salfred
1616329159Shselaskyint mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, u8 ignore_fcs_value)
1617255932Salfred{
1618255932Salfred	struct mlx4_cmd_mailbox *mailbox;
1619329159Shselasky	struct mlx4_set_port_general_context *context;
1620329159Shselasky	u32 in_mod;
1621255932Salfred	int err;
1622255932Salfred
1623255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
1624255932Salfred	if (IS_ERR(mailbox))
1625255932Salfred		return PTR_ERR(mailbox);
1626255932Salfred	context = mailbox->buf;
1627329159Shselasky	context->v_ignore_fcs |= MLX4_FLAG_V_IGNORE_FCS_MASK;
1628329159Shselasky	if (ignore_fcs_value)
1629329159Shselasky		context->ignore_fcs |= MLX4_IGNORE_FCS_MASK;
1630329159Shselasky	else
1631329159Shselasky		context->ignore_fcs &= ~MLX4_IGNORE_FCS_MASK;
1632255932Salfred
1633329159Shselasky	in_mod = MLX4_SET_PORT_GENERAL << 8 | port;
1634255932Salfred	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
1635255932Salfred		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
1636255932Salfred
1637255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
1638255932Salfred	return err;
1639255932Salfred}
1640329159ShselaskyEXPORT_SYMBOL(mlx4_SET_PORT_fcs_check);
1641255932Salfred
1642329159Shselaskyenum {
1643329159Shselasky	VXLAN_ENABLE_MODIFY	= 1 << 7,
1644329159Shselasky	VXLAN_STEERING_MODIFY	= 1 << 6,
1645329159Shselasky
1646329159Shselasky	VXLAN_ENABLE		= 1 << 7,
1647329159Shselasky};
1648329159Shselasky
1649329159Shselaskystruct mlx4_set_port_vxlan_context {
1650329159Shselasky	u32	reserved1;
1651329159Shselasky	u8	modify_flags;
1652329159Shselasky	u8	reserved2;
1653329159Shselasky	u8	enable_flags;
1654329159Shselasky	u8	steering;
1655329159Shselasky};
1656329159Shselasky
1657329159Shselaskyint mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable)
1658255932Salfred{
1659255932Salfred	int err;
1660255932Salfred	u32 in_mod;
1661329159Shselasky	struct mlx4_cmd_mailbox *mailbox;
1662329159Shselasky	struct mlx4_set_port_vxlan_context  *context;
1663255932Salfred
1664255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
1665255932Salfred	if (IS_ERR(mailbox))
1666255932Salfred		return PTR_ERR(mailbox);
1667255932Salfred	context = mailbox->buf;
1668329159Shselasky	memset(context, 0, sizeof(*context));
1669255932Salfred
1670329159Shselasky	context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY;
1671329159Shselasky	if (enable)
1672329159Shselasky		context->enable_flags = VXLAN_ENABLE;
1673329159Shselasky	context->steering  = steering;
1674255932Salfred
1675329159Shselasky	in_mod = MLX4_SET_PORT_VXLAN << 8 | port;
1676329159Shselasky	err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE,
1677329159Shselasky		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1678329159Shselasky		       MLX4_CMD_NATIVE);
1679255932Salfred
1680329159Shselasky	mlx4_free_cmd_mailbox(dev, mailbox);
1681329159Shselasky	return err;
1682329159Shselasky}
1683329159ShselaskyEXPORT_SYMBOL(mlx4_SET_PORT_VXLAN);
1684255932Salfred
1685329159Shselaskyint mlx4_SET_PORT_BEACON(struct mlx4_dev *dev, u8 port, u16 time)
1686329159Shselasky{
1687329159Shselasky	int err;
1688329159Shselasky	struct mlx4_cmd_mailbox *mailbox;
1689329159Shselasky
1690329159Shselasky	mailbox = mlx4_alloc_cmd_mailbox(dev);
1691329159Shselasky	if (IS_ERR(mailbox))
1692329159Shselasky		return PTR_ERR(mailbox);
1693329159Shselasky
1694329159Shselasky	*((__be32 *)mailbox->buf) = cpu_to_be32(time);
1695329159Shselasky
1696329159Shselasky	err = mlx4_cmd(dev, mailbox->dma, port, MLX4_SET_PORT_BEACON_OPCODE,
1697329159Shselasky		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
1698329159Shselasky		       MLX4_CMD_NATIVE);
1699329159Shselasky
1700255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
1701255932Salfred	return err;
1702255932Salfred}
1703329159ShselaskyEXPORT_SYMBOL(mlx4_SET_PORT_BEACON);
1704255932Salfred
1705255932Salfredint mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1706255932Salfred				struct mlx4_vhcr *vhcr,
1707255932Salfred				struct mlx4_cmd_mailbox *inbox,
1708255932Salfred				struct mlx4_cmd_mailbox *outbox,
1709255932Salfred				struct mlx4_cmd_info *cmd)
1710255932Salfred{
1711255932Salfred	int err = 0;
1712255932Salfred
1713255932Salfred	return err;
1714255932Salfred}
1715255932Salfred
1716255932Salfredint mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port,
1717255932Salfred			u64 mac, u64 clear, u8 mode)
1718255932Salfred{
1719255932Salfred	return mlx4_cmd(dev, (mac | (clear << 63)), port, mode,
1720255932Salfred			MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B,
1721255932Salfred			MLX4_CMD_WRAPPED);
1722255932Salfred}
1723255932SalfredEXPORT_SYMBOL(mlx4_SET_MCAST_FLTR);
1724255932Salfred
1725255932Salfredint mlx4_SET_VLAN_FLTR_wrapper(struct mlx4_dev *dev, int slave,
1726255932Salfred			       struct mlx4_vhcr *vhcr,
1727255932Salfred			       struct mlx4_cmd_mailbox *inbox,
1728255932Salfred			       struct mlx4_cmd_mailbox *outbox,
1729255932Salfred			       struct mlx4_cmd_info *cmd)
1730255932Salfred{
1731255932Salfred	int err = 0;
1732255932Salfred
1733255932Salfred	return err;
1734255932Salfred}
1735255932Salfred
1736255932Salfredint mlx4_DUMP_ETH_STATS_wrapper(struct mlx4_dev *dev, int slave,
1737255932Salfred				struct mlx4_vhcr *vhcr,
1738255932Salfred				struct mlx4_cmd_mailbox *inbox,
1739255932Salfred				struct mlx4_cmd_mailbox *outbox,
1740255932Salfred				struct mlx4_cmd_info *cmd)
1741255932Salfred{
1742272027Shselasky	return 0;
1743255932Salfred}
1744255932Salfred
1745329159Shselaskyint mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
1746329159Shselasky				 int *slave_id)
1747255932Salfred{
1748255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
1749255932Salfred	int i, found_ix = -1;
1750255932Salfred	int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
1751329159Shselasky	struct mlx4_slaves_pport slaves_pport;
1752329159Shselasky	unsigned num_vfs;
1753329159Shselasky	int slave_gid;
1754255932Salfred
1755255932Salfred	if (!mlx4_is_mfunc(dev))
1756255932Salfred		return -EINVAL;
1757255932Salfred
1758329159Shselasky	slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
1759329159Shselasky	num_vfs = bitmap_weight(slaves_pport.slaves,
1760329159Shselasky				dev->persist->num_vfs + 1) - 1;
1761329159Shselasky
1762255932Salfred	for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
1763329159Shselasky		if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid,
1764329159Shselasky			    MLX4_ROCE_GID_ENTRY_SIZE)) {
1765255932Salfred			found_ix = i;
1766255932Salfred			break;
1767255932Salfred		}
1768255932Salfred	}
1769255932Salfred
1770255932Salfred	if (found_ix >= 0) {
1771329159Shselasky		/* Calculate a slave_gid which is the slave number in the gid
1772329159Shselasky		 * table and not a globally unique slave number.
1773329159Shselasky		 */
1774255932Salfred		if (found_ix < MLX4_ROCE_PF_GIDS)
1775329159Shselasky			slave_gid = 0;
1776329159Shselasky		else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) *
1777329159Shselasky			 (vf_gids / num_vfs + 1))
1778329159Shselasky			slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) /
1779329159Shselasky				     (vf_gids / num_vfs + 1)) + 1;
1780255932Salfred		else
1781329159Shselasky			slave_gid =
1782255932Salfred			((found_ix - MLX4_ROCE_PF_GIDS -
1783329159Shselasky			  ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) /
1784329159Shselasky			 (vf_gids / num_vfs)) + vf_gids % num_vfs + 1;
1785329159Shselasky
1786329159Shselasky		/* Calculate the globally unique slave id */
1787329159Shselasky		if (slave_gid) {
1788329159Shselasky			struct mlx4_active_ports exclusive_ports;
1789329159Shselasky			struct mlx4_active_ports actv_ports;
1790329159Shselasky			struct mlx4_slaves_pport slaves_pport_actv;
1791329159Shselasky			unsigned max_port_p_one;
1792329159Shselasky			int num_vfs_before = 0;
1793329159Shselasky			int candidate_slave_gid;
1794329159Shselasky
1795329159Shselasky			/* Calculate how many VFs are on the previous port, if exists */
1796329159Shselasky			for (i = 1; i < port; i++) {
1797329159Shselasky				bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
1798329159Shselasky				set_bit(i - 1, exclusive_ports.ports);
1799329159Shselasky				slaves_pport_actv =
1800329159Shselasky					mlx4_phys_to_slaves_pport_actv(
1801329159Shselasky							dev, &exclusive_ports);
1802329159Shselasky				num_vfs_before += bitmap_weight(
1803329159Shselasky						slaves_pport_actv.slaves,
1804329159Shselasky						dev->persist->num_vfs + 1);
1805329159Shselasky			}
1806329159Shselasky
1807329159Shselasky			/* candidate_slave_gid isn't necessarily the correct slave, but
1808329159Shselasky			 * it has the same number of ports and is assigned to the same
1809329159Shselasky			 * ports as the real slave we're looking for. On dual port VF,
1810329159Shselasky			 * slave_gid = [single port VFs on port <port>] +
1811329159Shselasky			 * [offset of the current slave from the first dual port VF] +
1812329159Shselasky			 * 1 (for the PF).
1813329159Shselasky			 */
1814329159Shselasky			candidate_slave_gid = slave_gid + num_vfs_before;
1815329159Shselasky
1816329159Shselasky			actv_ports = mlx4_get_active_ports(dev, candidate_slave_gid);
1817329159Shselasky			max_port_p_one = find_first_bit(
1818329159Shselasky				actv_ports.ports, dev->caps.num_ports) +
1819329159Shselasky				bitmap_weight(actv_ports.ports,
1820329159Shselasky					      dev->caps.num_ports) + 1;
1821329159Shselasky
1822329159Shselasky			/* Calculate the real slave number */
1823329159Shselasky			for (i = 1; i < max_port_p_one; i++) {
1824329159Shselasky				if (i == port)
1825329159Shselasky					continue;
1826329159Shselasky				bitmap_zero(exclusive_ports.ports,
1827329159Shselasky					    dev->caps.num_ports);
1828329159Shselasky				set_bit(i - 1, exclusive_ports.ports);
1829329159Shselasky				slaves_pport_actv =
1830329159Shselasky					mlx4_phys_to_slaves_pport_actv(
1831329159Shselasky						dev, &exclusive_ports);
1832329159Shselasky				slave_gid += bitmap_weight(
1833329159Shselasky						slaves_pport_actv.slaves,
1834329159Shselasky						dev->persist->num_vfs + 1);
1835329159Shselasky			}
1836329159Shselasky		}
1837329159Shselasky		*slave_id = slave_gid;
1838255932Salfred	}
1839255932Salfred
1840255932Salfred	return (found_ix >= 0) ? 0 : -EINVAL;
1841255932Salfred}
1842255932SalfredEXPORT_SYMBOL(mlx4_get_slave_from_roce_gid);
1843255932Salfred
1844329159Shselaskyint mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id,
1845329159Shselasky				 u8 *gid)
1846255932Salfred{
1847255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
1848255932Salfred
1849255932Salfred	if (!mlx4_is_master(dev))
1850255932Salfred		return -EINVAL;
1851255932Salfred
1852329159Shselasky	memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw,
1853329159Shselasky	       MLX4_ROCE_GID_ENTRY_SIZE);
1854255932Salfred	return 0;
1855255932Salfred}
1856255932SalfredEXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
1857255932Salfred
1858283612Sglebius/* Cable Module Info */
1859283612Sglebius#define MODULE_INFO_MAX_READ 48
1860283612Sglebius
1861283612Sglebius#define I2C_ADDR_LOW  0x50
1862283612Sglebius#define I2C_ADDR_HIGH 0x51
1863283612Sglebius#define I2C_PAGE_SIZE 256
1864283612Sglebius
1865283612Sglebius/* Module Info Data */
1866283612Sglebiusstruct mlx4_cable_info {
1867283612Sglebius	u8	i2c_addr;
1868283612Sglebius	u8	page_num;
1869283612Sglebius	__be16	dev_mem_address;
1870283612Sglebius	__be16	reserved1;
1871283612Sglebius	__be16	size;
1872283612Sglebius	__be32	reserved2[2];
1873283612Sglebius	u8	data[MODULE_INFO_MAX_READ];
1874283612Sglebius};
1875283612Sglebius
1876283612Sglebiusenum cable_info_err {
1877329159Shselasky	 CABLE_INF_INV_PORT      = 0x1,
1878329159Shselasky	 CABLE_INF_OP_NOSUP      = 0x2,
1879329159Shselasky	 CABLE_INF_NOT_CONN      = 0x3,
1880329159Shselasky	 CABLE_INF_NO_EEPRM      = 0x4,
1881329159Shselasky	 CABLE_INF_PAGE_ERR      = 0x5,
1882329159Shselasky	 CABLE_INF_INV_ADDR      = 0x6,
1883329159Shselasky	 CABLE_INF_I2C_ADDR      = 0x7,
1884329159Shselasky	 CABLE_INF_QSFP_VIO      = 0x8,
1885329159Shselasky	 CABLE_INF_I2C_BUSY      = 0x9,
1886283612Sglebius};
1887283612Sglebius
1888283612Sglebius#define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF)
1889283612Sglebius
1890283612Sglebius#ifdef DEBUG
1891283612Sglebiusstatic inline const char *cable_info_mad_err_str(u16 mad_status)
1892283612Sglebius{
1893283612Sglebius	u8 err = MAD_STATUS_2_CABLE_ERR(mad_status);
1894283612Sglebius
1895283612Sglebius	switch (err) {
1896283612Sglebius	case CABLE_INF_INV_PORT:
1897283612Sglebius		return "invalid port selected";
1898283612Sglebius	case CABLE_INF_OP_NOSUP:
1899283612Sglebius		return "operation not supported for this port (the port is of type CX4 or internal)";
1900283612Sglebius	case CABLE_INF_NOT_CONN:
1901283612Sglebius		return "cable is not connected";
1902283612Sglebius	case CABLE_INF_NO_EEPRM:
1903283612Sglebius		return "the connected cable has no EPROM (passive copper cable)";
1904283612Sglebius	case CABLE_INF_PAGE_ERR:
1905283612Sglebius		return "page number is greater than 15";
1906283612Sglebius	case CABLE_INF_INV_ADDR:
1907283612Sglebius		return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)";
1908283612Sglebius	case CABLE_INF_I2C_ADDR:
1909283612Sglebius		return "invalid I2C slave address";
1910283612Sglebius	case CABLE_INF_QSFP_VIO:
1911283612Sglebius		return "at least one cable violates the QSFP specification and ignores the modsel signal";
1912283612Sglebius	case CABLE_INF_I2C_BUSY:
1913283612Sglebius		return "I2C bus is constantly busy";
1914283612Sglebius	}
1915283612Sglebius	return "Unknown Error";
1916283612Sglebius}
1917283612Sglebius#endif /* DEBUG */
1918283612Sglebius
1919283612Sglebius/**
1920283612Sglebius * mlx4_get_module_info - Read cable module eeprom data
1921283612Sglebius * @dev: mlx4_dev.
1922283612Sglebius * @port: port number.
1923283612Sglebius * @offset: byte offset in eeprom to start reading data from.
1924283612Sglebius * @size: num of bytes to read.
1925283612Sglebius * @data: output buffer to put the requested data into.
1926283612Sglebius *
1927283612Sglebius * Reads cable module eeprom data, puts the outcome data into
1928283612Sglebius * data pointer paramer.
1929283612Sglebius * Returns num of read bytes on success or a negative error
1930283612Sglebius * code.
1931283612Sglebius */
1932329159Shselaskyint mlx4_get_module_info(struct mlx4_dev *dev, u8 port,
1933329159Shselasky			 u16 offset, u16 size, u8 *data)
1934283612Sglebius{
1935283612Sglebius	struct mlx4_cmd_mailbox *inbox, *outbox;
1936283612Sglebius	struct mlx4_mad_ifc *inmad, *outmad;
1937283612Sglebius	struct mlx4_cable_info *cable_info;
1938283612Sglebius	u16 i2c_addr;
1939283612Sglebius	int ret;
1940283612Sglebius
1941283612Sglebius	if (size > MODULE_INFO_MAX_READ)
1942283612Sglebius		size = MODULE_INFO_MAX_READ;
1943283612Sglebius
1944283612Sglebius	inbox = mlx4_alloc_cmd_mailbox(dev);
1945329159Shselasky	if (IS_ERR(inbox))
1946283612Sglebius		return PTR_ERR(inbox);
1947283612Sglebius
1948283612Sglebius	outbox = mlx4_alloc_cmd_mailbox(dev);
1949283612Sglebius	if (IS_ERR(outbox)) {
1950283612Sglebius		mlx4_free_cmd_mailbox(dev, inbox);
1951283612Sglebius		return PTR_ERR(outbox);
1952283612Sglebius	}
1953283612Sglebius
1954283612Sglebius	inmad = (struct mlx4_mad_ifc *)(inbox->buf);
1955283612Sglebius	outmad = (struct mlx4_mad_ifc *)(outbox->buf);
1956283612Sglebius
1957283612Sglebius	inmad->method = 0x1; /* Get */
1958283612Sglebius	inmad->class_version = 0x1;
1959283612Sglebius	inmad->mgmt_class = 0x1;
1960283612Sglebius	inmad->base_version = 0x1;
1961283612Sglebius	inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */
1962283612Sglebius
1963283612Sglebius	if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE)
1964283612Sglebius		/* Cross pages reads are not allowed
1965283612Sglebius		 * read until offset 256 in low page
1966283612Sglebius		 */
1967283612Sglebius		size -= offset + size - I2C_PAGE_SIZE;
1968283612Sglebius
1969283612Sglebius	i2c_addr = I2C_ADDR_LOW;
1970283612Sglebius	if (offset >= I2C_PAGE_SIZE) {
1971283612Sglebius		/* Reset offset to high page */
1972283612Sglebius		i2c_addr = I2C_ADDR_HIGH;
1973283612Sglebius		offset -= I2C_PAGE_SIZE;
1974283612Sglebius	}
1975283612Sglebius
1976283612Sglebius	cable_info = (struct mlx4_cable_info *)inmad->data;
1977283612Sglebius	cable_info->dev_mem_address = cpu_to_be16(offset);
1978283612Sglebius	cable_info->page_num = 0;
1979283612Sglebius	cable_info->i2c_addr = i2c_addr;
1980283612Sglebius	cable_info->size = cpu_to_be16(size);
1981283612Sglebius
1982283612Sglebius	ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
1983329159Shselasky			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
1984329159Shselasky			   MLX4_CMD_NATIVE);
1985283612Sglebius	if (ret)
1986283612Sglebius		goto out;
1987283612Sglebius
1988283612Sglebius	if (be16_to_cpu(outmad->status)) {
1989283612Sglebius		/* Mad returned with bad status */
1990283612Sglebius		ret = be16_to_cpu(outmad->status);
1991283612Sglebius#ifdef DEBUG
1992329159Shselasky		mlx4_warn(dev,
1993329159Shselasky			  "MLX4_CMD_MAD_IFC Get Module info attr(%x) port(%d) i2c_addr(%x) offset(%d) size(%d): Response Mad Status(%x) - %s\n",
1994329159Shselasky			  0xFF60, port, i2c_addr, offset, size,
1995329159Shselasky			  ret, cable_info_mad_err_str(ret));
1996283612Sglebius#endif
1997283612Sglebius		if (i2c_addr == I2C_ADDR_HIGH &&
1998283612Sglebius		    MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR)
1999283612Sglebius			/* Some SFP cables do not support i2c slave
2000283612Sglebius			 * address 0x51 (high page), abort silently.
2001283612Sglebius			 */
2002283612Sglebius			ret = 0;
2003283612Sglebius		else
2004283612Sglebius			ret = -ret;
2005283612Sglebius		goto out;
2006283612Sglebius	}
2007283612Sglebius	cable_info = (struct mlx4_cable_info *)outmad->data;
2008283612Sglebius	memcpy(data, cable_info->data, size);
2009283612Sglebius	ret = size;
2010283612Sglebiusout:
2011283612Sglebius	mlx4_free_cmd_mailbox(dev, inbox);
2012283612Sglebius	mlx4_free_cmd_mailbox(dev, outbox);
2013283612Sglebius	return ret;
2014283612Sglebius}
2015283612SglebiusEXPORT_SYMBOL(mlx4_get_module_info);
2016