1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3 
4 #include "lag.h"
5 
6 static char *get_str_mode_type(struct mlx5_lag *ldev)
7 {
8 	if (ldev->flags & MLX5_LAG_FLAG_ROCE)
9 		return "roce";
10 	if (ldev->flags & MLX5_LAG_FLAG_SRIOV)
11 		return "switchdev";
12 	if (ldev->flags & MLX5_LAG_FLAG_MULTIPATH)
13 		return "multipath";
14 
15 	return NULL;
16 }
17 
18 static int type_show(struct seq_file *file, void *priv)
19 {
20 	struct mlx5_core_dev *dev = file->private;
21 	struct mlx5_lag *ldev;
22 	char *mode = NULL;
23 
24 	ldev = dev->priv.lag;
25 	mutex_lock(&ldev->lock);
26 	if (__mlx5_lag_is_active(ldev))
27 		mode = get_str_mode_type(ldev);
28 	mutex_unlock(&ldev->lock);
29 	if (!mode)
30 		return -EINVAL;
31 	seq_printf(file, "%s\n", mode);
32 
33 	return 0;
34 }
35 
36 static int port_sel_mode_show(struct seq_file *file, void *priv)
37 {
38 	struct mlx5_core_dev *dev = file->private;
39 	struct mlx5_lag *ldev;
40 	int ret = 0;
41 	char *mode;
42 
43 	ldev = dev->priv.lag;
44 	mutex_lock(&ldev->lock);
45 	if (__mlx5_lag_is_active(ldev))
46 		mode = get_str_port_sel_mode(ldev->flags);
47 	else
48 		ret = -EINVAL;
49 	mutex_unlock(&ldev->lock);
50 	if (ret || !mode)
51 		return ret;
52 
53 	seq_printf(file, "%s\n", mode);
54 	return 0;
55 }
56 
57 static int state_show(struct seq_file *file, void *priv)
58 {
59 	struct mlx5_core_dev *dev = file->private;
60 	struct mlx5_lag *ldev;
61 	bool active;
62 
63 	ldev = dev->priv.lag;
64 	mutex_lock(&ldev->lock);
65 	active = __mlx5_lag_is_active(ldev);
66 	mutex_unlock(&ldev->lock);
67 	seq_printf(file, "%s\n", active ? "active" : "disabled");
68 	return 0;
69 }
70 
71 static int flags_show(struct seq_file *file, void *priv)
72 {
73 	struct mlx5_core_dev *dev = file->private;
74 	struct mlx5_lag *ldev;
75 	bool shared_fdb;
76 	bool lag_active;
77 
78 	ldev = dev->priv.lag;
79 	mutex_lock(&ldev->lock);
80 	lag_active = __mlx5_lag_is_active(ldev);
81 	if (lag_active)
82 		shared_fdb = ldev->shared_fdb;
83 
84 	mutex_unlock(&ldev->lock);
85 	if (!lag_active)
86 		return -EINVAL;
87 
88 	seq_printf(file, "%s:%s\n", "shared_fdb", shared_fdb ? "on" : "off");
89 	return 0;
90 }
91 
92 static int mapping_show(struct seq_file *file, void *priv)
93 {
94 	struct mlx5_core_dev *dev = file->private;
95 	u8 ports[MLX5_MAX_PORTS] = {};
96 	struct mlx5_lag *ldev;
97 	bool hash = false;
98 	bool lag_active;
99 	int num_ports;
100 	int i;
101 
102 	ldev = dev->priv.lag;
103 	mutex_lock(&ldev->lock);
104 	lag_active = __mlx5_lag_is_active(ldev);
105 	if (lag_active) {
106 		if (ldev->flags & MLX5_LAG_FLAG_HASH_BASED) {
107 			mlx5_infer_tx_enabled(&ldev->tracker, ldev->ports, ports,
108 					      &num_ports);
109 			hash = true;
110 		} else {
111 			for (i = 0; i < ldev->ports; i++)
112 				ports[i] = ldev->v2p_map[i];
113 			num_ports = ldev->ports;
114 		}
115 	}
116 	mutex_unlock(&ldev->lock);
117 	if (!lag_active)
118 		return -EINVAL;
119 
120 	for (i = 0; i < num_ports; i++) {
121 		if (hash)
122 			seq_printf(file, "%d\n", ports[i] + 1);
123 		else
124 			seq_printf(file, "%d:%d\n", i + 1, ports[i]);
125 	}
126 
127 	return 0;
128 }
129 
130 static int members_show(struct seq_file *file, void *priv)
131 {
132 	struct mlx5_core_dev *dev = file->private;
133 	struct mlx5_lag *ldev;
134 	int i;
135 
136 	ldev = dev->priv.lag;
137 	mutex_lock(&ldev->lock);
138 	for (i = 0; i < ldev->ports; i++) {
139 		if (!ldev->pf[i].dev)
140 			continue;
141 		seq_printf(file, "%s\n", dev_name(ldev->pf[i].dev->device));
142 	}
143 	mutex_unlock(&ldev->lock);
144 
145 	return 0;
146 }
147 
148 DEFINE_SHOW_ATTRIBUTE(type);
149 DEFINE_SHOW_ATTRIBUTE(port_sel_mode);
150 DEFINE_SHOW_ATTRIBUTE(state);
151 DEFINE_SHOW_ATTRIBUTE(flags);
152 DEFINE_SHOW_ATTRIBUTE(mapping);
153 DEFINE_SHOW_ATTRIBUTE(members);
154 
155 void mlx5_ldev_add_debugfs(struct mlx5_core_dev *dev)
156 {
157 	struct dentry *dbg;
158 
159 	dbg = debugfs_create_dir("lag", mlx5_debugfs_get_dev_root(dev));
160 	dev->priv.dbg.lag_debugfs = dbg;
161 
162 	debugfs_create_file("type", 0444, dbg, dev, &type_fops);
163 	debugfs_create_file("port_sel_mode", 0444, dbg, dev, &port_sel_mode_fops);
164 	debugfs_create_file("state", 0444, dbg, dev, &state_fops);
165 	debugfs_create_file("flags", 0444, dbg, dev, &flags_fops);
166 	debugfs_create_file("mapping", 0444, dbg, dev, &mapping_fops);
167 	debugfs_create_file("members", 0444, dbg, dev, &members_fops);
168 }
169 
170 void mlx5_ldev_remove_debugfs(struct dentry *dbg)
171 {
172 	debugfs_remove_recursive(dbg);
173 }
174