]>
Commit | Line | Data |
---|---|---|
48935bbb SM |
1 | /* |
2 | * Copyright (c) 2017, 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 | ||
693dfd5a | 33 | #include <rdma/ib_verbs.h> |
48935bbb SM |
34 | #include <linux/mlx5/fs.h> |
35 | #include "en.h" | |
36 | #include "ipoib.h" | |
37 | ||
ec8fd927 | 38 | #define IB_DEFAULT_Q_KEY 0xb1b |
b6dc510f | 39 | #define MLX5I_PARAMS_DEFAULT_LOG_RQ_SIZE 9 |
ec8fd927 | 40 | |
603f4a45 SM |
41 | static int mlx5i_open(struct net_device *netdev); |
42 | static int mlx5i_close(struct net_device *netdev); | |
807c4415 | 43 | static int mlx5i_change_mtu(struct net_device *netdev, int new_mtu); |
603f4a45 SM |
44 | |
45 | static const struct net_device_ops mlx5i_netdev_ops = { | |
46 | .ndo_open = mlx5i_open, | |
47 | .ndo_stop = mlx5i_close, | |
c57d2358 | 48 | .ndo_get_stats64 = mlx5i_get_stats, |
603f4a45 SM |
49 | .ndo_init = mlx5i_dev_init, |
50 | .ndo_uninit = mlx5i_dev_cleanup, | |
807c4415 | 51 | .ndo_change_mtu = mlx5i_change_mtu, |
1170fbd8 | 52 | .ndo_do_ioctl = mlx5i_ioctl, |
603f4a45 SM |
53 | }; |
54 | ||
48935bbb | 55 | /* IPoIB mlx5 netdev profile */ |
b6dc510f ES |
56 | static void mlx5i_build_nic_params(struct mlx5_core_dev *mdev, |
57 | struct mlx5e_params *params) | |
58 | { | |
59 | /* Override RQ params as IPoIB supports only LINKED LIST RQ for now */ | |
2ccb0a79 TT |
60 | MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_STRIDING_RQ, false); |
61 | mlx5e_set_rq_type(mdev, params); | |
2a0f561b | 62 | mlx5e_init_rq_type_params(mdev, params); |
b6dc510f ES |
63 | |
64 | /* RQ size in ipoib by default is 512 */ | |
73281b78 | 65 | params->log_rq_mtu_frames = is_kdump_kernel() ? |
b6dc510f ES |
66 | MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE : |
67 | MLX5I_PARAMS_DEFAULT_LOG_RQ_SIZE; | |
68 | ||
69 | params->lro_en = false; | |
472a1e44 | 70 | params->hard_mtu = MLX5_IB_GRH_BYTES + MLX5_IPOIB_HARD_LEN; |
b6dc510f | 71 | } |
48935bbb SM |
72 | |
73 | /* Called directly after IPoIB netdevice was created to initialize SW structs */ | |
182570b2 FD |
74 | int mlx5i_init(struct mlx5_core_dev *mdev, |
75 | struct net_device *netdev, | |
76 | const struct mlx5e_profile *profile, | |
77 | void *ppriv) | |
48935bbb SM |
78 | { |
79 | struct mlx5e_priv *priv = mlx5i_epriv(netdev); | |
8e1d162d | 80 | u16 max_mtu; |
182570b2 | 81 | int err; |
48935bbb | 82 | |
519a0bf5 | 83 | err = mlx5e_netdev_init(netdev, priv, mdev, profile, ppriv); |
182570b2 FD |
84 | if (err) |
85 | return err; | |
86 | ||
8e1d162d FD |
87 | mlx5_query_port_max_mtu(mdev, &max_mtu, 1); |
88 | netdev->mtu = max_mtu; | |
89 | ||
472a1e44 | 90 | mlx5e_build_nic_params(mdev, &priv->channels.params, |
779d986d FD |
91 | mlx5e_get_netdev_max_channels(netdev), |
92 | netdev->mtu); | |
b6dc510f | 93 | mlx5i_build_nic_params(mdev, &priv->channels.params); |
5360fd47 | 94 | |
237f258c FD |
95 | mlx5e_timestamp_init(priv); |
96 | ||
c139dbfd | 97 | /* netdev init */ |
603f4a45 SM |
98 | netdev->hw_features |= NETIF_F_SG; |
99 | netdev->hw_features |= NETIF_F_IP_CSUM; | |
100 | netdev->hw_features |= NETIF_F_IPV6_CSUM; | |
101 | netdev->hw_features |= NETIF_F_GRO; | |
102 | netdev->hw_features |= NETIF_F_TSO; | |
103 | netdev->hw_features |= NETIF_F_TSO6; | |
104 | netdev->hw_features |= NETIF_F_RXCSUM; | |
105 | netdev->hw_features |= NETIF_F_RXHASH; | |
106 | ||
107 | netdev->netdev_ops = &mlx5i_netdev_ops; | |
076b0936 | 108 | netdev->ethtool_ops = &mlx5i_ethtool_ops; |
182570b2 FD |
109 | |
110 | return 0; | |
48935bbb SM |
111 | } |
112 | ||
113 | /* Called directly before IPoIB netdevice is destroyed to cleanup SW structs */ | |
182570b2 | 114 | void mlx5i_cleanup(struct mlx5e_priv *priv) |
48935bbb | 115 | { |
182570b2 | 116 | mlx5e_netdev_cleanup(priv->netdev, priv); |
48935bbb SM |
117 | } |
118 | ||
fbb66ad5 | 119 | static void mlx5i_grp_sw_update_stats(struct mlx5e_priv *priv) |
c57d2358 | 120 | { |
779d986d | 121 | int max_nch = mlx5e_get_netdev_max_channels(priv->netdev); |
c57d2358 FD |
122 | struct mlx5e_sw_stats s = { 0 }; |
123 | int i, j; | |
124 | ||
779d986d | 125 | for (i = 0; i < max_nch; i++) { |
c57d2358 FD |
126 | struct mlx5e_channel_stats *channel_stats; |
127 | struct mlx5e_rq_stats *rq_stats; | |
128 | ||
129 | channel_stats = &priv->channel_stats[i]; | |
130 | rq_stats = &channel_stats->rq; | |
131 | ||
132 | s.rx_packets += rq_stats->packets; | |
133 | s.rx_bytes += rq_stats->bytes; | |
134 | ||
135 | for (j = 0; j < priv->max_opened_tc; j++) { | |
136 | struct mlx5e_sq_stats *sq_stats = &channel_stats->sq[j]; | |
137 | ||
138 | s.tx_packets += sq_stats->packets; | |
139 | s.tx_bytes += sq_stats->bytes; | |
140 | s.tx_queue_dropped += sq_stats->dropped; | |
141 | } | |
142 | } | |
143 | ||
144 | memcpy(&priv->stats.sw, &s, sizeof(s)); | |
145 | } | |
146 | ||
147 | void mlx5i_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) | |
148 | { | |
149 | struct mlx5e_priv *priv = mlx5i_epriv(dev); | |
150 | struct mlx5e_sw_stats *sstats = &priv->stats.sw; | |
151 | ||
152 | mlx5i_grp_sw_update_stats(priv); | |
153 | ||
154 | stats->rx_packets = sstats->rx_packets; | |
155 | stats->rx_bytes = sstats->rx_bytes; | |
156 | stats->tx_packets = sstats->tx_packets; | |
157 | stats->tx_bytes = sstats->tx_bytes; | |
158 | stats->tx_dropped = sstats->tx_queue_dropped; | |
159 | } | |
160 | ||
af98cebc | 161 | int mlx5i_init_underlay_qp(struct mlx5e_priv *priv) |
c8249eda AV |
162 | { |
163 | struct mlx5_core_dev *mdev = priv->mdev; | |
164 | struct mlx5i_priv *ipriv = priv->ppriv; | |
165 | struct mlx5_core_qp *qp = &ipriv->qp; | |
166 | struct mlx5_qp_context *context; | |
167 | int ret; | |
168 | ||
169 | /* QP states */ | |
170 | context = kzalloc(sizeof(*context), GFP_KERNEL); | |
171 | if (!context) | |
172 | return -ENOMEM; | |
173 | ||
174 | context->flags = cpu_to_be32(MLX5_QP_PM_MIGRATED << 11); | |
175 | context->pri_path.port = 1; | |
da34f1a8 | 176 | context->pri_path.pkey_index = cpu_to_be16(ipriv->pkey_index); |
c8249eda AV |
177 | context->qkey = cpu_to_be32(IB_DEFAULT_Q_KEY); |
178 | ||
179 | ret = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_RST2INIT_QP, 0, context, qp); | |
180 | if (ret) { | |
181 | mlx5_core_err(mdev, "Failed to modify qp RST2INIT, err: %d\n", ret); | |
182 | goto err_qp_modify_to_err; | |
183 | } | |
184 | memset(context, 0, sizeof(*context)); | |
185 | ||
186 | ret = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_INIT2RTR_QP, 0, context, qp); | |
187 | if (ret) { | |
188 | mlx5_core_err(mdev, "Failed to modify qp INIT2RTR, err: %d\n", ret); | |
189 | goto err_qp_modify_to_err; | |
190 | } | |
191 | ||
192 | ret = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_RTR2RTS_QP, 0, context, qp); | |
193 | if (ret) { | |
194 | mlx5_core_err(mdev, "Failed to modify qp RTR2RTS, err: %d\n", ret); | |
195 | goto err_qp_modify_to_err; | |
196 | } | |
197 | ||
198 | kfree(context); | |
199 | return 0; | |
200 | ||
201 | err_qp_modify_to_err: | |
202 | mlx5_core_qp_modify(mdev, MLX5_CMD_OP_2ERR_QP, 0, &context, qp); | |
203 | kfree(context); | |
204 | return ret; | |
205 | } | |
206 | ||
af98cebc | 207 | void mlx5i_uninit_underlay_qp(struct mlx5e_priv *priv) |
c8249eda AV |
208 | { |
209 | struct mlx5i_priv *ipriv = priv->ppriv; | |
210 | struct mlx5_core_dev *mdev = priv->mdev; | |
211 | struct mlx5_qp_context context; | |
212 | int err; | |
213 | ||
214 | err = mlx5_core_qp_modify(mdev, MLX5_CMD_OP_2RST_QP, 0, &context, | |
215 | &ipriv->qp); | |
216 | if (err) | |
217 | mlx5_core_err(mdev, "Failed to modify qp 2RST, err: %d\n", err); | |
218 | } | |
219 | ||
ec8fd927 SM |
220 | #define MLX5_QP_ENHANCED_ULP_STATELESS_MODE 2 |
221 | ||
4c6c615e | 222 | int mlx5i_create_underlay_qp(struct mlx5_core_dev *mdev, struct mlx5_core_qp *qp) |
ec8fd927 | 223 | { |
ec8fd927 SM |
224 | u32 *in = NULL; |
225 | void *addr_path; | |
226 | int ret = 0; | |
227 | int inlen; | |
228 | void *qpc; | |
229 | ||
230 | inlen = MLX5_ST_SZ_BYTES(create_qp_in); | |
1b9a07ee | 231 | in = kvzalloc(inlen, GFP_KERNEL); |
ec8fd927 SM |
232 | if (!in) |
233 | return -ENOMEM; | |
234 | ||
235 | qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); | |
236 | MLX5_SET(qpc, qpc, st, MLX5_QP_ST_UD); | |
237 | MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); | |
238 | MLX5_SET(qpc, qpc, ulp_stateless_offload_mode, | |
239 | MLX5_QP_ENHANCED_ULP_STATELESS_MODE); | |
240 | ||
241 | addr_path = MLX5_ADDR_OF(qpc, qpc, primary_address_path); | |
32f69e4b | 242 | MLX5_SET(ads, addr_path, vhca_port_num, 1); |
ec8fd927 SM |
243 | MLX5_SET(ads, addr_path, grh, 1); |
244 | ||
245 | ret = mlx5_core_create_qp(mdev, qp, in, inlen); | |
246 | if (ret) { | |
247 | mlx5_core_err(mdev, "Failed creating IPoIB QP err : %d\n", ret); | |
248 | goto out; | |
249 | } | |
250 | ||
ec8fd927 | 251 | out: |
ec8fd927 SM |
252 | kvfree(in); |
253 | return ret; | |
254 | } | |
255 | ||
4c6c615e | 256 | void mlx5i_destroy_underlay_qp(struct mlx5_core_dev *mdev, struct mlx5_core_qp *qp) |
ec8fd927 SM |
257 | { |
258 | mlx5_core_destroy_qp(mdev, qp); | |
259 | } | |
260 | ||
48935bbb SM |
261 | static int mlx5i_init_tx(struct mlx5e_priv *priv) |
262 | { | |
5426a0b2 SM |
263 | struct mlx5i_priv *ipriv = priv->ppriv; |
264 | int err; | |
265 | ||
ec8fd927 SM |
266 | err = mlx5i_create_underlay_qp(priv->mdev, &ipriv->qp); |
267 | if (err) { | |
268 | mlx5_core_warn(priv->mdev, "create underlay QP failed, %d\n", err); | |
269 | return err; | |
270 | } | |
5426a0b2 SM |
271 | |
272 | err = mlx5e_create_tis(priv->mdev, 0 /* tc */, ipriv->qp.qpn, &priv->tisn[0]); | |
273 | if (err) { | |
274 | mlx5_core_warn(priv->mdev, "create tis failed, %d\n", err); | |
c8249eda | 275 | goto err_destroy_underlay_qp; |
5426a0b2 SM |
276 | } |
277 | ||
48935bbb | 278 | return 0; |
c8249eda AV |
279 | |
280 | err_destroy_underlay_qp: | |
281 | mlx5i_destroy_underlay_qp(priv->mdev, &ipriv->qp); | |
282 | return err; | |
48935bbb SM |
283 | } |
284 | ||
a7082ef0 | 285 | static void mlx5i_cleanup_tx(struct mlx5e_priv *priv) |
48935bbb | 286 | { |
ec8fd927 SM |
287 | struct mlx5i_priv *ipriv = priv->ppriv; |
288 | ||
5426a0b2 | 289 | mlx5e_destroy_tis(priv->mdev, priv->tisn[0]); |
ec8fd927 | 290 | mlx5i_destroy_underlay_qp(priv->mdev, &ipriv->qp); |
48935bbb SM |
291 | } |
292 | ||
bc81b9d3 SM |
293 | static int mlx5i_create_flow_steering(struct mlx5e_priv *priv) |
294 | { | |
1ae1df3a OG |
295 | struct ttc_params ttc_params = {}; |
296 | int tt, err; | |
bc81b9d3 SM |
297 | |
298 | priv->fs.ns = mlx5_get_flow_namespace(priv->mdev, | |
299 | MLX5_FLOW_NAMESPACE_KERNEL); | |
300 | ||
301 | if (!priv->fs.ns) | |
302 | return -EINVAL; | |
303 | ||
304 | err = mlx5e_arfs_create_tables(priv); | |
305 | if (err) { | |
306 | netdev_err(priv->netdev, "Failed to create arfs tables, err=%d\n", | |
307 | err); | |
308 | priv->netdev->hw_features &= ~NETIF_F_NTUPLE; | |
309 | } | |
310 | ||
1ae1df3a OG |
311 | mlx5e_set_ttc_basic_params(priv, &ttc_params); |
312 | mlx5e_set_inner_ttc_ft_params(&ttc_params); | |
313 | for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) | |
314 | ttc_params.indir_tirn[tt] = priv->inner_indir_tir[tt].tirn; | |
315 | ||
316 | err = mlx5e_create_inner_ttc_table(priv, &ttc_params, &priv->fs.inner_ttc); | |
458821c7 FD |
317 | if (err) { |
318 | netdev_err(priv->netdev, "Failed to create inner ttc table, err=%d\n", | |
319 | err); | |
320 | goto err_destroy_arfs_tables; | |
321 | } | |
322 | ||
1ae1df3a OG |
323 | mlx5e_set_ttc_ft_params(&ttc_params); |
324 | for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) | |
468330e8 | 325 | ttc_params.indir_tirn[tt] = priv->indir_tir[tt].tirn; |
1ae1df3a OG |
326 | |
327 | err = mlx5e_create_ttc_table(priv, &ttc_params, &priv->fs.ttc); | |
bc81b9d3 SM |
328 | if (err) { |
329 | netdev_err(priv->netdev, "Failed to create ttc table, err=%d\n", | |
330 | err); | |
458821c7 | 331 | goto err_destroy_inner_ttc_table; |
bc81b9d3 SM |
332 | } |
333 | ||
334 | return 0; | |
335 | ||
458821c7 | 336 | err_destroy_inner_ttc_table: |
1ae1df3a | 337 | mlx5e_destroy_inner_ttc_table(priv, &priv->fs.inner_ttc); |
bc81b9d3 SM |
338 | err_destroy_arfs_tables: |
339 | mlx5e_arfs_destroy_tables(priv); | |
340 | ||
341 | return err; | |
342 | } | |
343 | ||
344 | static void mlx5i_destroy_flow_steering(struct mlx5e_priv *priv) | |
345 | { | |
1ae1df3a OG |
346 | mlx5e_destroy_ttc_table(priv, &priv->fs.ttc); |
347 | mlx5e_destroy_inner_ttc_table(priv, &priv->fs.inner_ttc); | |
bc81b9d3 SM |
348 | mlx5e_arfs_destroy_tables(priv); |
349 | } | |
350 | ||
48935bbb SM |
351 | static int mlx5i_init_rx(struct mlx5e_priv *priv) |
352 | { | |
1462e48d | 353 | struct mlx5_core_dev *mdev = priv->mdev; |
8f493ffd SM |
354 | int err; |
355 | ||
1462e48d RD |
356 | mlx5e_create_q_counters(priv); |
357 | ||
358 | err = mlx5e_open_drop_rq(priv, &priv->drop_rq); | |
359 | if (err) { | |
360 | mlx5_core_err(mdev, "open drop rq failed, %d\n", err); | |
361 | goto err_destroy_q_counters; | |
362 | } | |
363 | ||
8f493ffd SM |
364 | err = mlx5e_create_indirect_rqt(priv); |
365 | if (err) | |
1462e48d | 366 | goto err_close_drop_rq; |
8f493ffd SM |
367 | |
368 | err = mlx5e_create_direct_rqts(priv); | |
369 | if (err) | |
370 | goto err_destroy_indirect_rqts; | |
371 | ||
46dc933c | 372 | err = mlx5e_create_indirect_tirs(priv, true); |
8f493ffd SM |
373 | if (err) |
374 | goto err_destroy_direct_rqts; | |
375 | ||
376 | err = mlx5e_create_direct_tirs(priv); | |
377 | if (err) | |
378 | goto err_destroy_indirect_tirs; | |
379 | ||
58569ef8 AV |
380 | err = mlx5i_create_flow_steering(priv); |
381 | if (err) | |
dae37456 | 382 | goto err_destroy_direct_tirs; |
58569ef8 | 383 | |
48935bbb | 384 | return 0; |
8f493ffd | 385 | |
bc81b9d3 SM |
386 | err_destroy_direct_tirs: |
387 | mlx5e_destroy_direct_tirs(priv); | |
8f493ffd | 388 | err_destroy_indirect_tirs: |
46dc933c | 389 | mlx5e_destroy_indirect_tirs(priv, true); |
8f493ffd SM |
390 | err_destroy_direct_rqts: |
391 | mlx5e_destroy_direct_rqts(priv); | |
392 | err_destroy_indirect_rqts: | |
393 | mlx5e_destroy_rqt(priv, &priv->indir_rqt); | |
1462e48d RD |
394 | err_close_drop_rq: |
395 | mlx5e_close_drop_rq(&priv->drop_rq); | |
396 | err_destroy_q_counters: | |
397 | mlx5e_destroy_q_counters(priv); | |
8f493ffd | 398 | return err; |
48935bbb SM |
399 | } |
400 | ||
401 | static void mlx5i_cleanup_rx(struct mlx5e_priv *priv) | |
402 | { | |
bc81b9d3 | 403 | mlx5i_destroy_flow_steering(priv); |
8f493ffd | 404 | mlx5e_destroy_direct_tirs(priv); |
46dc933c | 405 | mlx5e_destroy_indirect_tirs(priv, true); |
8f493ffd SM |
406 | mlx5e_destroy_direct_rqts(priv); |
407 | mlx5e_destroy_rqt(priv, &priv->indir_rqt); | |
1462e48d RD |
408 | mlx5e_close_drop_rq(&priv->drop_rq); |
409 | mlx5e_destroy_q_counters(priv); | |
48935bbb SM |
410 | } |
411 | ||
412 | static const struct mlx5e_profile mlx5i_nic_profile = { | |
413 | .init = mlx5i_init, | |
414 | .cleanup = mlx5i_cleanup, | |
415 | .init_tx = mlx5i_init_tx, | |
416 | .cleanup_tx = mlx5i_cleanup_tx, | |
417 | .init_rx = mlx5i_init_rx, | |
418 | .cleanup_rx = mlx5i_cleanup_rx, | |
419 | .enable = NULL, /* mlx5i_enable */ | |
420 | .disable = NULL, /* mlx5i_disable */ | |
421 | .update_stats = NULL, /* mlx5i_update_stats */ | |
7ca42c80 | 422 | .update_carrier = NULL, /* no HW update in IB link */ |
9d6bd752 SM |
423 | .rx_handlers.handle_rx_cqe = mlx5i_handle_rx_cqe, |
424 | .rx_handlers.handle_rx_cqe_mpwqe = NULL, /* Not supported */ | |
48935bbb SM |
425 | .max_tc = MLX5I_MAX_NUM_TC, |
426 | }; | |
427 | ||
603f4a45 SM |
428 | /* mlx5i netdev NDos */ |
429 | ||
807c4415 ES |
430 | static int mlx5i_change_mtu(struct net_device *netdev, int new_mtu) |
431 | { | |
432 | struct mlx5e_priv *priv = mlx5i_epriv(netdev); | |
433 | struct mlx5e_channels new_channels = {}; | |
472a1e44 | 434 | struct mlx5e_params *params; |
807c4415 ES |
435 | int err = 0; |
436 | ||
437 | mutex_lock(&priv->state_lock); | |
438 | ||
472a1e44 | 439 | params = &priv->channels.params; |
807c4415 | 440 | |
472a1e44 TT |
441 | if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) { |
442 | params->sw_mtu = new_mtu; | |
443 | netdev->mtu = params->sw_mtu; | |
807c4415 | 444 | goto out; |
472a1e44 | 445 | } |
807c4415 | 446 | |
472a1e44 TT |
447 | new_channels.params = *params; |
448 | new_channels.params.sw_mtu = new_mtu; | |
807c4415 | 449 | err = mlx5e_open_channels(priv, &new_channels); |
472a1e44 | 450 | if (err) |
807c4415 | 451 | goto out; |
807c4415 ES |
452 | |
453 | mlx5e_switch_priv_channels(priv, &new_channels, NULL); | |
472a1e44 | 454 | netdev->mtu = new_channels.params.sw_mtu; |
807c4415 ES |
455 | |
456 | out: | |
457 | mutex_unlock(&priv->state_lock); | |
458 | return err; | |
459 | } | |
460 | ||
af98cebc | 461 | int mlx5i_dev_init(struct net_device *dev) |
603f4a45 SM |
462 | { |
463 | struct mlx5e_priv *priv = mlx5i_epriv(dev); | |
464 | struct mlx5i_priv *ipriv = priv->ppriv; | |
465 | ||
466 | /* Set dev address using underlay QP */ | |
467 | dev->dev_addr[1] = (ipriv->qp.qpn >> 16) & 0xff; | |
468 | dev->dev_addr[2] = (ipriv->qp.qpn >> 8) & 0xff; | |
469 | dev->dev_addr[3] = (ipriv->qp.qpn) & 0xff; | |
470 | ||
7e7f4780 AV |
471 | /* Add QPN to net-device mapping to HT */ |
472 | mlx5i_pkey_add_qpn(dev ,ipriv->qp.qpn); | |
473 | ||
603f4a45 SM |
474 | return 0; |
475 | } | |
476 | ||
08437c57 | 477 | int mlx5i_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
1170fbd8 FD |
478 | { |
479 | struct mlx5e_priv *priv = mlx5i_epriv(dev); | |
480 | ||
481 | switch (cmd) { | |
482 | case SIOCSHWTSTAMP: | |
483 | return mlx5e_hwstamp_set(priv, ifr); | |
484 | case SIOCGHWTSTAMP: | |
485 | return mlx5e_hwstamp_get(priv, ifr); | |
486 | default: | |
487 | return -EOPNOTSUPP; | |
488 | } | |
489 | } | |
490 | ||
af98cebc | 491 | void mlx5i_dev_cleanup(struct net_device *dev) |
603f4a45 | 492 | { |
ec8fd927 | 493 | struct mlx5e_priv *priv = mlx5i_epriv(dev); |
7e7f4780 | 494 | struct mlx5i_priv *ipriv = priv->ppriv; |
ec8fd927 | 495 | |
c8249eda | 496 | mlx5i_uninit_underlay_qp(priv); |
7e7f4780 AV |
497 | |
498 | /* Delete QPN to net-device mapping from HT */ | |
499 | mlx5i_pkey_del_qpn(dev, ipriv->qp.qpn); | |
603f4a45 SM |
500 | } |
501 | ||
502 | static int mlx5i_open(struct net_device *netdev) | |
503 | { | |
dae37456 AV |
504 | struct mlx5e_priv *epriv = mlx5i_epriv(netdev); |
505 | struct mlx5i_priv *ipriv = epriv->ppriv; | |
506 | struct mlx5_core_dev *mdev = epriv->mdev; | |
603f4a45 SM |
507 | int err; |
508 | ||
dae37456 | 509 | mutex_lock(&epriv->state_lock); |
603f4a45 | 510 | |
dae37456 | 511 | set_bit(MLX5E_STATE_OPENED, &epriv->state); |
603f4a45 | 512 | |
dae37456 AV |
513 | err = mlx5i_init_underlay_qp(epriv); |
514 | if (err) { | |
515 | mlx5_core_warn(mdev, "prepare underlay qp state failed, %d\n", err); | |
603f4a45 | 516 | goto err_clear_state_opened_flag; |
dae37456 AV |
517 | } |
518 | ||
519 | err = mlx5_fs_add_rx_underlay_qpn(mdev, ipriv->qp.qpn); | |
520 | if (err) { | |
521 | mlx5_core_warn(mdev, "attach underlay qp to ft failed, %d\n", err); | |
522 | goto err_reset_qp; | |
523 | } | |
603f4a45 | 524 | |
dae37456 AV |
525 | err = mlx5e_open_channels(epriv, &epriv->channels); |
526 | if (err) | |
527 | goto err_remove_fs_underlay_qp; | |
7ca42c80 | 528 | |
dae37456 AV |
529 | mlx5e_refresh_tirs(epriv, false); |
530 | mlx5e_activate_priv_channels(epriv); | |
dae37456 AV |
531 | |
532 | mutex_unlock(&epriv->state_lock); | |
603f4a45 SM |
533 | return 0; |
534 | ||
dae37456 AV |
535 | err_remove_fs_underlay_qp: |
536 | mlx5_fs_remove_rx_underlay_qpn(mdev, ipriv->qp.qpn); | |
537 | err_reset_qp: | |
538 | mlx5i_uninit_underlay_qp(epriv); | |
603f4a45 | 539 | err_clear_state_opened_flag: |
dae37456 AV |
540 | clear_bit(MLX5E_STATE_OPENED, &epriv->state); |
541 | mutex_unlock(&epriv->state_lock); | |
603f4a45 SM |
542 | return err; |
543 | } | |
544 | ||
545 | static int mlx5i_close(struct net_device *netdev) | |
546 | { | |
dae37456 AV |
547 | struct mlx5e_priv *epriv = mlx5i_epriv(netdev); |
548 | struct mlx5i_priv *ipriv = epriv->ppriv; | |
549 | struct mlx5_core_dev *mdev = epriv->mdev; | |
603f4a45 SM |
550 | |
551 | /* May already be CLOSED in case a previous configuration operation | |
552 | * (e.g RX/TX queue size change) that involves close&open failed. | |
553 | */ | |
dae37456 | 554 | mutex_lock(&epriv->state_lock); |
603f4a45 | 555 | |
dae37456 | 556 | if (!test_bit(MLX5E_STATE_OPENED, &epriv->state)) |
603f4a45 SM |
557 | goto unlock; |
558 | ||
dae37456 | 559 | clear_bit(MLX5E_STATE_OPENED, &epriv->state); |
603f4a45 | 560 | |
dae37456 AV |
561 | netif_carrier_off(epriv->netdev); |
562 | mlx5_fs_remove_rx_underlay_qpn(mdev, ipriv->qp.qpn); | |
dae37456 | 563 | mlx5e_deactivate_priv_channels(epriv); |
4c5386ba | 564 | mlx5e_close_channels(&epriv->channels); |
acf3766b | 565 | mlx5i_uninit_underlay_qp(epriv); |
603f4a45 | 566 | unlock: |
dae37456 | 567 | mutex_unlock(&epriv->state_lock); |
603f4a45 SM |
568 | return 0; |
569 | } | |
570 | ||
48935bbb | 571 | /* IPoIB RDMA netdev callbacks */ |
a7082ef0 | 572 | static int mlx5i_attach_mcast(struct net_device *netdev, struct ib_device *hca, |
693dfd5a ES |
573 | union ib_gid *gid, u16 lid, int set_qkey, |
574 | u32 qkey) | |
ec8fd927 SM |
575 | { |
576 | struct mlx5e_priv *epriv = mlx5i_epriv(netdev); | |
577 | struct mlx5_core_dev *mdev = epriv->mdev; | |
578 | struct mlx5i_priv *ipriv = epriv->ppriv; | |
579 | int err; | |
580 | ||
581 | mlx5_core_dbg(mdev, "attaching QPN 0x%x, MGID %pI6\n", ipriv->qp.qpn, gid->raw); | |
582 | err = mlx5_core_attach_mcg(mdev, gid, ipriv->qp.qpn); | |
583 | if (err) | |
584 | mlx5_core_warn(mdev, "failed attaching QPN 0x%x, MGID %pI6\n", | |
585 | ipriv->qp.qpn, gid->raw); | |
586 | ||
693dfd5a ES |
587 | if (set_qkey) { |
588 | mlx5_core_dbg(mdev, "%s setting qkey 0x%x\n", | |
589 | netdev->name, qkey); | |
590 | ipriv->qkey = qkey; | |
591 | } | |
592 | ||
ec8fd927 SM |
593 | return err; |
594 | } | |
595 | ||
a7082ef0 SH |
596 | static int mlx5i_detach_mcast(struct net_device *netdev, struct ib_device *hca, |
597 | union ib_gid *gid, u16 lid) | |
ec8fd927 SM |
598 | { |
599 | struct mlx5e_priv *epriv = mlx5i_epriv(netdev); | |
600 | struct mlx5_core_dev *mdev = epriv->mdev; | |
601 | struct mlx5i_priv *ipriv = epriv->ppriv; | |
602 | int err; | |
603 | ||
604 | mlx5_core_dbg(mdev, "detaching QPN 0x%x, MGID %pI6\n", ipriv->qp.qpn, gid->raw); | |
605 | ||
606 | err = mlx5_core_detach_mcg(mdev, gid, ipriv->qp.qpn); | |
607 | if (err) | |
53378898 | 608 | mlx5_core_dbg(mdev, "failed detaching QPN 0x%x, MGID %pI6\n", |
ec8fd927 SM |
609 | ipriv->qp.qpn, gid->raw); |
610 | ||
611 | return err; | |
612 | } | |
48935bbb | 613 | |
a7082ef0 | 614 | static int mlx5i_xmit(struct net_device *dev, struct sk_buff *skb, |
693dfd5a | 615 | struct ib_ah *address, u32 dqpn) |
25854544 SM |
616 | { |
617 | struct mlx5e_priv *epriv = mlx5i_epriv(dev); | |
618 | struct mlx5e_txqsq *sq = epriv->txq2sq[skb_get_queue_mapping(skb)]; | |
619 | struct mlx5_ib_ah *mah = to_mah(address); | |
693dfd5a | 620 | struct mlx5i_priv *ipriv = epriv->ppriv; |
25854544 | 621 | |
693dfd5a | 622 | return mlx5i_sq_xmit(sq, skb, &mah->av, dqpn, ipriv->qkey); |
25854544 SM |
623 | } |
624 | ||
da34f1a8 AV |
625 | static void mlx5i_set_pkey_index(struct net_device *netdev, int id) |
626 | { | |
627 | struct mlx5i_priv *ipriv = netdev_priv(netdev); | |
628 | ||
629 | ipriv->pkey_index = (u16)id; | |
630 | } | |
631 | ||
48935bbb SM |
632 | static int mlx5i_check_required_hca_cap(struct mlx5_core_dev *mdev) |
633 | { | |
634 | if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_IB) | |
635 | return -EOPNOTSUPP; | |
636 | ||
637 | if (!MLX5_CAP_GEN(mdev, ipoib_enhanced_offloads)) { | |
638 | mlx5_core_warn(mdev, "IPoIB enhanced offloads are not supported\n"); | |
693dfd5a | 639 | return -EOPNOTSUPP; |
48935bbb SM |
640 | } |
641 | ||
642 | return 0; | |
643 | } | |
644 | ||
9f49a5b5 JG |
645 | static void mlx5_rdma_netdev_free(struct net_device *netdev) |
646 | { | |
647 | struct mlx5e_priv *priv = mlx5i_epriv(netdev); | |
648 | struct mlx5i_priv *ipriv = priv->ppriv; | |
649 | const struct mlx5e_profile *profile = priv->profile; | |
650 | ||
651 | mlx5e_detach_netdev(priv); | |
652 | profile->cleanup(priv); | |
9f49a5b5 JG |
653 | |
654 | if (!ipriv->sub_interface) { | |
655 | mlx5i_pkey_qpn_ht_cleanup(netdev); | |
656 | mlx5e_destroy_mdev_resources(priv->mdev); | |
657 | } | |
658 | } | |
659 | ||
f6a8a19b | 660 | static bool mlx5_is_sub_interface(struct mlx5_core_dev *mdev) |
48935bbb | 661 | { |
f6a8a19b DD |
662 | return mdev->mlx5e_res.pdn != 0; |
663 | } | |
664 | ||
665 | static const struct mlx5e_profile *mlx5_get_profile(struct mlx5_core_dev *mdev) | |
666 | { | |
667 | if (mlx5_is_sub_interface(mdev)) | |
668 | return mlx5i_pkey_get_profile(); | |
669 | return &mlx5i_nic_profile; | |
670 | } | |
671 | ||
672 | static int mlx5_rdma_setup_rn(struct ib_device *ibdev, u8 port_num, | |
673 | struct net_device *netdev, void *param) | |
674 | { | |
675 | struct mlx5_core_dev *mdev = (struct mlx5_core_dev *)param; | |
676 | const struct mlx5e_profile *prof = mlx5_get_profile(mdev); | |
48935bbb SM |
677 | struct mlx5i_priv *ipriv; |
678 | struct mlx5e_priv *epriv; | |
693dfd5a | 679 | struct rdma_netdev *rn; |
48935bbb SM |
680 | int err; |
681 | ||
48935bbb SM |
682 | ipriv = netdev_priv(netdev); |
683 | epriv = mlx5i_epriv(netdev); | |
684 | ||
f6a8a19b | 685 | ipriv->sub_interface = mlx5_is_sub_interface(mdev); |
b5ae5777 AV |
686 | if (!ipriv->sub_interface) { |
687 | err = mlx5i_pkey_qpn_ht_init(netdev); | |
688 | if (err) { | |
689 | mlx5_core_warn(mdev, "allocate qpn_to_netdev ht failed\n"); | |
182570b2 | 690 | return err; |
b5ae5777 AV |
691 | } |
692 | ||
693 | /* This should only be called once per mdev */ | |
694 | err = mlx5e_create_mdev_resources(mdev); | |
695 | if (err) | |
696 | goto destroy_ht; | |
7e7f4780 AV |
697 | } |
698 | ||
f6a8a19b | 699 | prof->init(mdev, netdev, prof, ipriv); |
48935bbb SM |
700 | |
701 | mlx5e_attach_netdev(epriv); | |
702 | netif_carrier_off(netdev); | |
703 | ||
693dfd5a ES |
704 | /* set rdma_netdev func pointers */ |
705 | rn = &ipriv->rn; | |
706 | rn->hca = ibdev; | |
707 | rn->send = mlx5i_xmit; | |
708 | rn->attach_mcast = mlx5i_attach_mcast; | |
709 | rn->detach_mcast = mlx5i_detach_mcast; | |
da34f1a8 | 710 | rn->set_id = mlx5i_set_pkey_index; |
693dfd5a | 711 | |
9f49a5b5 JG |
712 | netdev->priv_destructor = mlx5_rdma_netdev_free; |
713 | netdev->needs_free_netdev = 1; | |
714 | ||
f6a8a19b | 715 | return 0; |
48935bbb | 716 | |
b5ae5777 AV |
717 | destroy_ht: |
718 | mlx5i_pkey_qpn_ht_cleanup(netdev); | |
f6a8a19b DD |
719 | return err; |
720 | } | |
721 | ||
722 | int mlx5_rdma_rn_get_params(struct mlx5_core_dev *mdev, | |
723 | struct ib_device *device, | |
724 | struct rdma_netdev_alloc_params *params) | |
725 | { | |
726 | int nch; | |
727 | int rc; | |
728 | ||
729 | rc = mlx5i_check_required_hca_cap(mdev); | |
730 | if (rc) | |
731 | return rc; | |
6905e5a5 | 732 | |
779d986d | 733 | nch = mlx5e_get_max_num_channels(mdev); |
f6a8a19b DD |
734 | |
735 | *params = (struct rdma_netdev_alloc_params){ | |
736 | .sizeof_priv = sizeof(struct mlx5i_priv) + | |
737 | sizeof(struct mlx5e_priv), | |
738 | .txqs = nch * MLX5E_MAX_NUM_TC, | |
739 | .rxqs = nch, | |
740 | .param = mdev, | |
741 | .initialize_rdma_netdev = mlx5_rdma_setup_rn, | |
742 | }; | |
743 | ||
744 | return 0; | |
48935bbb | 745 | } |
f6a8a19b | 746 | EXPORT_SYMBOL(mlx5_rdma_rn_get_params); |