linux/drivers/net/ethernet/mellanox/mlx5/core/en/tir.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 "tir.h"
   5#include "params.h"
   6#include <linux/mlx5/transobj.h>
   7
   8#define MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ (64 * 1024)
   9
  10/* max() doesn't work inside square brackets. */
  11#define MLX5E_TIR_CMD_IN_SZ_DW ( \
  12        MLX5_ST_SZ_DW(create_tir_in) > MLX5_ST_SZ_DW(modify_tir_in) ? \
  13        MLX5_ST_SZ_DW(create_tir_in) : MLX5_ST_SZ_DW(modify_tir_in) \
  14)
  15
  16struct mlx5e_tir_builder {
  17        u32 in[MLX5E_TIR_CMD_IN_SZ_DW];
  18        bool modify;
  19};
  20
  21struct mlx5e_tir_builder *mlx5e_tir_builder_alloc(bool modify)
  22{
  23        struct mlx5e_tir_builder *builder;
  24
  25        builder = kvzalloc(sizeof(*builder), GFP_KERNEL);
  26        builder->modify = modify;
  27
  28        return builder;
  29}
  30
  31void mlx5e_tir_builder_free(struct mlx5e_tir_builder *builder)
  32{
  33        kvfree(builder);
  34}
  35
  36void mlx5e_tir_builder_clear(struct mlx5e_tir_builder *builder)
  37{
  38        memset(builder->in, 0, sizeof(builder->in));
  39}
  40
  41static void *mlx5e_tir_builder_get_tirc(struct mlx5e_tir_builder *builder)
  42{
  43        if (builder->modify)
  44                return MLX5_ADDR_OF(modify_tir_in, builder->in, ctx);
  45        return MLX5_ADDR_OF(create_tir_in, builder->in, ctx);
  46}
  47
  48void mlx5e_tir_builder_build_inline(struct mlx5e_tir_builder *builder, u32 tdn, u32 rqn)
  49{
  50        void *tirc = mlx5e_tir_builder_get_tirc(builder);
  51
  52        WARN_ON(builder->modify);
  53
  54        MLX5_SET(tirc, tirc, transport_domain, tdn);
  55        MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_DIRECT);
  56        MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_NONE);
  57        MLX5_SET(tirc, tirc, inline_rqn, rqn);
  58}
  59
  60void mlx5e_tir_builder_build_rqt(struct mlx5e_tir_builder *builder, u32 tdn,
  61                                 u32 rqtn, bool inner_ft_support)
  62{
  63        void *tirc = mlx5e_tir_builder_get_tirc(builder);
  64
  65        WARN_ON(builder->modify);
  66
  67        MLX5_SET(tirc, tirc, transport_domain, tdn);
  68        MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT);
  69        MLX5_SET(tirc, tirc, indirect_table, rqtn);
  70        MLX5_SET(tirc, tirc, tunneled_offload_en, inner_ft_support);
  71}
  72
  73void mlx5e_tir_builder_build_lro(struct mlx5e_tir_builder *builder,
  74                                 const struct mlx5e_lro_param *lro_param)
  75{
  76        void *tirc = mlx5e_tir_builder_get_tirc(builder);
  77        const unsigned int rough_max_l2_l3_hdr_sz = 256;
  78
  79        if (builder->modify)
  80                MLX5_SET(modify_tir_in, builder->in, bitmask.lro, 1);
  81
  82        if (!lro_param->enabled)
  83                return;
  84
  85        MLX5_SET(tirc, tirc, lro_enable_mask,
  86                 MLX5_TIRC_LRO_ENABLE_MASK_IPV4_LRO |
  87                 MLX5_TIRC_LRO_ENABLE_MASK_IPV6_LRO);
  88        MLX5_SET(tirc, tirc, lro_max_ip_payload_size,
  89                 (MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ - rough_max_l2_l3_hdr_sz) >> 8);
  90        MLX5_SET(tirc, tirc, lro_timeout_period_usecs, lro_param->timeout);
  91}
  92
  93static int mlx5e_hfunc_to_hw(u8 hfunc)
  94{
  95        switch (hfunc) {
  96        case ETH_RSS_HASH_TOP:
  97                return MLX5_RX_HASH_FN_TOEPLITZ;
  98        case ETH_RSS_HASH_XOR:
  99                return MLX5_RX_HASH_FN_INVERTED_XOR8;
 100        default:
 101                return MLX5_RX_HASH_FN_NONE;
 102        }
 103}
 104
 105void mlx5e_tir_builder_build_rss(struct mlx5e_tir_builder *builder,
 106                                 const struct mlx5e_rss_params_hash *rss_hash,
 107                                 const struct mlx5e_rss_params_traffic_type *rss_tt,
 108                                 bool inner)
 109{
 110        void *tirc = mlx5e_tir_builder_get_tirc(builder);
 111        void *hfso;
 112
 113        if (builder->modify)
 114                MLX5_SET(modify_tir_in, builder->in, bitmask.hash, 1);
 115
 116        MLX5_SET(tirc, tirc, rx_hash_fn, mlx5e_hfunc_to_hw(rss_hash->hfunc));
 117        if (rss_hash->hfunc == ETH_RSS_HASH_TOP) {
 118                const size_t len = MLX5_FLD_SZ_BYTES(tirc, rx_hash_toeplitz_key);
 119                void *rss_key = MLX5_ADDR_OF(tirc, tirc, rx_hash_toeplitz_key);
 120
 121                MLX5_SET(tirc, tirc, rx_hash_symmetric, 1);
 122                memcpy(rss_key, rss_hash->toeplitz_hash_key, len);
 123        }
 124
 125        if (inner)
 126                hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_inner);
 127        else
 128                hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer);
 129        MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, rss_tt->l3_prot_type);
 130        MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, rss_tt->l4_prot_type);
 131        MLX5_SET(rx_hash_field_select, hfso, selected_fields, rss_tt->rx_hash_fields);
 132}
 133
 134void mlx5e_tir_builder_build_direct(struct mlx5e_tir_builder *builder)
 135{
 136        void *tirc = mlx5e_tir_builder_get_tirc(builder);
 137
 138        WARN_ON(builder->modify);
 139
 140        MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_INVERTED_XOR8);
 141}
 142
 143void mlx5e_tir_builder_build_tls(struct mlx5e_tir_builder *builder)
 144{
 145        void *tirc = mlx5e_tir_builder_get_tirc(builder);
 146
 147        WARN_ON(builder->modify);
 148
 149        MLX5_SET(tirc, tirc, tls_en, 1);
 150        MLX5_SET(tirc, tirc, self_lb_block,
 151                 MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST |
 152                 MLX5_TIRC_SELF_LB_BLOCK_BLOCK_MULTICAST);
 153}
 154
 155int mlx5e_tir_init(struct mlx5e_tir *tir, struct mlx5e_tir_builder *builder,
 156                   struct mlx5_core_dev *mdev, bool reg)
 157{
 158        int err;
 159
 160        tir->mdev = mdev;
 161
 162        err = mlx5_core_create_tir(tir->mdev, builder->in, &tir->tirn);
 163        if (err)
 164                return err;
 165
 166        if (reg) {
 167                struct mlx5e_hw_objs *res = &tir->mdev->mlx5e_res.hw_objs;
 168
 169                mutex_lock(&res->td.list_lock);
 170                list_add(&tir->list, &res->td.tirs_list);
 171                mutex_unlock(&res->td.list_lock);
 172        } else {
 173                INIT_LIST_HEAD(&tir->list);
 174        }
 175
 176        return 0;
 177}
 178
 179void mlx5e_tir_destroy(struct mlx5e_tir *tir)
 180{
 181        struct mlx5e_hw_objs *res = &tir->mdev->mlx5e_res.hw_objs;
 182
 183        /* Skip mutex if list_del is no-op (the TIR wasn't registered in the
 184         * list). list_empty will never return true for an item of tirs_list,
 185         * and READ_ONCE/WRITE_ONCE in list_empty/list_del guarantee consistency
 186         * of the list->next value.
 187         */
 188        if (!list_empty(&tir->list)) {
 189                mutex_lock(&res->td.list_lock);
 190                list_del(&tir->list);
 191                mutex_unlock(&res->td.list_lock);
 192        }
 193
 194        mlx5_core_destroy_tir(tir->mdev, tir->tirn);
 195}
 196
 197int mlx5e_tir_modify(struct mlx5e_tir *tir, struct mlx5e_tir_builder *builder)
 198{
 199        return mlx5_core_modify_tir(tir->mdev, tir->tirn, builder->in);
 200}
 201