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
41void 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(dev: 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
52int 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(dev: mdev, mkey, in, inlen);
73
74 kvfree(addr: in);
75 return err;
76}
77
78int 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(dev: mdev))
85 MLX5_SET(tisc, tisc, strict_lag_tx_port_affinity, 1);
86
87 return mlx5_core_create_tis(dev: mdev, in, tisn);
88}
89
90void mlx5e_destroy_tis(struct mlx5_core_dev *mdev, u32 tisn)
91{
92 mlx5_core_destroy_tis(dev: mdev, tisn);
93}
94
95static 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: tisn[i][tc]);
102}
103
104static 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
109static 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: &tisn[i][tc]);
127 if (err)
128 goto err_close_tises;
129 }
130 }
131
132 return 0;
133
134err_close_tises:
135 for (; i >= 0; i--) {
136 for (tc--; tc >= 0; tc--)
137 mlx5e_destroy_tis(mdev, tisn: tisn[i][tc]);
138 tc = MLX5_MAX_NUM_TC;
139 }
140
141 return err;
142}
143
144static unsigned int
145mlx5e_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(priv: dev);
149 union devlink_param_value val;
150 int err;
151
152 err = devl_param_driverinit_value_get(devlink, param_id, val: &val);
153 return err ? MLX5_DEFAULT_NUM_DOORBELLS : val.vu32;
154}
155
156int 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(dev: mdev, pdn: &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(dev: mdev, tdn: &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, pdn: res->pdn, mkey: &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 = kcalloc(num_doorbells, sizeof(*res->bfregs), GFP_KERNEL);
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, bfreg: res->bfregs + i, map_wc: false, fast_path: 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, tisn: 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(list: &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(ptr: 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
220err_destroy_bfregs:
221 for (i = 0; i < res->num_bfregs; i++)
222 mlx5_free_bfreg(mdev, bfreg: res->bfregs + i);
223 kfree(objp: res->bfregs);
224err_destroy_mkey:
225 mlx5_core_destroy_mkey(dev: mdev, mkey: res->mkey);
226err_dealloc_transport_domain:
227 mlx5_core_dealloc_transport_domain(dev: mdev, tdn: res->td.tdn);
228err_dealloc_pd:
229 mlx5_core_dealloc_pd(dev: mdev, pdn: res->pdn);
230 return err;
231}
232
233void 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(dek_priv: mdev->mlx5e_res.dek_priv);
238 mdev->mlx5e_res.dek_priv = NULL;
239 if (res->tisn_valid)
240 mlx5e_destroy_tises(mdev, tisn: res->tisn);
241 for (unsigned int i = 0; i < res->num_bfregs; i++)
242 mlx5_free_bfreg(mdev, bfreg: res->bfregs + i);
243 kfree(objp: res->bfregs);
244 mlx5_core_destroy_mkey(dev: mdev, mkey: res->mkey);
245 mlx5_core_dealloc_transport_domain(dev: mdev, tdn: res->td.tdn);
246 mlx5_core_dealloc_pd(dev: mdev, pdn: res->pdn);
247 memset(res, 0, sizeof(*res));
248}
249
250int 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(modify: 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(lock: &mdev->mlx5e_res.hw_objs.td.list_lock);
276
277 mlx5e_tir_builder_free(builder);
278
279 return err;
280}
281
282int 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

source code of linux/drivers/net/ethernet/mellanox/mlx5/core/en_common.c