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