• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 struct mlx5e_tir_builder {
17 	u32 in[MLX5E_TIR_CMD_IN_SZ_DW];
18 	bool modify;
19 };
20 
mlx5e_tir_builder_alloc(bool modify)21 struct 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 
mlx5e_tir_builder_free(struct mlx5e_tir_builder * builder)31 void mlx5e_tir_builder_free(struct mlx5e_tir_builder *builder)
32 {
33 	kvfree(builder);
34 }
35 
mlx5e_tir_builder_clear(struct mlx5e_tir_builder * builder)36 void mlx5e_tir_builder_clear(struct mlx5e_tir_builder *builder)
37 {
38 	memset(builder->in, 0, sizeof(builder->in));
39 }
40 
mlx5e_tir_builder_get_tirc(struct mlx5e_tir_builder * builder)41 static 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 
mlx5e_tir_builder_build_inline(struct mlx5e_tir_builder * builder,u32 tdn,u32 rqn)48 void 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 
mlx5e_tir_builder_build_rqt(struct mlx5e_tir_builder * builder,u32 tdn,u32 rqtn,bool inner_ft_support)60 void 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 
mlx5e_tir_builder_build_packet_merge(struct mlx5e_tir_builder * builder,const struct mlx5e_packet_merge_param * pkt_merge_param)73 void mlx5e_tir_builder_build_packet_merge(struct mlx5e_tir_builder *builder,
74 					  const struct mlx5e_packet_merge_param *pkt_merge_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.packet_merge, 1);
81 
82 	if (pkt_merge_param->type == MLX5E_PACKET_MERGE_NONE)
83 		return;
84 
85 	MLX5_SET(tirc, tirc, packet_merge_mask,
86 		 MLX5_TIRC_PACKET_MERGE_MASK_IPV4_LRO |
87 		 MLX5_TIRC_PACKET_MERGE_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, pkt_merge_param->timeout);
91 }
92 
mlx5e_hfunc_to_hw(u8 hfunc)93 static 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 
mlx5e_tir_builder_build_rss(struct mlx5e_tir_builder * builder,const struct mlx5e_rss_params_hash * rss_hash,const struct mlx5e_rss_params_traffic_type * rss_tt,bool inner)105 void 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 
mlx5e_tir_builder_build_direct(struct mlx5e_tir_builder * builder)134 void 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 
mlx5e_tir_builder_build_tls(struct mlx5e_tir_builder * builder)143 void 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 
mlx5e_tir_init(struct mlx5e_tir * tir,struct mlx5e_tir_builder * builder,struct mlx5_core_dev * mdev,bool reg)155 int 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 
mlx5e_tir_destroy(struct mlx5e_tir * tir)179 void 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 
mlx5e_tir_modify(struct mlx5e_tir * tir,struct mlx5e_tir_builder * builder)197 int 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