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