Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1/*
  2 * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
  3 *
  4 * This software is available to you under a choice of one of two
  5 * licenses.  You may choose to be licensed under the terms of the GNU
  6 * General Public License (GPL) Version 2, available from the file
  7 * COPYING in the main directory of this source tree, or the
  8 * OpenIB.org BSD license below:
  9 *
 10 *     Redistribution and use in source and binary forms, with or
 11 *     without modification, are permitted provided that the following
 12 *     conditions are met:
 13 *
 14 *      - Redistributions of source code must retain the above
 15 *        copyright notice, this list of conditions and the following
 16 *        disclaimer.
 17 *
 18 *      - Redistributions in binary form must reproduce the above
 19 *        copyright notice, this list of conditions and the following
 20 *        disclaimer in the documentation and/or other materials
 21 *        provided with the distribution.
 22 *
 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 30 * SOFTWARE.
 31 */
 32
 33#include <linux/errno.h>
 34#include <linux/if_ether.h>
 35
 36#include <linux/mlx4/cmd.h>
 37
 38#include "mlx4.h"
 39
 40#define MLX4_MAC_VALID		(1ull << 63)
 41#define MLX4_MAC_MASK		0xffffffffffffULL
 42
 43#define MLX4_VLAN_VALID		(1u << 31)
 44#define MLX4_VLAN_MASK		0xfff
 45
 46void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table)
 47{
 48	int i;
 49
 50	mutex_init(&table->mutex);
 51	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
 52		table->entries[i] = 0;
 53		table->refs[i]	 = 0;
 54	}
 55	table->max   = 1 << dev->caps.log_num_macs;
 56	table->total = 0;
 57}
 58
 59void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
 60{
 61	int i;
 62
 63	mutex_init(&table->mutex);
 64	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
 65		table->entries[i] = 0;
 66		table->refs[i]	 = 0;
 67	}
 68	table->max   = 1 << dev->caps.log_num_vlans;
 69	table->total = 0;
 70}
 71
 72static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
 73				   __be64 *entries)
 74{
 75	struct mlx4_cmd_mailbox *mailbox;
 76	u32 in_mod;
 77	int err;
 78
 79	mailbox = mlx4_alloc_cmd_mailbox(dev);
 80	if (IS_ERR(mailbox))
 81		return PTR_ERR(mailbox);
 82
 83	memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE);
 84
 85	in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port;
 86	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
 87		       MLX4_CMD_TIME_CLASS_B);
 88
 89	mlx4_free_cmd_mailbox(dev, mailbox);
 90	return err;
 91}
 92
 93static int mlx4_uc_steer_add(struct mlx4_dev *dev, u8 port,
 94			     u64 mac, int *qpn, u8 reserve)
 95{
 96	struct mlx4_qp qp;
 97	u8 gid[16] = {0};
 98	int err;
 99
100	if (reserve) {
101		err = mlx4_qp_reserve_range(dev, 1, 1, qpn);
102		if (err) {
103			mlx4_err(dev, "Failed to reserve qp for mac registration\n");
104			return err;
105		}
106	}
107	qp.qpn = *qpn;
108
109	mac &= 0xffffffffffffULL;
110	mac = cpu_to_be64(mac << 16);
111	memcpy(&gid[10], &mac, ETH_ALEN);
112	gid[5] = port;
113	gid[7] = MLX4_UC_STEER << 1;
114
115	err = mlx4_qp_attach_common(dev, &qp, gid, 0,
116				    MLX4_PROT_ETH, MLX4_UC_STEER);
117	if (err && reserve)
118		mlx4_qp_release_range(dev, *qpn, 1);
119
120	return err;
121}
122
123static void mlx4_uc_steer_release(struct mlx4_dev *dev, u8 port,
124				  u64 mac, int qpn, u8 free)
125{
126	struct mlx4_qp qp;
127	u8 gid[16] = {0};
128
129	qp.qpn = qpn;
130	mac &= 0xffffffffffffULL;
131	mac = cpu_to_be64(mac << 16);
132	memcpy(&gid[10], &mac, ETH_ALEN);
133	gid[5] = port;
134	gid[7] = MLX4_UC_STEER << 1;
135
136	mlx4_qp_detach_common(dev, &qp, gid, MLX4_PROT_ETH, MLX4_UC_STEER);
137	if (free)
138		mlx4_qp_release_range(dev, qpn, 1);
139}
140
141int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn, u8 wrap)
142{
143	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
144	struct mlx4_mac_table *table = &info->mac_table;
145	struct mlx4_mac_entry *entry;
146	int i, err = 0;
147	int free = -1;
148
149	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER) {
150		err = mlx4_uc_steer_add(dev, port, mac, qpn, 1);
151		if (!err) {
152			entry = kmalloc(sizeof *entry, GFP_KERNEL);
153			if (!entry) {
154				mlx4_uc_steer_release(dev, port, mac, *qpn, 1);
155				return -ENOMEM;
156			}
157			entry->mac = mac;
158			err = radix_tree_insert(&info->mac_tree, *qpn, entry);
159			if (err) {
160				mlx4_uc_steer_release(dev, port, mac, *qpn, 1);
161				return err;
162			}
163		} else
164			return err;
165	}
166	mlx4_dbg(dev, "Registering MAC: 0x%llx\n", (unsigned long long) mac);
167	mutex_lock(&table->mutex);
168	for (i = 0; i < MLX4_MAX_MAC_NUM - 1; i++) {
169		if (free < 0 && !table->refs[i]) {
170			free = i;
171			continue;
172		}
173
174		if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
175			/* MAC already registered, increase references count */
176			++table->refs[i];
177			goto out;
178		}
179	}
180
181	if (free < 0) {
182		err = -ENOMEM;
183		goto out;
184	}
185
186	mlx4_dbg(dev, "Free MAC index is %d\n", free);
187
188	if (table->total == table->max) {
189		/* No free mac entries */
190		err = -ENOSPC;
191		goto out;
192	}
193
194	/* Register new MAC */
195	table->refs[free] = 1;
196	table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
197
198	err = mlx4_set_port_mac_table(dev, port, table->entries);
199	if (unlikely(err)) {
200		mlx4_err(dev, "Failed adding MAC: 0x%llx\n", (unsigned long long) mac);
201		table->refs[free] = 0;
202		table->entries[free] = 0;
203		goto out;
204	}
205
206	if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER))
207		*qpn = info->base_qpn + free;
208	++table->total;
209out:
210	mutex_unlock(&table->mutex);
211	return err;
212}
213EXPORT_SYMBOL_GPL(mlx4_register_mac);
214
215static int validate_index(struct mlx4_dev *dev,
216			  struct mlx4_mac_table *table, int index)
217{
218	int err = 0;
219
220	if (index < 0 || index >= table->max || !table->entries[index]) {
221		mlx4_warn(dev, "No valid Mac entry for the given index\n");
222		err = -EINVAL;
223	}
224	return err;
225}
226
227static int find_index(struct mlx4_dev *dev,
228		      struct mlx4_mac_table *table, u64 mac)
229{
230	int i;
231	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
232		if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))
233			return i;
234	}
235	/* Mac not found */
236	return -EINVAL;
237}
238
239void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int qpn)
240{
241	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
242	struct mlx4_mac_table *table = &info->mac_table;
243	int index = qpn - info->base_qpn;
244	struct mlx4_mac_entry *entry;
245
246	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER) {
247		entry = radix_tree_lookup(&info->mac_tree, qpn);
248		if (entry) {
249			mlx4_uc_steer_release(dev, port, entry->mac, qpn, 1);
250			radix_tree_delete(&info->mac_tree, qpn);
251			index = find_index(dev, table, entry->mac);
252			kfree(entry);
253		}
254	}
255
256	mutex_lock(&table->mutex);
257
258	if (validate_index(dev, table, index))
259		goto out;
260
261	/* Check whether this address has reference count */
262	if (!(--table->refs[index])) {
263		table->entries[index] = 0;
264		mlx4_set_port_mac_table(dev, port, table->entries);
265		--table->total;
266	}
267out:
268	mutex_unlock(&table->mutex);
269}
270EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
271
272int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac, u8 wrap)
273{
274	struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
275	struct mlx4_mac_table *table = &info->mac_table;
276	int index = qpn - info->base_qpn;
277	struct mlx4_mac_entry *entry;
278	int err;
279
280	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER) {
281		entry = radix_tree_lookup(&info->mac_tree, qpn);
282		if (!entry)
283			return -EINVAL;
284		index = find_index(dev, table, entry->mac);
285		mlx4_uc_steer_release(dev, port, entry->mac, qpn, 0);
286		entry->mac = new_mac;
287		err = mlx4_uc_steer_add(dev, port, entry->mac, &qpn, 0);
288		if (err || index < 0)
289			return err;
290	}
291
292	mutex_lock(&table->mutex);
293
294	err = validate_index(dev, table, index);
295	if (err)
296		goto out;
297
298	table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
299
300	err = mlx4_set_port_mac_table(dev, port, table->entries);
301	if (unlikely(err)) {
302		mlx4_err(dev, "Failed adding MAC: 0x%llx\n", (unsigned long long) new_mac);
303		table->entries[index] = 0;
304	}
305out:
306	mutex_unlock(&table->mutex);
307	return err;
308}
309EXPORT_SYMBOL_GPL(mlx4_replace_mac);
310static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
311				    __be32 *entries)
312{
313	struct mlx4_cmd_mailbox *mailbox;
314	u32 in_mod;
315	int err;
316
317	mailbox = mlx4_alloc_cmd_mailbox(dev);
318	if (IS_ERR(mailbox))
319		return PTR_ERR(mailbox);
320
321	memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE);
322	in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port;
323	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
324		       MLX4_CMD_TIME_CLASS_B);
325
326	mlx4_free_cmd_mailbox(dev, mailbox);
327
328	return err;
329}
330
331int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
332{
333	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
334	int i;
335
336	for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) {
337		if (table->refs[i] &&
338		    (vid == (MLX4_VLAN_MASK &
339			      be32_to_cpu(table->entries[i])))) {
340			/* VLAN already registered, increase reference count */
341			*idx = i;
342			return 0;
343		}
344	}
345
346	return -ENOENT;
347}
348EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
349
350int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
351{
352	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
353	int i, err = 0;
354	int free = -1;
355
356	mutex_lock(&table->mutex);
357	for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
358		if (free < 0 && (table->refs[i] == 0)) {
359			free = i;
360			continue;
361		}
362
363		if (table->refs[i] &&
364		    (vlan == (MLX4_VLAN_MASK &
365			      be32_to_cpu(table->entries[i])))) {
366			/* Vlan already registered, increase references count */
367			*index = i;
368			++table->refs[i];
369			goto out;
370		}
371	}
372
373	if (free < 0) {
374		err = -ENOMEM;
375		goto out;
376	}
377
378	if (table->total == table->max) {
379		/* No free vlan entries */
380		err = -ENOSPC;
381		goto out;
382	}
383
384	/* Register new MAC */
385	table->refs[free] = 1;
386	table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
387
388	err = mlx4_set_port_vlan_table(dev, port, table->entries);
389	if (unlikely(err)) {
390		mlx4_warn(dev, "Failed adding vlan: %u\n", vlan);
391		table->refs[free] = 0;
392		table->entries[free] = 0;
393		goto out;
394	}
395
396	*index = free;
397	++table->total;
398out:
399	mutex_unlock(&table->mutex);
400	return err;
401}
402EXPORT_SYMBOL_GPL(mlx4_register_vlan);
403
404void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
405{
406	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
407
408	if (index < MLX4_VLAN_REGULAR) {
409		mlx4_warn(dev, "Trying to free special vlan index %d\n", index);
410		return;
411	}
412
413	mutex_lock(&table->mutex);
414	if (!table->refs[index]) {
415		mlx4_warn(dev, "No vlan entry for index %d\n", index);
416		goto out;
417	}
418	if (--table->refs[index]) {
419		mlx4_dbg(dev, "Have more references for index %d,"
420			 "no need to modify vlan table\n", index);
421		goto out;
422	}
423	table->entries[index] = 0;
424	mlx4_set_port_vlan_table(dev, port, table->entries);
425	--table->total;
426out:
427	mutex_unlock(&table->mutex);
428}
429EXPORT_SYMBOL_GPL(mlx4_unregister_vlan);
430
431int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
432{
433	struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
434	u8 *inbuf, *outbuf;
435	int err;
436
437	inmailbox = mlx4_alloc_cmd_mailbox(dev);
438	if (IS_ERR(inmailbox))
439		return PTR_ERR(inmailbox);
440
441	outmailbox = mlx4_alloc_cmd_mailbox(dev);
442	if (IS_ERR(outmailbox)) {
443		mlx4_free_cmd_mailbox(dev, inmailbox);
444		return PTR_ERR(outmailbox);
445	}
446
447	inbuf = inmailbox->buf;
448	outbuf = outmailbox->buf;
449	memset(inbuf, 0, 256);
450	memset(outbuf, 0, 256);
451	inbuf[0] = 1;
452	inbuf[1] = 1;
453	inbuf[2] = 1;
454	inbuf[3] = 1;
455	*(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015);
456	*(__be32 *) (&inbuf[20]) = cpu_to_be32(port);
457
458	err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3,
459			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C);
460	if (!err)
461		*caps = *(__be32 *) (outbuf + 84);
462	mlx4_free_cmd_mailbox(dev, inmailbox);
463	mlx4_free_cmd_mailbox(dev, outmailbox);
464	return err;
465}
466
467int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port)
468{
469	struct mlx4_cmd_mailbox *mailbox;
470	int err;
471
472	if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
473		return 0;
474
475	mailbox = mlx4_alloc_cmd_mailbox(dev);
476	if (IS_ERR(mailbox))
477		return PTR_ERR(mailbox);
478
479	memset(mailbox->buf, 0, 256);
480
481	((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port];
482	err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT,
483		       MLX4_CMD_TIME_CLASS_B);
484
485	mlx4_free_cmd_mailbox(dev, mailbox);
486	return err;
487}