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 93int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) 94{ 95 struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table; 96 int i, err = 0; 97 int free = -1; 98 99 mlx4_dbg(dev, "Registering MAC: 0x%llx\n", (unsigned long long) mac); 100 mutex_lock(&table->mutex); 101 for (i = 0; i < MLX4_MAX_MAC_NUM - 1; i++) { 102 if (free < 0 && !table->refs[i]) { 103 free = i; 104 continue; 105 } 106 107 if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 108 /* MAC already registered, increase refernce count */ 109 *index = i; 110 ++table->refs[i]; 111 goto out; 112 } 113 } 114 mlx4_dbg(dev, "Free MAC index is %d\n", free); 115 116 if (table->total == table->max) { 117 /* No free mac entries */ 118 err = -ENOSPC; 119 goto out; 120 } 121 122 /* Register new MAC */ 123 table->refs[free] = 1; 124 table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); 125 126 err = mlx4_set_port_mac_table(dev, port, table->entries); 127 if (unlikely(err)) { 128 mlx4_err(dev, "Failed adding MAC: 0x%llx\n", (unsigned long long) mac); 129 table->refs[free] = 0; 130 table->entries[free] = 0; 131 goto out; 132 } 133 134 *index = free; 135 ++table->total; 136out: 137 mutex_unlock(&table->mutex); 138 return err; 139} 140EXPORT_SYMBOL_GPL(mlx4_register_mac); 141 142void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index) 143{ 144 struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table; 145 146 mutex_lock(&table->mutex); 147 if (!table->refs[index]) { 148 mlx4_warn(dev, "No MAC entry for index %d\n", index); 149 goto out; 150 } 151 if (--table->refs[index]) { 152 mlx4_warn(dev, "Have more references for index %d," 153 "no need to modify MAC table\n", index); 154 goto out; 155 } 156 table->entries[index] = 0; 157 mlx4_set_port_mac_table(dev, port, table->entries); 158 --table->total; 159out: 160 mutex_unlock(&table->mutex); 161} 162EXPORT_SYMBOL_GPL(mlx4_unregister_mac); 163 164static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, 165 __be32 *entries) 166{ 167 struct mlx4_cmd_mailbox *mailbox; 168 u32 in_mod; 169 int err; 170 171 mailbox = mlx4_alloc_cmd_mailbox(dev); 172 if (IS_ERR(mailbox)) 173 return PTR_ERR(mailbox); 174 175 memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); 176 in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; 177 err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, 178 MLX4_CMD_TIME_CLASS_B); 179 180 mlx4_free_cmd_mailbox(dev, mailbox); 181 182 return err; 183} 184 185int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) 186{ 187 struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 188 int i, err = 0; 189 int free = -1; 190 191 mutex_lock(&table->mutex); 192 for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { 193 if (free < 0 && (table->refs[i] == 0)) { 194 free = i; 195 continue; 196 } 197 198 if (table->refs[i] && 199 (vlan == (MLX4_VLAN_MASK & 200 be32_to_cpu(table->entries[i])))) { 201 /* Vlan already registered, increase refernce count */ 202 *index = i; 203 ++table->refs[i]; 204 goto out; 205 } 206 } 207 208 if (table->total == table->max) { 209 /* No free vlan entries */ 210 err = -ENOSPC; 211 goto out; 212 } 213 214 /* Register new MAC */ 215 table->refs[free] = 1; 216 table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); 217 218 err = mlx4_set_port_vlan_table(dev, port, table->entries); 219 if (unlikely(err)) { 220 mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); 221 table->refs[free] = 0; 222 table->entries[free] = 0; 223 goto out; 224 } 225 226 *index = free; 227 ++table->total; 228out: 229 mutex_unlock(&table->mutex); 230 return err; 231} 232EXPORT_SYMBOL_GPL(mlx4_register_vlan); 233 234void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index) 235{ 236 struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; 237 238 if (index < MLX4_VLAN_REGULAR) { 239 mlx4_warn(dev, "Trying to free special vlan index %d\n", index); 240 return; 241 } 242 243 mutex_lock(&table->mutex); 244 if (!table->refs[index]) { 245 mlx4_warn(dev, "No vlan entry for index %d\n", index); 246 goto out; 247 } 248 if (--table->refs[index]) { 249 mlx4_dbg(dev, "Have more references for index %d," 250 "no need to modify vlan table\n", index); 251 goto out; 252 } 253 table->entries[index] = 0; 254 mlx4_set_port_vlan_table(dev, port, table->entries); 255 --table->total; 256out: 257 mutex_unlock(&table->mutex); 258} 259EXPORT_SYMBOL_GPL(mlx4_unregister_vlan); 260 261int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) 262{ 263 struct mlx4_cmd_mailbox *inmailbox, *outmailbox; 264 u8 *inbuf, *outbuf; 265 int err; 266 267 inmailbox = mlx4_alloc_cmd_mailbox(dev); 268 if (IS_ERR(inmailbox)) 269 return PTR_ERR(inmailbox); 270 271 outmailbox = mlx4_alloc_cmd_mailbox(dev); 272 if (IS_ERR(outmailbox)) { 273 mlx4_free_cmd_mailbox(dev, inmailbox); 274 return PTR_ERR(outmailbox); 275 } 276 277 inbuf = inmailbox->buf; 278 outbuf = outmailbox->buf; 279 memset(inbuf, 0, 256); 280 memset(outbuf, 0, 256); 281 inbuf[0] = 1; 282 inbuf[1] = 1; 283 inbuf[2] = 1; 284 inbuf[3] = 1; 285 *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015); 286 *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); 287 288 err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, 289 MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C); 290 if (!err) 291 *caps = *(__be32 *) (outbuf + 84); 292 mlx4_free_cmd_mailbox(dev, inmailbox); 293 mlx4_free_cmd_mailbox(dev, outmailbox); 294 return err; 295} 296 297int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port) 298{ 299 struct mlx4_cmd_mailbox *mailbox; 300 int err; 301 302 if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) 303 return 0; 304 305 mailbox = mlx4_alloc_cmd_mailbox(dev); 306 if (IS_ERR(mailbox)) 307 return PTR_ERR(mailbox); 308 309 memset(mailbox->buf, 0, 256); 310 311 ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; 312 err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT, 313 MLX4_CMD_TIME_CLASS_B); 314 315 mlx4_free_cmd_mailbox(dev, mailbox); 316 return err; 317} 318