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