root/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_l2table_entry_cmd
  2. del_l2table_entry_cmd
  3. alloc_l2table_index
  4. free_l2table_index
  5. mlx5_mpfs_init
  6. mlx5_mpfs_cleanup
  7. mlx5_mpfs_add_mac
  8. mlx5_mpfs_del_mac

   1 /*
   2  * Copyright (c) 2017, 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/etherdevice.h>
  34 #include <linux/mlx5/driver.h>
  35 #include <linux/mlx5/mlx5_ifc.h>
  36 #include <linux/mlx5/eswitch.h>
  37 #include "mlx5_core.h"
  38 #include "lib/mpfs.h"
  39 
  40 /* HW L2 Table (MPFS) management */
  41 static int set_l2table_entry_cmd(struct mlx5_core_dev *dev, u32 index, u8 *mac)
  42 {
  43         u32 in[MLX5_ST_SZ_DW(set_l2_table_entry_in)]   = {0};
  44         u32 out[MLX5_ST_SZ_DW(set_l2_table_entry_out)] = {0};
  45         u8 *in_mac_addr;
  46 
  47         MLX5_SET(set_l2_table_entry_in, in, opcode, MLX5_CMD_OP_SET_L2_TABLE_ENTRY);
  48         MLX5_SET(set_l2_table_entry_in, in, table_index, index);
  49 
  50         in_mac_addr = MLX5_ADDR_OF(set_l2_table_entry_in, in, mac_address);
  51         ether_addr_copy(&in_mac_addr[2], mac);
  52 
  53         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
  54 }
  55 
  56 static int del_l2table_entry_cmd(struct mlx5_core_dev *dev, u32 index)
  57 {
  58         u32 in[MLX5_ST_SZ_DW(delete_l2_table_entry_in)]   = {0};
  59         u32 out[MLX5_ST_SZ_DW(delete_l2_table_entry_out)] = {0};
  60 
  61         MLX5_SET(delete_l2_table_entry_in, in, opcode, MLX5_CMD_OP_DELETE_L2_TABLE_ENTRY);
  62         MLX5_SET(delete_l2_table_entry_in, in, table_index, index);
  63         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
  64 }
  65 
  66 /* UC L2 table hash node */
  67 struct l2table_node {
  68         struct l2addr_node node;
  69         u32                index; /* index in HW l2 table */
  70         int                ref_count;
  71 };
  72 
  73 struct mlx5_mpfs {
  74         struct hlist_head    hash[MLX5_L2_ADDR_HASH_SIZE];
  75         struct mutex         lock; /* Synchronize l2 table access */
  76         u32                  size;
  77         unsigned long        *bitmap;
  78 };
  79 
  80 static int alloc_l2table_index(struct mlx5_mpfs *l2table, u32 *ix)
  81 {
  82         int err = 0;
  83 
  84         *ix = find_first_zero_bit(l2table->bitmap, l2table->size);
  85         if (*ix >= l2table->size)
  86                 err = -ENOSPC;
  87         else
  88                 __set_bit(*ix, l2table->bitmap);
  89 
  90         return err;
  91 }
  92 
  93 static void free_l2table_index(struct mlx5_mpfs *l2table, u32 ix)
  94 {
  95         __clear_bit(ix, l2table->bitmap);
  96 }
  97 
  98 int mlx5_mpfs_init(struct mlx5_core_dev *dev)
  99 {
 100         int l2table_size = 1 << MLX5_CAP_GEN(dev, log_max_l2_table);
 101         struct mlx5_mpfs *mpfs;
 102 
 103         if (!MLX5_ESWITCH_MANAGER(dev))
 104                 return 0;
 105 
 106         mpfs = kzalloc(sizeof(*mpfs), GFP_KERNEL);
 107         if (!mpfs)
 108                 return -ENOMEM;
 109 
 110         mutex_init(&mpfs->lock);
 111         mpfs->size   = l2table_size;
 112         mpfs->bitmap = bitmap_zalloc(l2table_size, GFP_KERNEL);
 113         if (!mpfs->bitmap) {
 114                 kfree(mpfs);
 115                 return -ENOMEM;
 116         }
 117 
 118         dev->priv.mpfs = mpfs;
 119         return 0;
 120 }
 121 
 122 void mlx5_mpfs_cleanup(struct mlx5_core_dev *dev)
 123 {
 124         struct mlx5_mpfs *mpfs = dev->priv.mpfs;
 125 
 126         if (!MLX5_ESWITCH_MANAGER(dev))
 127                 return;
 128 
 129         WARN_ON(!hlist_empty(mpfs->hash));
 130         bitmap_free(mpfs->bitmap);
 131         kfree(mpfs);
 132 }
 133 
 134 int mlx5_mpfs_add_mac(struct mlx5_core_dev *dev, u8 *mac)
 135 {
 136         struct mlx5_mpfs *mpfs = dev->priv.mpfs;
 137         struct l2table_node *l2addr;
 138         int err = 0;
 139         u32 index;
 140 
 141         if (!MLX5_ESWITCH_MANAGER(dev))
 142                 return 0;
 143 
 144         mutex_lock(&mpfs->lock);
 145 
 146         l2addr = l2addr_hash_find(mpfs->hash, mac, struct l2table_node);
 147         if (l2addr) {
 148                 l2addr->ref_count++;
 149                 goto out;
 150         }
 151 
 152         err = alloc_l2table_index(mpfs, &index);
 153         if (err)
 154                 goto out;
 155 
 156         l2addr = l2addr_hash_add(mpfs->hash, mac, struct l2table_node, GFP_KERNEL);
 157         if (!l2addr) {
 158                 err = -ENOMEM;
 159                 goto hash_add_err;
 160         }
 161 
 162         err = set_l2table_entry_cmd(dev, index, mac);
 163         if (err)
 164                 goto set_table_entry_err;
 165 
 166         l2addr->index = index;
 167         l2addr->ref_count = 1;
 168 
 169         mlx5_core_dbg(dev, "MPFS mac added %pM, index (%d)\n", mac, index);
 170         goto out;
 171 
 172 set_table_entry_err:
 173         l2addr_hash_del(l2addr);
 174 hash_add_err:
 175         free_l2table_index(mpfs, index);
 176 out:
 177         mutex_unlock(&mpfs->lock);
 178         return err;
 179 }
 180 
 181 int mlx5_mpfs_del_mac(struct mlx5_core_dev *dev, u8 *mac)
 182 {
 183         struct mlx5_mpfs *mpfs = dev->priv.mpfs;
 184         struct l2table_node *l2addr;
 185         int err = 0;
 186         u32 index;
 187 
 188         if (!MLX5_ESWITCH_MANAGER(dev))
 189                 return 0;
 190 
 191         mutex_lock(&mpfs->lock);
 192 
 193         l2addr = l2addr_hash_find(mpfs->hash, mac, struct l2table_node);
 194         if (!l2addr) {
 195                 err = -ENOENT;
 196                 goto unlock;
 197         }
 198 
 199         if (--l2addr->ref_count > 0)
 200                 goto unlock;
 201 
 202         index = l2addr->index;
 203         del_l2table_entry_cmd(dev, index);
 204         l2addr_hash_del(l2addr);
 205         free_l2table_index(mpfs, index);
 206         mlx5_core_dbg(dev, "MPFS mac deleted %pM, index (%d)\n", mac, index);
 207 unlock:
 208         mutex_unlock(&mpfs->lock);
 209         return err;
 210 }

/* [<][>][^][v][top][bottom][index][help] */