1 /*
2 * Copyright (c) 2016, 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 "devlink.h"
34 #include "en.h"
35 #include "lib/crypto.h"
36
37 /* mlx5e global resources should be placed in this file.
38 * Global resources are common to all the netdevices created on the same nic.
39 */
40
mlx5e_mkey_set_relaxed_ordering(struct mlx5_core_dev * mdev,void * mkc)41 void mlx5e_mkey_set_relaxed_ordering(struct mlx5_core_dev *mdev, void *mkc)
42 {
43 bool ro_write = MLX5_CAP_GEN(mdev, relaxed_ordering_write);
44 bool ro_read = MLX5_CAP_GEN(mdev, relaxed_ordering_read) ||
45 (pcie_relaxed_ordering_enabled(mdev->pdev) &&
46 MLX5_CAP_GEN(mdev, relaxed_ordering_read_pci_enabled));
47
48 MLX5_SET(mkc, mkc, relaxed_ordering_read, ro_read);
49 MLX5_SET(mkc, mkc, relaxed_ordering_write, ro_write);
50 }
51
mlx5e_create_mkey(struct mlx5_core_dev * mdev,u32 pdn,u32 * mkey)52 int mlx5e_create_mkey(struct mlx5_core_dev *mdev, u32 pdn, u32 *mkey)
53 {
54 int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
55 void *mkc;
56 u32 *in;
57 int err;
58
59 in = kvzalloc(inlen, GFP_KERNEL);
60 if (!in)
61 return -ENOMEM;
62
63 mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
64 MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);
65 MLX5_SET(mkc, mkc, lw, 1);
66 MLX5_SET(mkc, mkc, lr, 1);
67 mlx5e_mkey_set_relaxed_ordering(mdev, mkc);
68 MLX5_SET(mkc, mkc, pd, pdn);
69 MLX5_SET(mkc, mkc, length64, 1);
70 MLX5_SET(mkc, mkc, qpn, 0xffffff);
71
72 err = mlx5_core_create_mkey(mdev, mkey, in, inlen);
73
74 kvfree(in);
75 return err;
76 }
77
mlx5e_create_tis(struct mlx5_core_dev * mdev,void * in,u32 * tisn)78 int mlx5e_create_tis(struct mlx5_core_dev *mdev, void *in, u32 *tisn)
79 {
80 void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
81
82 MLX5_SET(tisc, tisc, transport_domain, mdev->mlx5e_res.hw_objs.td.tdn);
83
84 if (mlx5_lag_is_lacp_owner(mdev))
85 MLX5_SET(tisc, tisc, strict_lag_tx_port_affinity, 1);
86
87 return mlx5_core_create_tis(mdev, in, tisn);
88 }
89
mlx5e_destroy_tis(struct mlx5_core_dev * mdev,u32 tisn)90 void mlx5e_destroy_tis(struct mlx5_core_dev *mdev, u32 tisn)
91 {
92 mlx5_core_destroy_tis(mdev, tisn);
93 }
94
mlx5e_destroy_tises(struct mlx5_core_dev * mdev,u32 tisn[MLX5_MAX_PORTS][MLX5_MAX_NUM_TC])95 static void mlx5e_destroy_tises(struct mlx5_core_dev *mdev, u32 tisn[MLX5_MAX_PORTS][MLX5_MAX_NUM_TC])
96 {
97 int tc, i;
98
99 for (i = 0; i < mlx5e_get_num_lag_ports(mdev); i++)
100 for (tc = 0; tc < MLX5_MAX_NUM_TC; tc++)
101 mlx5e_destroy_tis(mdev, tisn[i][tc]);
102 }
103
mlx5_lag_should_assign_affinity(struct mlx5_core_dev * mdev)104 static bool mlx5_lag_should_assign_affinity(struct mlx5_core_dev *mdev)
105 {
106 return MLX5_CAP_GEN(mdev, lag_tx_port_affinity) && mlx5e_get_num_lag_ports(mdev) > 1;
107 }
108
mlx5e_create_tises(struct mlx5_core_dev * mdev,u32 tisn[MLX5_MAX_PORTS][MLX5_MAX_NUM_TC])109 static int mlx5e_create_tises(struct mlx5_core_dev *mdev, u32 tisn[MLX5_MAX_PORTS][MLX5_MAX_NUM_TC])
110 {
111 int tc, i;
112 int err;
113
114 for (i = 0; i < mlx5e_get_num_lag_ports(mdev); i++) {
115 for (tc = 0; tc < MLX5_MAX_NUM_TC; tc++) {
116 u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {};
117 void *tisc;
118
119 tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
120
121 MLX5_SET(tisc, tisc, prio, tc << 1);
122
123 if (mlx5_lag_should_assign_affinity(mdev))
124 MLX5_SET(tisc, tisc, lag_tx_port_affinity, i + 1);
125
126 err = mlx5e_create_tis(mdev, in, &tisn[i][tc]);
127 if (err)
128 goto err_close_tises;
129 }
130 }
131
132 return 0;
133
134 err_close_tises:
135 for (; i >= 0; i--) {
136 for (tc--; tc >= 0; tc--)
137 mlx5e_destroy_tis(mdev, tisn[i][tc]);
138 tc = MLX5_MAX_NUM_TC;
139 }
140
141 return err;
142 }
143
144 static unsigned int
mlx5e_get_devlink_param_num_doorbells(struct mlx5_core_dev * dev)145 mlx5e_get_devlink_param_num_doorbells(struct mlx5_core_dev *dev)
146 {
147 const u32 param_id = DEVLINK_PARAM_GENERIC_ID_NUM_DOORBELLS;
148 struct devlink *devlink = priv_to_devlink(dev);
149 union devlink_param_value val;
150 int err;
151
152 err = devl_param_driverinit_value_get(devlink, param_id, &val);
153 return err ? MLX5_DEFAULT_NUM_DOORBELLS : val.vu32;
154 }
155
mlx5e_create_mdev_resources(struct mlx5_core_dev * mdev,bool create_tises)156 int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev, bool create_tises)
157 {
158 struct mlx5e_hw_objs *res = &mdev->mlx5e_res.hw_objs;
159 unsigned int num_doorbells, i;
160 int err;
161
162 err = mlx5_core_alloc_pd(mdev, &res->pdn);
163 if (err) {
164 mlx5_core_err(mdev, "alloc pd failed, %d\n", err);
165 return err;
166 }
167
168 err = mlx5_core_alloc_transport_domain(mdev, &res->td.tdn);
169 if (err) {
170 mlx5_core_err(mdev, "alloc td failed, %d\n", err);
171 goto err_dealloc_pd;
172 }
173
174 err = mlx5e_create_mkey(mdev, res->pdn, &res->mkey);
175 if (err) {
176 mlx5_core_err(mdev, "create mkey failed, %d\n", err);
177 goto err_dealloc_transport_domain;
178 }
179
180 num_doorbells = min(mlx5e_get_devlink_param_num_doorbells(mdev),
181 mlx5e_get_max_num_channels(mdev));
182 res->bfregs = kzalloc_objs(*res->bfregs, num_doorbells);
183 if (!res->bfregs) {
184 err = -ENOMEM;
185 goto err_destroy_mkey;
186 }
187
188 for (i = 0; i < num_doorbells; i++) {
189 err = mlx5_alloc_bfreg(mdev, res->bfregs + i, false, false);
190 if (err) {
191 mlx5_core_warn(mdev,
192 "could only allocate %d/%d doorbells, err %d.\n",
193 i, num_doorbells, err);
194 break;
195 }
196 }
197 res->num_bfregs = i;
198
199 if (create_tises) {
200 err = mlx5e_create_tises(mdev, res->tisn);
201 if (err) {
202 mlx5_core_err(mdev, "alloc tises failed, %d\n", err);
203 goto err_destroy_bfregs;
204 }
205 res->tisn_valid = true;
206 }
207
208 INIT_LIST_HEAD(&res->td.tirs_list);
209 mutex_init(&res->td.list_lock);
210
211 mdev->mlx5e_res.dek_priv = mlx5_crypto_dek_init(mdev);
212 if (IS_ERR(mdev->mlx5e_res.dek_priv)) {
213 mlx5_core_err(mdev, "crypto dek init failed, %pe\n",
214 mdev->mlx5e_res.dek_priv);
215 mdev->mlx5e_res.dek_priv = NULL;
216 }
217
218 return 0;
219
220 err_destroy_bfregs:
221 for (i = 0; i < res->num_bfregs; i++)
222 mlx5_free_bfreg(mdev, res->bfregs + i);
223 kfree(res->bfregs);
224 err_destroy_mkey:
225 mlx5_core_destroy_mkey(mdev, res->mkey);
226 err_dealloc_transport_domain:
227 mlx5_core_dealloc_transport_domain(mdev, res->td.tdn);
228 err_dealloc_pd:
229 mlx5_core_dealloc_pd(mdev, res->pdn);
230 return err;
231 }
232
mlx5e_destroy_mdev_resources(struct mlx5_core_dev * mdev)233 void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev)
234 {
235 struct mlx5e_hw_objs *res = &mdev->mlx5e_res.hw_objs;
236
237 mlx5_crypto_dek_cleanup(mdev->mlx5e_res.dek_priv);
238 mdev->mlx5e_res.dek_priv = NULL;
239 if (res->tisn_valid)
240 mlx5e_destroy_tises(mdev, res->tisn);
241 for (unsigned int i = 0; i < res->num_bfregs; i++)
242 mlx5_free_bfreg(mdev, res->bfregs + i);
243 kfree(res->bfregs);
244 mlx5_core_destroy_mkey(mdev, res->mkey);
245 mlx5_core_dealloc_transport_domain(mdev, res->td.tdn);
246 mlx5_core_dealloc_pd(mdev, res->pdn);
247 memset(res, 0, sizeof(*res));
248 }
249
mlx5e_modify_tirs_lb(struct mlx5_core_dev * mdev,bool enable_uc_lb,bool enable_mc_lb)250 int mlx5e_modify_tirs_lb(struct mlx5_core_dev *mdev, bool enable_uc_lb,
251 bool enable_mc_lb)
252 {
253 struct mlx5e_tir_builder *builder;
254 struct mlx5e_tir *tir;
255 int err = 0;
256
257 builder = mlx5e_tir_builder_alloc(true);
258 if (!builder)
259 return -ENOMEM;
260
261 mlx5e_tir_builder_build_self_lb_block(builder, enable_uc_lb,
262 enable_mc_lb);
263
264 mutex_lock(&mdev->mlx5e_res.hw_objs.td.list_lock);
265 list_for_each_entry(tir, &mdev->mlx5e_res.hw_objs.td.tirs_list, list) {
266 err = mlx5e_tir_modify(tir, builder);
267 if (err) {
268 mlx5_core_err(mdev,
269 "modify tir(0x%x) enable_lb uc(%d) mc(%d) failed, %d\n",
270 mlx5e_tir_get_tirn(tir),
271 enable_uc_lb, enable_mc_lb, err);
272 break;
273 }
274 }
275 mutex_unlock(&mdev->mlx5e_res.hw_objs.td.list_lock);
276
277 mlx5e_tir_builder_free(builder);
278
279 return err;
280 }
281
mlx5e_refresh_tirs(struct mlx5_core_dev * mdev,bool enable_uc_lb,bool enable_mc_lb)282 int mlx5e_refresh_tirs(struct mlx5_core_dev *mdev, bool enable_uc_lb,
283 bool enable_mc_lb)
284 {
285 if (MLX5_CAP_GEN(mdev, tis_tir_td_order))
286 return 0; /* refresh not needed */
287
288 return mlx5e_modify_tirs_lb(mdev, enable_uc_lb, enable_mc_lb);
289 }
290