linux/drivers/net/mlx4/port.c
<<
>>
Prefs
   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