Commit | Line | Data |
---|---|---|
7f46a0b7 MB |
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 | { | |
94db3317 EC |
8 | switch (ldev->mode) { |
9 | case MLX5_LAG_MODE_ROCE: return "roce"; | |
10 | case MLX5_LAG_MODE_SRIOV: return "switchdev"; | |
11 | case MLX5_LAG_MODE_MULTIPATH: return "multipath"; | |
12 | case MLX5_LAG_MODE_MPESW: return "multiport_eswitch"; | |
13 | default: return "invalid"; | |
14 | } | |
7f46a0b7 MB |
15 | |
16 | return NULL; | |
17 | } | |
18 | ||
19 | static int type_show(struct seq_file *file, void *priv) | |
20 | { | |
21 | struct mlx5_core_dev *dev = file->private; | |
22 | struct mlx5_lag *ldev; | |
23 | char *mode = NULL; | |
24 | ||
25 | ldev = dev->priv.lag; | |
26 | mutex_lock(&ldev->lock); | |
27 | if (__mlx5_lag_is_active(ldev)) | |
28 | mode = get_str_mode_type(ldev); | |
29 | mutex_unlock(&ldev->lock); | |
30 | if (!mode) | |
31 | return -EINVAL; | |
32 | seq_printf(file, "%s\n", mode); | |
33 | ||
34 | return 0; | |
35 | } | |
36 | ||
37 | static int port_sel_mode_show(struct seq_file *file, void *priv) | |
38 | { | |
39 | struct mlx5_core_dev *dev = file->private; | |
40 | struct mlx5_lag *ldev; | |
41 | int ret = 0; | |
42 | char *mode; | |
43 | ||
44 | ldev = dev->priv.lag; | |
45 | mutex_lock(&ldev->lock); | |
46 | if (__mlx5_lag_is_active(ldev)) | |
1afbd1e2 | 47 | mode = mlx5_get_str_port_sel_mode(ldev->mode, ldev->mode_flags); |
7f46a0b7 MB |
48 | else |
49 | ret = -EINVAL; | |
50 | mutex_unlock(&ldev->lock); | |
94db3317 | 51 | if (ret) |
7f46a0b7 MB |
52 | return ret; |
53 | ||
54 | seq_printf(file, "%s\n", mode); | |
55 | return 0; | |
56 | } | |
57 | ||
58 | static int state_show(struct seq_file *file, void *priv) | |
59 | { | |
60 | struct mlx5_core_dev *dev = file->private; | |
61 | struct mlx5_lag *ldev; | |
62 | bool active; | |
63 | ||
64 | ldev = dev->priv.lag; | |
65 | mutex_lock(&ldev->lock); | |
66 | active = __mlx5_lag_is_active(ldev); | |
67 | mutex_unlock(&ldev->lock); | |
68 | seq_printf(file, "%s\n", active ? "active" : "disabled"); | |
69 | return 0; | |
70 | } | |
71 | ||
72 | static int flags_show(struct seq_file *file, void *priv) | |
73 | { | |
74 | struct mlx5_core_dev *dev = file->private; | |
4892bd98 | 75 | bool fdb_sel_mode_native; |
7f46a0b7 MB |
76 | struct mlx5_lag *ldev; |
77 | bool shared_fdb; | |
78 | bool lag_active; | |
79 | ||
80 | ldev = dev->priv.lag; | |
81 | mutex_lock(&ldev->lock); | |
82 | lag_active = __mlx5_lag_is_active(ldev); | |
4892bd98 MB |
83 | if (!lag_active) |
84 | goto unlock; | |
85 | ||
86 | shared_fdb = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &ldev->mode_flags); | |
87 | fdb_sel_mode_native = test_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE, | |
88 | &ldev->mode_flags); | |
7f46a0b7 | 89 | |
4892bd98 | 90 | unlock: |
7f46a0b7 MB |
91 | mutex_unlock(&ldev->lock); |
92 | if (!lag_active) | |
93 | return -EINVAL; | |
94 | ||
95 | seq_printf(file, "%s:%s\n", "shared_fdb", shared_fdb ? "on" : "off"); | |
4892bd98 MB |
96 | seq_printf(file, "%s:%s\n", "fdb_selection_mode", |
97 | fdb_sel_mode_native ? "native" : "affinity"); | |
7f46a0b7 MB |
98 | return 0; |
99 | } | |
100 | ||
101 | static int mapping_show(struct seq_file *file, void *priv) | |
102 | { | |
103 | struct mlx5_core_dev *dev = file->private; | |
104 | u8 ports[MLX5_MAX_PORTS] = {}; | |
105 | struct mlx5_lag *ldev; | |
106 | bool hash = false; | |
107 | bool lag_active; | |
108 | int num_ports; | |
109 | int i; | |
110 | ||
111 | ldev = dev->priv.lag; | |
112 | mutex_lock(&ldev->lock); | |
113 | lag_active = __mlx5_lag_is_active(ldev); | |
114 | if (lag_active) { | |
ef9a3a4a | 115 | if (test_bit(MLX5_LAG_MODE_FLAG_HASH_BASED, &ldev->mode_flags)) { |
7f46a0b7 MB |
116 | mlx5_infer_tx_enabled(&ldev->tracker, ldev->ports, ports, |
117 | &num_ports); | |
118 | hash = true; | |
119 | } else { | |
120 | for (i = 0; i < ldev->ports; i++) | |
121 | ports[i] = ldev->v2p_map[i]; | |
122 | num_ports = ldev->ports; | |
123 | } | |
124 | } | |
125 | mutex_unlock(&ldev->lock); | |
126 | if (!lag_active) | |
127 | return -EINVAL; | |
128 | ||
129 | for (i = 0; i < num_ports; i++) { | |
130 | if (hash) | |
131 | seq_printf(file, "%d\n", ports[i] + 1); | |
132 | else | |
133 | seq_printf(file, "%d:%d\n", i + 1, ports[i]); | |
134 | } | |
135 | ||
136 | return 0; | |
137 | } | |
138 | ||
139 | static int members_show(struct seq_file *file, void *priv) | |
140 | { | |
141 | struct mlx5_core_dev *dev = file->private; | |
142 | struct mlx5_lag *ldev; | |
143 | int i; | |
144 | ||
145 | ldev = dev->priv.lag; | |
146 | mutex_lock(&ldev->lock); | |
147 | for (i = 0; i < ldev->ports; i++) { | |
148 | if (!ldev->pf[i].dev) | |
149 | continue; | |
150 | seq_printf(file, "%s\n", dev_name(ldev->pf[i].dev->device)); | |
151 | } | |
152 | mutex_unlock(&ldev->lock); | |
153 | ||
154 | return 0; | |
155 | } | |
156 | ||
157 | DEFINE_SHOW_ATTRIBUTE(type); | |
158 | DEFINE_SHOW_ATTRIBUTE(port_sel_mode); | |
159 | DEFINE_SHOW_ATTRIBUTE(state); | |
160 | DEFINE_SHOW_ATTRIBUTE(flags); | |
161 | DEFINE_SHOW_ATTRIBUTE(mapping); | |
162 | DEFINE_SHOW_ATTRIBUTE(members); | |
163 | ||
164 | void mlx5_ldev_add_debugfs(struct mlx5_core_dev *dev) | |
165 | { | |
166 | struct dentry *dbg; | |
167 | ||
168 | dbg = debugfs_create_dir("lag", mlx5_debugfs_get_dev_root(dev)); | |
169 | dev->priv.dbg.lag_debugfs = dbg; | |
170 | ||
171 | debugfs_create_file("type", 0444, dbg, dev, &type_fops); | |
172 | debugfs_create_file("port_sel_mode", 0444, dbg, dev, &port_sel_mode_fops); | |
173 | debugfs_create_file("state", 0444, dbg, dev, &state_fops); | |
174 | debugfs_create_file("flags", 0444, dbg, dev, &flags_fops); | |
175 | debugfs_create_file("mapping", 0444, dbg, dev, &mapping_fops); | |
176 | debugfs_create_file("members", 0444, dbg, dev, &members_fops); | |
177 | } | |
178 | ||
179 | void mlx5_ldev_remove_debugfs(struct dentry *dbg) | |
180 | { | |
181 | debugfs_remove_recursive(dbg); | |
182 | } |