linux/drivers/net/ethernet/mellanox/mlx5/core/en/rqt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
   2/* Copyright (c) 2021, Mellanox Technologies inc. All rights reserved. */
   3
   4#include "rqt.h"
   5#include <linux/mlx5/transobj.h>
   6
   7void mlx5e_rss_params_indir_init_uniform(struct mlx5e_rss_params_indir *indir,
   8                                         unsigned int num_channels)
   9{
  10        unsigned int i;
  11
  12        for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++)
  13                indir->table[i] = i % num_channels;
  14}
  15
  16static int mlx5e_rqt_init(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev,
  17                          u16 max_size, u32 *init_rqns, u16 init_size)
  18{
  19        void *rqtc;
  20        int inlen;
  21        int err;
  22        u32 *in;
  23        int i;
  24
  25        rqt->mdev = mdev;
  26        rqt->size = max_size;
  27
  28        inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * init_size;
  29        in = kvzalloc(inlen, GFP_KERNEL);
  30        if (!in)
  31                return -ENOMEM;
  32
  33        rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context);
  34
  35        MLX5_SET(rqtc, rqtc, rqt_max_size, rqt->size);
  36
  37        MLX5_SET(rqtc, rqtc, rqt_actual_size, init_size);
  38        for (i = 0; i < init_size; i++)
  39                MLX5_SET(rqtc, rqtc, rq_num[i], init_rqns[i]);
  40
  41        err = mlx5_core_create_rqt(rqt->mdev, in, inlen, &rqt->rqtn);
  42
  43        kvfree(in);
  44        return err;
  45}
  46
  47int mlx5e_rqt_init_direct(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev,
  48                          bool indir_enabled, u32 init_rqn)
  49{
  50        u16 max_size = indir_enabled ? MLX5E_INDIR_RQT_SIZE : 1;
  51
  52        return mlx5e_rqt_init(rqt, mdev, max_size, &init_rqn, 1);
  53}
  54
  55static int mlx5e_bits_invert(unsigned long a, int size)
  56{
  57        int inv = 0;
  58        int i;
  59
  60        for (i = 0; i < size; i++)
  61                inv |= (test_bit(size - i - 1, &a) ? 1 : 0) << i;
  62
  63        return inv;
  64}
  65
  66static int mlx5e_calc_indir_rqns(u32 *rss_rqns, u32 *rqns, unsigned int num_rqns,
  67                                 u8 hfunc, struct mlx5e_rss_params_indir *indir)
  68{
  69        unsigned int i;
  70
  71        for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++) {
  72                unsigned int ix = i;
  73
  74                if (hfunc == ETH_RSS_HASH_XOR)
  75                        ix = mlx5e_bits_invert(ix, ilog2(MLX5E_INDIR_RQT_SIZE));
  76
  77                ix = indir->table[ix];
  78
  79                if (WARN_ON(ix >= num_rqns))
  80                        /* Could be a bug in the driver or in the kernel part of
  81                         * ethtool: indir table refers to non-existent RQs.
  82                         */
  83                        return -EINVAL;
  84                rss_rqns[i] = rqns[ix];
  85        }
  86
  87        return 0;
  88}
  89
  90int mlx5e_rqt_init_indir(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev,
  91                         u32 *rqns, unsigned int num_rqns,
  92                         u8 hfunc, struct mlx5e_rss_params_indir *indir)
  93{
  94        u32 *rss_rqns;
  95        int err;
  96
  97        rss_rqns = kvmalloc_array(MLX5E_INDIR_RQT_SIZE, sizeof(*rss_rqns), GFP_KERNEL);
  98        if (!rss_rqns)
  99                return -ENOMEM;
 100
 101        err = mlx5e_calc_indir_rqns(rss_rqns, rqns, num_rqns, hfunc, indir);
 102        if (err)
 103                goto out;
 104
 105        err = mlx5e_rqt_init(rqt, mdev, MLX5E_INDIR_RQT_SIZE, rss_rqns, MLX5E_INDIR_RQT_SIZE);
 106
 107out:
 108        kvfree(rss_rqns);
 109        return err;
 110}
 111
 112void mlx5e_rqt_destroy(struct mlx5e_rqt *rqt)
 113{
 114        mlx5_core_destroy_rqt(rqt->mdev, rqt->rqtn);
 115}
 116
 117static int mlx5e_rqt_redirect(struct mlx5e_rqt *rqt, u32 *rqns, unsigned int size)
 118{
 119        unsigned int i;
 120        void *rqtc;
 121        int inlen;
 122        u32 *in;
 123        int err;
 124
 125        inlen = MLX5_ST_SZ_BYTES(modify_rqt_in) + sizeof(u32) * size;
 126        in = kvzalloc(inlen, GFP_KERNEL);
 127        if (!in)
 128                return -ENOMEM;
 129
 130        rqtc = MLX5_ADDR_OF(modify_rqt_in, in, ctx);
 131
 132        MLX5_SET(modify_rqt_in, in, bitmask.rqn_list, 1);
 133        MLX5_SET(rqtc, rqtc, rqt_actual_size, size);
 134        for (i = 0; i < size; i++)
 135                MLX5_SET(rqtc, rqtc, rq_num[i], rqns[i]);
 136
 137        err = mlx5_core_modify_rqt(rqt->mdev, rqt->rqtn, in, inlen);
 138
 139        kvfree(in);
 140        return err;
 141}
 142
 143int mlx5e_rqt_redirect_direct(struct mlx5e_rqt *rqt, u32 rqn)
 144{
 145        return mlx5e_rqt_redirect(rqt, &rqn, 1);
 146}
 147
 148int mlx5e_rqt_redirect_indir(struct mlx5e_rqt *rqt, u32 *rqns, unsigned int num_rqns,
 149                             u8 hfunc, struct mlx5e_rss_params_indir *indir)
 150{
 151        u32 *rss_rqns;
 152        int err;
 153
 154        if (WARN_ON(rqt->size != MLX5E_INDIR_RQT_SIZE))
 155                return -EINVAL;
 156
 157        rss_rqns = kvmalloc_array(MLX5E_INDIR_RQT_SIZE, sizeof(*rss_rqns), GFP_KERNEL);
 158        if (!rss_rqns)
 159                return -ENOMEM;
 160
 161        err = mlx5e_calc_indir_rqns(rss_rqns, rqns, num_rqns, hfunc, indir);
 162        if (err)
 163                goto out;
 164
 165        err = mlx5e_rqt_redirect(rqt, rss_rqns, MLX5E_INDIR_RQT_SIZE);
 166
 167out:
 168        kvfree(rss_rqns);
 169        return err;
 170}
 171