2 * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
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:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
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.
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
33 #include <linux/netdevice.h>
34 #include <linux/mlx5/driver.h>
35 #include <linux/mlx5/vport.h>
36 #include "mlx5_core.h"
41 /* General purpose, use for short periods of time.
42 * Beware of lock dependencies (preferably, no locks should be acquired
45 static DEFINE_MUTEX(lag_mutex
);
47 static int mlx5_cmd_create_lag(struct mlx5_core_dev
*dev
, u8 remap_port1
,
50 u32 in
[MLX5_ST_SZ_DW(create_lag_in
)] = {0};
51 u32 out
[MLX5_ST_SZ_DW(create_lag_out
)] = {0};
52 void *lag_ctx
= MLX5_ADDR_OF(create_lag_in
, in
, ctx
);
54 MLX5_SET(create_lag_in
, in
, opcode
, MLX5_CMD_OP_CREATE_LAG
);
56 MLX5_SET(lagc
, lag_ctx
, tx_remap_affinity_1
, remap_port1
);
57 MLX5_SET(lagc
, lag_ctx
, tx_remap_affinity_2
, remap_port2
);
59 return mlx5_cmd_exec(dev
, in
, sizeof(in
), out
, sizeof(out
));
62 static int mlx5_cmd_modify_lag(struct mlx5_core_dev
*dev
, u8 remap_port1
,
65 u32 in
[MLX5_ST_SZ_DW(modify_lag_in
)] = {0};
66 u32 out
[MLX5_ST_SZ_DW(modify_lag_out
)] = {0};
67 void *lag_ctx
= MLX5_ADDR_OF(modify_lag_in
, in
, ctx
);
69 MLX5_SET(modify_lag_in
, in
, opcode
, MLX5_CMD_OP_MODIFY_LAG
);
70 MLX5_SET(modify_lag_in
, in
, field_select
, 0x1);
72 MLX5_SET(lagc
, lag_ctx
, tx_remap_affinity_1
, remap_port1
);
73 MLX5_SET(lagc
, lag_ctx
, tx_remap_affinity_2
, remap_port2
);
75 return mlx5_cmd_exec(dev
, in
, sizeof(in
), out
, sizeof(out
));
78 static int mlx5_cmd_destroy_lag(struct mlx5_core_dev
*dev
)
80 u32 in
[MLX5_ST_SZ_DW(destroy_lag_in
)] = {0};
81 u32 out
[MLX5_ST_SZ_DW(destroy_lag_out
)] = {0};
83 MLX5_SET(destroy_lag_in
, in
, opcode
, MLX5_CMD_OP_DESTROY_LAG
);
85 return mlx5_cmd_exec(dev
, in
, sizeof(in
), out
, sizeof(out
));
88 int mlx5_cmd_create_vport_lag(struct mlx5_core_dev
*dev
)
90 u32 in
[MLX5_ST_SZ_DW(create_vport_lag_in
)] = {0};
91 u32 out
[MLX5_ST_SZ_DW(create_vport_lag_out
)] = {0};
93 MLX5_SET(create_vport_lag_in
, in
, opcode
, MLX5_CMD_OP_CREATE_VPORT_LAG
);
95 return mlx5_cmd_exec(dev
, in
, sizeof(in
), out
, sizeof(out
));
97 EXPORT_SYMBOL(mlx5_cmd_create_vport_lag
);
99 int mlx5_cmd_destroy_vport_lag(struct mlx5_core_dev
*dev
)
101 u32 in
[MLX5_ST_SZ_DW(destroy_vport_lag_in
)] = {0};
102 u32 out
[MLX5_ST_SZ_DW(destroy_vport_lag_out
)] = {0};
104 MLX5_SET(destroy_vport_lag_in
, in
, opcode
, MLX5_CMD_OP_DESTROY_VPORT_LAG
);
106 return mlx5_cmd_exec(dev
, in
, sizeof(in
), out
, sizeof(out
));
108 EXPORT_SYMBOL(mlx5_cmd_destroy_vport_lag
);
110 static int mlx5_cmd_query_cong_counter(struct mlx5_core_dev
*dev
,
111 bool reset
, void *out
, int out_size
)
113 u32 in
[MLX5_ST_SZ_DW(query_cong_statistics_in
)] = { };
115 MLX5_SET(query_cong_statistics_in
, in
, opcode
,
116 MLX5_CMD_OP_QUERY_CONG_STATISTICS
);
117 MLX5_SET(query_cong_statistics_in
, in
, clear
, reset
);
118 return mlx5_cmd_exec(dev
, in
, sizeof(in
), out
, out_size
);
121 int mlx5_lag_dev_get_netdev_idx(struct mlx5_lag
*ldev
,
122 struct net_device
*ndev
)
126 for (i
= 0; i
< MLX5_MAX_PORTS
; i
++)
127 if (ldev
->pf
[i
].netdev
== ndev
)
133 static bool __mlx5_lag_is_roce(struct mlx5_lag
*ldev
)
135 return !!(ldev
->flags
& MLX5_LAG_FLAG_ROCE
);
138 static bool __mlx5_lag_is_sriov(struct mlx5_lag
*ldev
)
140 return !!(ldev
->flags
& MLX5_LAG_FLAG_SRIOV
);
143 static void mlx5_infer_tx_affinity_mapping(struct lag_tracker
*tracker
,
144 u8
*port1
, u8
*port2
)
148 if (!tracker
->netdev_state
[MLX5_LAG_P1
].tx_enabled
||
149 !tracker
->netdev_state
[MLX5_LAG_P1
].link_up
) {
154 if (!tracker
->netdev_state
[MLX5_LAG_P2
].tx_enabled
||
155 !tracker
->netdev_state
[MLX5_LAG_P2
].link_up
)
159 void mlx5_modify_lag(struct mlx5_lag
*ldev
,
160 struct lag_tracker
*tracker
)
162 struct mlx5_core_dev
*dev0
= ldev
->pf
[MLX5_LAG_P1
].dev
;
163 u8 v2p_port1
, v2p_port2
;
166 mlx5_infer_tx_affinity_mapping(tracker
, &v2p_port1
,
169 if (v2p_port1
!= ldev
->v2p_map
[MLX5_LAG_P1
] ||
170 v2p_port2
!= ldev
->v2p_map
[MLX5_LAG_P2
]) {
171 ldev
->v2p_map
[MLX5_LAG_P1
] = v2p_port1
;
172 ldev
->v2p_map
[MLX5_LAG_P2
] = v2p_port2
;
174 mlx5_core_info(dev0
, "modify lag map port 1:%d port 2:%d",
175 ldev
->v2p_map
[MLX5_LAG_P1
],
176 ldev
->v2p_map
[MLX5_LAG_P2
]);
178 err
= mlx5_cmd_modify_lag(dev0
, v2p_port1
, v2p_port2
);
181 "Failed to modify LAG (%d)\n",
186 static int mlx5_create_lag(struct mlx5_lag
*ldev
,
187 struct lag_tracker
*tracker
)
189 struct mlx5_core_dev
*dev0
= ldev
->pf
[MLX5_LAG_P1
].dev
;
192 mlx5_infer_tx_affinity_mapping(tracker
, &ldev
->v2p_map
[MLX5_LAG_P1
],
193 &ldev
->v2p_map
[MLX5_LAG_P2
]);
195 mlx5_core_info(dev0
, "lag map port 1:%d port 2:%d",
196 ldev
->v2p_map
[MLX5_LAG_P1
], ldev
->v2p_map
[MLX5_LAG_P2
]);
198 err
= mlx5_cmd_create_lag(dev0
, ldev
->v2p_map
[MLX5_LAG_P1
],
199 ldev
->v2p_map
[MLX5_LAG_P2
]);
202 "Failed to create LAG (%d)\n",
207 int mlx5_activate_lag(struct mlx5_lag
*ldev
,
208 struct lag_tracker
*tracker
,
211 bool roce_lag
= !!(flags
& MLX5_LAG_FLAG_ROCE
);
212 struct mlx5_core_dev
*dev0
= ldev
->pf
[MLX5_LAG_P1
].dev
;
215 err
= mlx5_create_lag(ldev
, tracker
);
219 "Failed to activate RoCE LAG\n");
222 "Failed to activate VF LAG\n"
223 "Make sure all VFs are unbound prior to VF LAG activation or deactivation\n");
228 ldev
->flags
|= flags
;
232 static int mlx5_deactivate_lag(struct mlx5_lag
*ldev
)
234 struct mlx5_core_dev
*dev0
= ldev
->pf
[MLX5_LAG_P1
].dev
;
235 bool roce_lag
= __mlx5_lag_is_roce(ldev
);
238 ldev
->flags
&= ~MLX5_LAG_MODE_FLAGS
;
240 err
= mlx5_cmd_destroy_lag(dev0
);
244 "Failed to deactivate RoCE LAG; driver restart required\n");
247 "Failed to deactivate VF LAG; driver restart required\n"
248 "Make sure all VFs are unbound prior to VF LAG activation or deactivation\n");
255 static bool mlx5_lag_check_prereq(struct mlx5_lag
*ldev
)
257 if (!ldev
->pf
[MLX5_LAG_P1
].dev
|| !ldev
->pf
[MLX5_LAG_P2
].dev
)
260 #ifdef CONFIG_MLX5_ESWITCH
261 return mlx5_esw_lag_prereq(ldev
->pf
[MLX5_LAG_P1
].dev
,
262 ldev
->pf
[MLX5_LAG_P2
].dev
);
264 return (!mlx5_sriov_is_enabled(ldev
->pf
[MLX5_LAG_P1
].dev
) &&
265 !mlx5_sriov_is_enabled(ldev
->pf
[MLX5_LAG_P2
].dev
));
269 static void mlx5_lag_add_ib_devices(struct mlx5_lag
*ldev
)
273 for (i
= 0; i
< MLX5_MAX_PORTS
; i
++)
275 mlx5_add_dev_by_protocol(ldev
->pf
[i
].dev
,
276 MLX5_INTERFACE_PROTOCOL_IB
);
279 static void mlx5_lag_remove_ib_devices(struct mlx5_lag
*ldev
)
283 for (i
= 0; i
< MLX5_MAX_PORTS
; i
++)
285 mlx5_remove_dev_by_protocol(ldev
->pf
[i
].dev
,
286 MLX5_INTERFACE_PROTOCOL_IB
);
289 static void mlx5_do_bond(struct mlx5_lag
*ldev
)
291 struct mlx5_core_dev
*dev0
= ldev
->pf
[MLX5_LAG_P1
].dev
;
292 struct mlx5_core_dev
*dev1
= ldev
->pf
[MLX5_LAG_P2
].dev
;
293 struct lag_tracker tracker
;
294 bool do_bond
, roce_lag
;
300 mutex_lock(&lag_mutex
);
301 tracker
= ldev
->tracker
;
302 mutex_unlock(&lag_mutex
);
304 do_bond
= tracker
.is_bonded
&& mlx5_lag_check_prereq(ldev
);
306 if (do_bond
&& !__mlx5_lag_is_active(ldev
)) {
307 roce_lag
= !mlx5_sriov_is_enabled(dev0
) &&
308 !mlx5_sriov_is_enabled(dev1
);
310 #ifdef CONFIG_MLX5_ESWITCH
311 roce_lag
&= dev0
->priv
.eswitch
->mode
== MLX5_ESWITCH_NONE
&&
312 dev1
->priv
.eswitch
->mode
== MLX5_ESWITCH_NONE
;
316 mlx5_lag_remove_ib_devices(ldev
);
318 err
= mlx5_activate_lag(ldev
, &tracker
,
319 roce_lag
? MLX5_LAG_FLAG_ROCE
:
320 MLX5_LAG_FLAG_SRIOV
);
323 mlx5_lag_add_ib_devices(ldev
);
329 mlx5_add_dev_by_protocol(dev0
, MLX5_INTERFACE_PROTOCOL_IB
);
330 mlx5_nic_vport_enable_roce(dev1
);
332 } else if (do_bond
&& __mlx5_lag_is_active(ldev
)) {
333 mlx5_modify_lag(ldev
, &tracker
);
334 } else if (!do_bond
&& __mlx5_lag_is_active(ldev
)) {
335 roce_lag
= __mlx5_lag_is_roce(ldev
);
338 mlx5_remove_dev_by_protocol(dev0
, MLX5_INTERFACE_PROTOCOL_IB
);
339 mlx5_nic_vport_disable_roce(dev1
);
342 err
= mlx5_deactivate_lag(ldev
);
347 mlx5_lag_add_ib_devices(ldev
);
351 static void mlx5_queue_bond_work(struct mlx5_lag
*ldev
, unsigned long delay
)
353 queue_delayed_work(ldev
->wq
, &ldev
->bond_work
, delay
);
356 static void mlx5_do_bond_work(struct work_struct
*work
)
358 struct delayed_work
*delayed_work
= to_delayed_work(work
);
359 struct mlx5_lag
*ldev
= container_of(delayed_work
, struct mlx5_lag
,
363 status
= mlx5_dev_list_trylock();
366 mlx5_queue_bond_work(ldev
, HZ
);
371 mlx5_dev_list_unlock();
374 static int mlx5_handle_changeupper_event(struct mlx5_lag
*ldev
,
375 struct lag_tracker
*tracker
,
376 struct net_device
*ndev
,
377 struct netdev_notifier_changeupper_info
*info
)
379 struct net_device
*upper
= info
->upper_dev
, *ndev_tmp
;
380 struct netdev_lag_upper_info
*lag_upper_info
= NULL
;
386 if (!netif_is_lag_master(upper
))
390 lag_upper_info
= info
->upper_info
;
392 /* The event may still be of interest if the slave does not belong to
393 * us, but is enslaved to a master which has one or more of our netdevs
394 * as slaves (e.g., if a new slave is added to a master that bonds two
395 * of our netdevs, we should unbond).
398 for_each_netdev_in_bond_rcu(upper
, ndev_tmp
) {
399 idx
= mlx5_lag_dev_get_netdev_idx(ldev
, ndev_tmp
);
401 bond_status
|= (1 << idx
);
407 /* None of this lagdev's netdevs are slaves of this master. */
408 if (!(bond_status
& 0x3))
412 tracker
->tx_type
= lag_upper_info
->tx_type
;
414 /* Determine bonding status:
415 * A device is considered bonded if both its physical ports are slaves
416 * of the same lag master, and only them.
417 * Lag mode must be activebackup or hash.
419 is_bonded
= (num_slaves
== MLX5_MAX_PORTS
) &&
420 (bond_status
== 0x3) &&
421 ((tracker
->tx_type
== NETDEV_LAG_TX_TYPE_ACTIVEBACKUP
) ||
422 (tracker
->tx_type
== NETDEV_LAG_TX_TYPE_HASH
));
424 if (tracker
->is_bonded
!= is_bonded
) {
425 tracker
->is_bonded
= is_bonded
;
432 static int mlx5_handle_changelowerstate_event(struct mlx5_lag
*ldev
,
433 struct lag_tracker
*tracker
,
434 struct net_device
*ndev
,
435 struct netdev_notifier_changelowerstate_info
*info
)
437 struct netdev_lag_lower_state_info
*lag_lower_info
;
440 if (!netif_is_lag_port(ndev
))
443 idx
= mlx5_lag_dev_get_netdev_idx(ldev
, ndev
);
447 /* This information is used to determine virtual to physical
450 lag_lower_info
= info
->lower_state_info
;
454 tracker
->netdev_state
[idx
] = *lag_lower_info
;
459 static int mlx5_lag_netdev_event(struct notifier_block
*this,
460 unsigned long event
, void *ptr
)
462 struct net_device
*ndev
= netdev_notifier_info_to_dev(ptr
);
463 struct lag_tracker tracker
;
464 struct mlx5_lag
*ldev
;
467 if (!net_eq(dev_net(ndev
), &init_net
))
470 if ((event
!= NETDEV_CHANGEUPPER
) && (event
!= NETDEV_CHANGELOWERSTATE
))
473 ldev
= container_of(this, struct mlx5_lag
, nb
);
474 tracker
= ldev
->tracker
;
477 case NETDEV_CHANGEUPPER
:
478 changed
= mlx5_handle_changeupper_event(ldev
, &tracker
, ndev
,
481 case NETDEV_CHANGELOWERSTATE
:
482 changed
= mlx5_handle_changelowerstate_event(ldev
, &tracker
,
487 mutex_lock(&lag_mutex
);
488 ldev
->tracker
= tracker
;
489 mutex_unlock(&lag_mutex
);
492 mlx5_queue_bond_work(ldev
, 0);
497 static struct mlx5_lag
*mlx5_lag_dev_alloc(void)
499 struct mlx5_lag
*ldev
;
501 ldev
= kzalloc(sizeof(*ldev
), GFP_KERNEL
);
505 ldev
->wq
= create_singlethread_workqueue("mlx5_lag");
511 INIT_DELAYED_WORK(&ldev
->bond_work
, mlx5_do_bond_work
);
516 static void mlx5_lag_dev_free(struct mlx5_lag
*ldev
)
518 destroy_workqueue(ldev
->wq
);
522 static void mlx5_lag_dev_add_pf(struct mlx5_lag
*ldev
,
523 struct mlx5_core_dev
*dev
,
524 struct net_device
*netdev
)
526 unsigned int fn
= PCI_FUNC(dev
->pdev
->devfn
);
528 if (fn
>= MLX5_MAX_PORTS
)
531 mutex_lock(&lag_mutex
);
532 ldev
->pf
[fn
].dev
= dev
;
533 ldev
->pf
[fn
].netdev
= netdev
;
534 ldev
->tracker
.netdev_state
[fn
].link_up
= 0;
535 ldev
->tracker
.netdev_state
[fn
].tx_enabled
= 0;
537 dev
->priv
.lag
= ldev
;
539 mutex_unlock(&lag_mutex
);
542 static void mlx5_lag_dev_remove_pf(struct mlx5_lag
*ldev
,
543 struct mlx5_core_dev
*dev
)
547 for (i
= 0; i
< MLX5_MAX_PORTS
; i
++)
548 if (ldev
->pf
[i
].dev
== dev
)
551 if (i
== MLX5_MAX_PORTS
)
554 mutex_lock(&lag_mutex
);
555 memset(&ldev
->pf
[i
], 0, sizeof(*ldev
->pf
));
557 dev
->priv
.lag
= NULL
;
558 mutex_unlock(&lag_mutex
);
561 /* Must be called with intf_mutex held */
562 void mlx5_lag_add(struct mlx5_core_dev
*dev
, struct net_device
*netdev
)
564 struct mlx5_lag
*ldev
= NULL
;
565 struct mlx5_core_dev
*tmp_dev
;
568 if (!MLX5_CAP_GEN(dev
, vport_group_manager
) ||
569 !MLX5_CAP_GEN(dev
, lag_master
) ||
570 (MLX5_CAP_GEN(dev
, num_lag_ports
) != MLX5_MAX_PORTS
))
573 tmp_dev
= mlx5_get_next_phys_dev(dev
);
575 ldev
= tmp_dev
->priv
.lag
;
578 ldev
= mlx5_lag_dev_alloc();
580 mlx5_core_err(dev
, "Failed to alloc lag dev\n");
585 mlx5_lag_dev_add_pf(ldev
, dev
, netdev
);
587 if (!ldev
->nb
.notifier_call
) {
588 ldev
->nb
.notifier_call
= mlx5_lag_netdev_event
;
589 if (register_netdevice_notifier(&ldev
->nb
)) {
590 ldev
->nb
.notifier_call
= NULL
;
591 mlx5_core_err(dev
, "Failed to register LAG netdev notifier\n");
595 err
= mlx5_lag_mp_init(ldev
);
597 mlx5_core_err(dev
, "Failed to init multipath lag err=%d\n",
601 /* Must be called with intf_mutex held */
602 void mlx5_lag_remove(struct mlx5_core_dev
*dev
)
604 struct mlx5_lag
*ldev
;
607 ldev
= mlx5_lag_dev_get(dev
);
611 if (__mlx5_lag_is_active(ldev
))
612 mlx5_deactivate_lag(ldev
);
614 mlx5_lag_dev_remove_pf(ldev
, dev
);
616 for (i
= 0; i
< MLX5_MAX_PORTS
; i
++)
620 if (i
== MLX5_MAX_PORTS
) {
621 if (ldev
->nb
.notifier_call
)
622 unregister_netdevice_notifier(&ldev
->nb
);
623 mlx5_lag_mp_cleanup(ldev
);
624 cancel_delayed_work_sync(&ldev
->bond_work
);
625 mlx5_lag_dev_free(ldev
);
629 bool mlx5_lag_is_roce(struct mlx5_core_dev
*dev
)
631 struct mlx5_lag
*ldev
;
634 mutex_lock(&lag_mutex
);
635 ldev
= mlx5_lag_dev_get(dev
);
636 res
= ldev
&& __mlx5_lag_is_roce(ldev
);
637 mutex_unlock(&lag_mutex
);
641 EXPORT_SYMBOL(mlx5_lag_is_roce
);
643 bool mlx5_lag_is_active(struct mlx5_core_dev
*dev
)
645 struct mlx5_lag
*ldev
;
648 mutex_lock(&lag_mutex
);
649 ldev
= mlx5_lag_dev_get(dev
);
650 res
= ldev
&& __mlx5_lag_is_active(ldev
);
651 mutex_unlock(&lag_mutex
);
655 EXPORT_SYMBOL(mlx5_lag_is_active
);
657 bool mlx5_lag_is_sriov(struct mlx5_core_dev
*dev
)
659 struct mlx5_lag
*ldev
;
662 mutex_lock(&lag_mutex
);
663 ldev
= mlx5_lag_dev_get(dev
);
664 res
= ldev
&& __mlx5_lag_is_sriov(ldev
);
665 mutex_unlock(&lag_mutex
);
669 EXPORT_SYMBOL(mlx5_lag_is_sriov
);
671 void mlx5_lag_update(struct mlx5_core_dev
*dev
)
673 struct mlx5_lag
*ldev
;
675 mlx5_dev_list_lock();
676 ldev
= mlx5_lag_dev_get(dev
);
683 mlx5_dev_list_unlock();
686 struct net_device
*mlx5_lag_get_roce_netdev(struct mlx5_core_dev
*dev
)
688 struct net_device
*ndev
= NULL
;
689 struct mlx5_lag
*ldev
;
691 mutex_lock(&lag_mutex
);
692 ldev
= mlx5_lag_dev_get(dev
);
694 if (!(ldev
&& __mlx5_lag_is_roce(ldev
)))
697 if (ldev
->tracker
.tx_type
== NETDEV_LAG_TX_TYPE_ACTIVEBACKUP
) {
698 ndev
= ldev
->tracker
.netdev_state
[MLX5_LAG_P1
].tx_enabled
?
699 ldev
->pf
[MLX5_LAG_P1
].netdev
:
700 ldev
->pf
[MLX5_LAG_P2
].netdev
;
702 ndev
= ldev
->pf
[MLX5_LAG_P1
].netdev
;
708 mutex_unlock(&lag_mutex
);
712 EXPORT_SYMBOL(mlx5_lag_get_roce_netdev
);
714 bool mlx5_lag_intf_add(struct mlx5_interface
*intf
, struct mlx5_priv
*priv
)
716 struct mlx5_core_dev
*dev
= container_of(priv
, struct mlx5_core_dev
,
718 struct mlx5_lag
*ldev
;
720 if (intf
->protocol
!= MLX5_INTERFACE_PROTOCOL_IB
)
723 ldev
= mlx5_lag_dev_get(dev
);
724 if (!ldev
|| !__mlx5_lag_is_roce(ldev
) ||
725 ldev
->pf
[MLX5_LAG_P1
].dev
== dev
)
728 /* If bonded, we do not add an IB device for PF1. */
732 int mlx5_lag_query_cong_counters(struct mlx5_core_dev
*dev
,
737 int outlen
= MLX5_ST_SZ_BYTES(query_cong_statistics_out
);
738 struct mlx5_core_dev
*mdev
[MLX5_MAX_PORTS
];
739 struct mlx5_lag
*ldev
;
744 out
= kvzalloc(outlen
, GFP_KERNEL
);
748 memset(values
, 0, sizeof(*values
) * num_counters
);
750 mutex_lock(&lag_mutex
);
751 ldev
= mlx5_lag_dev_get(dev
);
752 if (ldev
&& __mlx5_lag_is_roce(ldev
)) {
753 num_ports
= MLX5_MAX_PORTS
;
754 mdev
[MLX5_LAG_P1
] = ldev
->pf
[MLX5_LAG_P1
].dev
;
755 mdev
[MLX5_LAG_P2
] = ldev
->pf
[MLX5_LAG_P2
].dev
;
758 mdev
[MLX5_LAG_P1
] = dev
;
761 for (i
= 0; i
< num_ports
; ++i
) {
762 ret
= mlx5_cmd_query_cong_counter(mdev
[i
], false, out
, outlen
);
766 for (j
= 0; j
< num_counters
; ++j
)
767 values
[j
] += be64_to_cpup((__be64
*)(out
+ offsets
[j
]));
771 mutex_unlock(&lag_mutex
);
775 EXPORT_SYMBOL(mlx5_lag_query_cong_counters
);