 22cdbd1d57
			
		
	
	
	22cdbd1d57
	
	
	
		
			
			* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (108 commits) ehea: Fixing statistics bonding: Fix lockdep warning after bond_vlan_rx_register() tunnels: Fix tunnels change rcu protection caif-u5500: Build config for CAIF shared mem driver caif-u5500: CAIF shared memory mailbox interface caif-u5500: CAIF shared memory transport protocol caif-u5500: Adding shared memory include drivers/isdn: delete double assignment drivers/net/typhoon.c: delete double assignment drivers/net/sb1000.c: delete double assignment qlcnic: define valid vlan id range qlcnic: reduce rx ring size qlcnic: fix mac learning ehea: fix use after free inetpeer: __rcu annotations fib_rules: __rcu annotates ctarget tunnels: add __rcu annotations net: add __rcu annotations to protocol ipv4: add __rcu annotations to routes.c qlge: bugfix: Restoring the vlan setting. ...
		
			
				
	
	
		
			347 lines
		
	
	
	
		
			8.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			347 lines
		
	
	
	
		
			8.6 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
 | |
|  *
 | |
|  * This software is available to you under a choice of one of two
 | |
|  * licenses.  You may choose to be licensed under the terms of the GNU
 | |
|  * General Public License (GPL) Version 2, available from the file
 | |
|  * COPYING in the main directory of this source tree, or the
 | |
|  * OpenIB.org BSD license below:
 | |
|  *
 | |
|  *     Redistribution and use in source and binary forms, with or
 | |
|  *     without modification, are permitted provided that the following
 | |
|  *     conditions are met:
 | |
|  *
 | |
|  *      - Redistributions of source code must retain the above
 | |
|  *        copyright notice, this list of conditions and the following
 | |
|  *        disclaimer.
 | |
|  *
 | |
|  *      - Redistributions in binary form must reproduce the above
 | |
|  *        copyright notice, this list of conditions and the following
 | |
|  *        disclaimer in the documentation and/or other materials
 | |
|  *        provided with the distribution.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | |
|  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
|  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | |
|  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 | |
|  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 | |
|  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | |
|  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | |
|  * SOFTWARE.
 | |
|  */
 | |
| 
 | |
| #include <linux/errno.h>
 | |
| #include <linux/if_ether.h>
 | |
| 
 | |
| #include <linux/mlx4/cmd.h>
 | |
| 
 | |
| #include "mlx4.h"
 | |
| 
 | |
| #define MLX4_MAC_VALID		(1ull << 63)
 | |
| #define MLX4_MAC_MASK		0xffffffffffffULL
 | |
| 
 | |
| #define MLX4_VLAN_VALID		(1u << 31)
 | |
| #define MLX4_VLAN_MASK		0xfff
 | |
| 
 | |
| void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	mutex_init(&table->mutex);
 | |
| 	for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
 | |
| 		table->entries[i] = 0;
 | |
| 		table->refs[i]	 = 0;
 | |
| 	}
 | |
| 	table->max   = 1 << dev->caps.log_num_macs;
 | |
| 	table->total = 0;
 | |
| }
 | |
| 
 | |
| void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	mutex_init(&table->mutex);
 | |
| 	for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
 | |
| 		table->entries[i] = 0;
 | |
| 		table->refs[i]	 = 0;
 | |
| 	}
 | |
| 	table->max   = 1 << dev->caps.log_num_vlans;
 | |
| 	table->total = 0;
 | |
| }
 | |
| 
 | |
| static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
 | |
| 				   __be64 *entries)
 | |
| {
 | |
| 	struct mlx4_cmd_mailbox *mailbox;
 | |
| 	u32 in_mod;
 | |
| 	int err;
 | |
| 
 | |
| 	mailbox = mlx4_alloc_cmd_mailbox(dev);
 | |
| 	if (IS_ERR(mailbox))
 | |
| 		return PTR_ERR(mailbox);
 | |
| 
 | |
| 	memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE);
 | |
| 
 | |
| 	in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port;
 | |
| 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
 | |
| 		       MLX4_CMD_TIME_CLASS_B);
 | |
| 
 | |
| 	mlx4_free_cmd_mailbox(dev, mailbox);
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index)
 | |
| {
 | |
| 	struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table;
 | |
| 	int i, err = 0;
 | |
| 	int free = -1;
 | |
| 
 | |
| 	mlx4_dbg(dev, "Registering MAC: 0x%llx\n", (unsigned long long) mac);
 | |
| 	mutex_lock(&table->mutex);
 | |
| 	for (i = 0; i < MLX4_MAX_MAC_NUM - 1; i++) {
 | |
| 		if (free < 0 && !table->refs[i]) {
 | |
| 			free = i;
 | |
| 			continue;
 | |
| 		}
 | |
| 
 | |
| 		if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
 | |
| 			/* MAC already registered, increase refernce count */
 | |
| 			*index = i;
 | |
| 			++table->refs[i];
 | |
| 			goto out;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (free < 0) {
 | |
| 		err = -ENOMEM;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	mlx4_dbg(dev, "Free MAC index is %d\n", free);
 | |
| 
 | |
| 	if (table->total == table->max) {
 | |
| 		/* No free mac entries */
 | |
| 		err = -ENOSPC;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/* Register new MAC */
 | |
| 	table->refs[free] = 1;
 | |
| 	table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
 | |
| 
 | |
| 	err = mlx4_set_port_mac_table(dev, port, table->entries);
 | |
| 	if (unlikely(err)) {
 | |
| 		mlx4_err(dev, "Failed adding MAC: 0x%llx\n", (unsigned long long) mac);
 | |
| 		table->refs[free] = 0;
 | |
| 		table->entries[free] = 0;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	*index = free;
 | |
| 	++table->total;
 | |
| out:
 | |
| 	mutex_unlock(&table->mutex);
 | |
| 	return err;
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(mlx4_register_mac);
 | |
| 
 | |
| void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index)
 | |
| {
 | |
| 	struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table;
 | |
| 
 | |
| 	mutex_lock(&table->mutex);
 | |
| 	if (!table->refs[index]) {
 | |
| 		mlx4_warn(dev, "No MAC entry for index %d\n", index);
 | |
| 		goto out;
 | |
| 	}
 | |
| 	if (--table->refs[index]) {
 | |
| 		mlx4_warn(dev, "Have more references for index %d,"
 | |
| 			  "no need to modify MAC table\n", index);
 | |
| 		goto out;
 | |
| 	}
 | |
| 	table->entries[index] = 0;
 | |
| 	mlx4_set_port_mac_table(dev, port, table->entries);
 | |
| 	--table->total;
 | |
| out:
 | |
| 	mutex_unlock(&table->mutex);
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
 | |
| 
 | |
| static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
 | |
| 				    __be32 *entries)
 | |
| {
 | |
| 	struct mlx4_cmd_mailbox *mailbox;
 | |
| 	u32 in_mod;
 | |
| 	int err;
 | |
| 
 | |
| 	mailbox = mlx4_alloc_cmd_mailbox(dev);
 | |
| 	if (IS_ERR(mailbox))
 | |
| 		return PTR_ERR(mailbox);
 | |
| 
 | |
| 	memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE);
 | |
| 	in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port;
 | |
| 	err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
 | |
| 		       MLX4_CMD_TIME_CLASS_B);
 | |
| 
 | |
| 	mlx4_free_cmd_mailbox(dev, mailbox);
 | |
| 
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
 | |
| {
 | |
| 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) {
 | |
| 		if (table->refs[i] &&
 | |
| 		    (vid == (MLX4_VLAN_MASK &
 | |
| 			      be32_to_cpu(table->entries[i])))) {
 | |
| 			/* VLAN already registered, increase reference count */
 | |
| 			*idx = i;
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return -ENOENT;
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
 | |
| 
 | |
| int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
 | |
| {
 | |
| 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
 | |
| 	int i, err = 0;
 | |
| 	int free = -1;
 | |
| 
 | |
| 	mutex_lock(&table->mutex);
 | |
| 	for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
 | |
| 		if (free < 0 && (table->refs[i] == 0)) {
 | |
| 			free = i;
 | |
| 			continue;
 | |
| 		}
 | |
| 
 | |
| 		if (table->refs[i] &&
 | |
| 		    (vlan == (MLX4_VLAN_MASK &
 | |
| 			      be32_to_cpu(table->entries[i])))) {
 | |
| 			/* Vlan already registered, increase refernce count */
 | |
| 			*index = i;
 | |
| 			++table->refs[i];
 | |
| 			goto out;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (free < 0) {
 | |
| 		err = -ENOMEM;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	if (table->total == table->max) {
 | |
| 		/* No free vlan entries */
 | |
| 		err = -ENOSPC;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/* Register new MAC */
 | |
| 	table->refs[free] = 1;
 | |
| 	table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
 | |
| 
 | |
| 	err = mlx4_set_port_vlan_table(dev, port, table->entries);
 | |
| 	if (unlikely(err)) {
 | |
| 		mlx4_warn(dev, "Failed adding vlan: %u\n", vlan);
 | |
| 		table->refs[free] = 0;
 | |
| 		table->entries[free] = 0;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	*index = free;
 | |
| 	++table->total;
 | |
| out:
 | |
| 	mutex_unlock(&table->mutex);
 | |
| 	return err;
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(mlx4_register_vlan);
 | |
| 
 | |
| void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
 | |
| {
 | |
| 	struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
 | |
| 
 | |
| 	if (index < MLX4_VLAN_REGULAR) {
 | |
| 		mlx4_warn(dev, "Trying to free special vlan index %d\n", index);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	mutex_lock(&table->mutex);
 | |
| 	if (!table->refs[index]) {
 | |
| 		mlx4_warn(dev, "No vlan entry for index %d\n", index);
 | |
| 		goto out;
 | |
| 	}
 | |
| 	if (--table->refs[index]) {
 | |
| 		mlx4_dbg(dev, "Have more references for index %d,"
 | |
| 			 "no need to modify vlan table\n", index);
 | |
| 		goto out;
 | |
| 	}
 | |
| 	table->entries[index] = 0;
 | |
| 	mlx4_set_port_vlan_table(dev, port, table->entries);
 | |
| 	--table->total;
 | |
| out:
 | |
| 	mutex_unlock(&table->mutex);
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(mlx4_unregister_vlan);
 | |
| 
 | |
| int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
 | |
| {
 | |
| 	struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
 | |
| 	u8 *inbuf, *outbuf;
 | |
| 	int err;
 | |
| 
 | |
| 	inmailbox = mlx4_alloc_cmd_mailbox(dev);
 | |
| 	if (IS_ERR(inmailbox))
 | |
| 		return PTR_ERR(inmailbox);
 | |
| 
 | |
| 	outmailbox = mlx4_alloc_cmd_mailbox(dev);
 | |
| 	if (IS_ERR(outmailbox)) {
 | |
| 		mlx4_free_cmd_mailbox(dev, inmailbox);
 | |
| 		return PTR_ERR(outmailbox);
 | |
| 	}
 | |
| 
 | |
| 	inbuf = inmailbox->buf;
 | |
| 	outbuf = outmailbox->buf;
 | |
| 	memset(inbuf, 0, 256);
 | |
| 	memset(outbuf, 0, 256);
 | |
| 	inbuf[0] = 1;
 | |
| 	inbuf[1] = 1;
 | |
| 	inbuf[2] = 1;
 | |
| 	inbuf[3] = 1;
 | |
| 	*(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015);
 | |
| 	*(__be32 *) (&inbuf[20]) = cpu_to_be32(port);
 | |
| 
 | |
| 	err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3,
 | |
| 			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C);
 | |
| 	if (!err)
 | |
| 		*caps = *(__be32 *) (outbuf + 84);
 | |
| 	mlx4_free_cmd_mailbox(dev, inmailbox);
 | |
| 	mlx4_free_cmd_mailbox(dev, outmailbox);
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port)
 | |
| {
 | |
| 	struct mlx4_cmd_mailbox *mailbox;
 | |
| 	int err;
 | |
| 
 | |
| 	if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
 | |
| 		return 0;
 | |
| 
 | |
| 	mailbox = mlx4_alloc_cmd_mailbox(dev);
 | |
| 	if (IS_ERR(mailbox))
 | |
| 		return PTR_ERR(mailbox);
 | |
| 
 | |
| 	memset(mailbox->buf, 0, 256);
 | |
| 
 | |
| 	((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port];
 | |
| 	err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT,
 | |
| 		       MLX4_CMD_TIME_CLASS_B);
 | |
| 
 | |
| 	mlx4_free_cmd_mailbox(dev, mailbox);
 | |
| 	return err;
 | |
| }
 |