Commit | Line | Data |
---|---|---|
1f28d776 EBE |
1 | // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB |
2 | /* Copyright (c) 2019 Mellanox Technologies */ | |
3 | ||
4 | #include <devlink.h> | |
5 | ||
6 | #include "mlx5_core.h" | |
e890acd5 | 7 | #include "fs_core.h" |
1f28d776 EBE |
8 | #include "eswitch.h" |
9 | ||
10 | static int mlx5_devlink_flash_update(struct devlink *devlink, | |
11 | const char *file_name, | |
12 | const char *component, | |
13 | struct netlink_ext_ack *extack) | |
14 | { | |
15 | struct mlx5_core_dev *dev = devlink_priv(devlink); | |
16 | const struct firmware *fw; | |
17 | int err; | |
18 | ||
19 | if (component) | |
20 | return -EOPNOTSUPP; | |
21 | ||
22 | err = request_firmware_direct(&fw, file_name, &dev->pdev->dev); | |
23 | if (err) | |
24 | return err; | |
25 | ||
26 | return mlx5_firmware_flash(dev, fw, extack); | |
27 | } | |
28 | ||
8338d937 SA |
29 | static u8 mlx5_fw_ver_major(u32 version) |
30 | { | |
31 | return (version >> 24) & 0xff; | |
32 | } | |
33 | ||
34 | static u8 mlx5_fw_ver_minor(u32 version) | |
35 | { | |
36 | return (version >> 16) & 0xff; | |
37 | } | |
38 | ||
39 | static u16 mlx5_fw_ver_subminor(u32 version) | |
40 | { | |
41 | return version & 0xffff; | |
42 | } | |
43 | ||
44 | #define DEVLINK_FW_STRING_LEN 32 | |
45 | ||
46 | static int | |
47 | mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, | |
48 | struct netlink_ext_ack *extack) | |
49 | { | |
50 | struct mlx5_core_dev *dev = devlink_priv(devlink); | |
51 | char version_str[DEVLINK_FW_STRING_LEN]; | |
52 | u32 running_fw, stored_fw; | |
53 | int err; | |
54 | ||
55 | err = devlink_info_driver_name_put(req, DRIVER_NAME); | |
56 | if (err) | |
57 | return err; | |
58 | ||
59 | err = devlink_info_version_fixed_put(req, "fw.psid", dev->board_id); | |
60 | if (err) | |
61 | return err; | |
62 | ||
63 | err = mlx5_fw_version_query(dev, &running_fw, &stored_fw); | |
64 | if (err) | |
65 | return err; | |
66 | ||
67 | snprintf(version_str, sizeof(version_str), "%d.%d.%04d", | |
68 | mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw), | |
69 | mlx5_fw_ver_subminor(running_fw)); | |
70 | err = devlink_info_version_running_put(req, "fw.version", version_str); | |
71 | if (err) | |
72 | return err; | |
73 | ||
74 | /* no pending version, return running (stored) version */ | |
75 | if (stored_fw == 0) | |
76 | stored_fw = running_fw; | |
77 | ||
78 | snprintf(version_str, sizeof(version_str), "%d.%d.%04d", | |
79 | mlx5_fw_ver_major(stored_fw), mlx5_fw_ver_minor(stored_fw), | |
80 | mlx5_fw_ver_subminor(stored_fw)); | |
81 | err = devlink_info_version_stored_put(req, "fw.version", version_str); | |
82 | if (err) | |
83 | return err; | |
84 | ||
85 | return 0; | |
86 | } | |
87 | ||
4383cfcc MG |
88 | static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change, |
89 | struct netlink_ext_ack *extack) | |
90 | { | |
91 | struct mlx5_core_dev *dev = devlink_priv(devlink); | |
92 | ||
93 | return mlx5_unload_one(dev, false); | |
94 | } | |
95 | ||
96 | static int mlx5_devlink_reload_up(struct devlink *devlink, | |
97 | struct netlink_ext_ack *extack) | |
98 | { | |
99 | struct mlx5_core_dev *dev = devlink_priv(devlink); | |
100 | ||
101 | return mlx5_load_one(dev, false); | |
102 | } | |
103 | ||
1f28d776 EBE |
104 | static const struct devlink_ops mlx5_devlink_ops = { |
105 | #ifdef CONFIG_MLX5_ESWITCH | |
106 | .eswitch_mode_set = mlx5_devlink_eswitch_mode_set, | |
107 | .eswitch_mode_get = mlx5_devlink_eswitch_mode_get, | |
108 | .eswitch_inline_mode_set = mlx5_devlink_eswitch_inline_mode_set, | |
109 | .eswitch_inline_mode_get = mlx5_devlink_eswitch_inline_mode_get, | |
110 | .eswitch_encap_mode_set = mlx5_devlink_eswitch_encap_mode_set, | |
111 | .eswitch_encap_mode_get = mlx5_devlink_eswitch_encap_mode_get, | |
112 | #endif | |
113 | .flash_update = mlx5_devlink_flash_update, | |
8338d937 | 114 | .info_get = mlx5_devlink_info_get, |
4383cfcc MG |
115 | .reload_down = mlx5_devlink_reload_down, |
116 | .reload_up = mlx5_devlink_reload_up, | |
1f28d776 EBE |
117 | }; |
118 | ||
39f58860 | 119 | struct devlink *mlx5_devlink_alloc(void) |
1f28d776 EBE |
120 | { |
121 | return devlink_alloc(&mlx5_devlink_ops, sizeof(struct mlx5_core_dev)); | |
122 | } | |
123 | ||
124 | void mlx5_devlink_free(struct devlink *devlink) | |
125 | { | |
126 | devlink_free(devlink); | |
127 | } | |
128 | ||
e890acd5 MG |
129 | static int mlx5_devlink_fs_mode_validate(struct devlink *devlink, u32 id, |
130 | union devlink_param_value val, | |
131 | struct netlink_ext_ack *extack) | |
132 | { | |
133 | struct mlx5_core_dev *dev = devlink_priv(devlink); | |
134 | char *value = val.vstr; | |
135 | int err = 0; | |
136 | ||
137 | if (!strcmp(value, "dmfs")) { | |
138 | return 0; | |
139 | } else if (!strcmp(value, "smfs")) { | |
140 | u8 eswitch_mode; | |
141 | bool smfs_cap; | |
142 | ||
143 | eswitch_mode = mlx5_eswitch_mode(dev->priv.eswitch); | |
144 | smfs_cap = mlx5_fs_dr_is_supported(dev); | |
145 | ||
146 | if (!smfs_cap) { | |
147 | err = -EOPNOTSUPP; | |
148 | NL_SET_ERR_MSG_MOD(extack, | |
149 | "Software managed steering is not supported by current device"); | |
150 | } | |
151 | ||
152 | else if (eswitch_mode == MLX5_ESWITCH_OFFLOADS) { | |
153 | NL_SET_ERR_MSG_MOD(extack, | |
4938c3d8 | 154 | "Software managed steering is not supported when eswitch offloads enabled."); |
e890acd5 MG |
155 | err = -EOPNOTSUPP; |
156 | } | |
157 | } else { | |
158 | NL_SET_ERR_MSG_MOD(extack, | |
159 | "Bad parameter: supported values are [\"dmfs\", \"smfs\"]"); | |
160 | err = -EINVAL; | |
161 | } | |
162 | ||
163 | return err; | |
164 | } | |
165 | ||
166 | static int mlx5_devlink_fs_mode_set(struct devlink *devlink, u32 id, | |
167 | struct devlink_param_gset_ctx *ctx) | |
168 | { | |
169 | struct mlx5_core_dev *dev = devlink_priv(devlink); | |
170 | enum mlx5_flow_steering_mode mode; | |
171 | ||
172 | if (!strcmp(ctx->val.vstr, "smfs")) | |
173 | mode = MLX5_FLOW_STEERING_MODE_SMFS; | |
174 | else | |
175 | mode = MLX5_FLOW_STEERING_MODE_DMFS; | |
176 | dev->priv.steering->mode = mode; | |
177 | ||
178 | return 0; | |
179 | } | |
180 | ||
181 | static int mlx5_devlink_fs_mode_get(struct devlink *devlink, u32 id, | |
182 | struct devlink_param_gset_ctx *ctx) | |
183 | { | |
184 | struct mlx5_core_dev *dev = devlink_priv(devlink); | |
185 | ||
186 | if (dev->priv.steering->mode == MLX5_FLOW_STEERING_MODE_SMFS) | |
187 | strcpy(ctx->val.vstr, "smfs"); | |
188 | else | |
189 | strcpy(ctx->val.vstr, "dmfs"); | |
190 | return 0; | |
191 | } | |
192 | ||
193 | enum mlx5_devlink_param_id { | |
194 | MLX5_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, | |
195 | MLX5_DEVLINK_PARAM_FLOW_STEERING_MODE, | |
196 | }; | |
197 | ||
cc9defcb MG |
198 | static int mlx5_devlink_enable_roce_validate(struct devlink *devlink, u32 id, |
199 | union devlink_param_value val, | |
200 | struct netlink_ext_ack *extack) | |
201 | { | |
202 | struct mlx5_core_dev *dev = devlink_priv(devlink); | |
203 | bool new_state = val.vbool; | |
204 | ||
205 | if (new_state && !MLX5_CAP_GEN(dev, roce)) { | |
206 | NL_SET_ERR_MSG_MOD(extack, "Device doesn't support RoCE"); | |
207 | return -EOPNOTSUPP; | |
208 | } | |
209 | ||
210 | return 0; | |
211 | } | |
212 | ||
e890acd5 MG |
213 | static const struct devlink_param mlx5_devlink_params[] = { |
214 | DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_FLOW_STEERING_MODE, | |
215 | "flow_steering_mode", DEVLINK_PARAM_TYPE_STRING, | |
216 | BIT(DEVLINK_PARAM_CMODE_RUNTIME), | |
217 | mlx5_devlink_fs_mode_get, mlx5_devlink_fs_mode_set, | |
218 | mlx5_devlink_fs_mode_validate), | |
cc9defcb MG |
219 | DEVLINK_PARAM_GENERIC(ENABLE_ROCE, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), |
220 | NULL, NULL, mlx5_devlink_enable_roce_validate), | |
e890acd5 MG |
221 | }; |
222 | ||
223 | static void mlx5_devlink_set_params_init_values(struct devlink *devlink) | |
224 | { | |
225 | struct mlx5_core_dev *dev = devlink_priv(devlink); | |
226 | union devlink_param_value value; | |
227 | ||
228 | if (dev->priv.steering->mode == MLX5_FLOW_STEERING_MODE_DMFS) | |
229 | strcpy(value.vstr, "dmfs"); | |
230 | else | |
231 | strcpy(value.vstr, "smfs"); | |
232 | devlink_param_driverinit_value_set(devlink, | |
233 | MLX5_DEVLINK_PARAM_FLOW_STEERING_MODE, | |
234 | value); | |
cc9defcb MG |
235 | |
236 | value.vbool = MLX5_CAP_GEN(dev, roce); | |
237 | devlink_param_driverinit_value_set(devlink, | |
238 | DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE, | |
239 | value); | |
e890acd5 MG |
240 | } |
241 | ||
1f28d776 EBE |
242 | int mlx5_devlink_register(struct devlink *devlink, struct device *dev) |
243 | { | |
e890acd5 MG |
244 | int err; |
245 | ||
246 | err = devlink_register(devlink, dev); | |
247 | if (err) | |
248 | return err; | |
249 | ||
250 | err = devlink_params_register(devlink, mlx5_devlink_params, | |
251 | ARRAY_SIZE(mlx5_devlink_params)); | |
252 | if (err) | |
253 | goto params_reg_err; | |
254 | mlx5_devlink_set_params_init_values(devlink); | |
255 | devlink_params_publish(devlink); | |
4383cfcc | 256 | devlink_reload_enable(devlink); |
e890acd5 MG |
257 | return 0; |
258 | ||
259 | params_reg_err: | |
260 | devlink_unregister(devlink); | |
261 | return err; | |
1f28d776 EBE |
262 | } |
263 | ||
264 | void mlx5_devlink_unregister(struct devlink *devlink) | |
265 | { | |
4383cfcc | 266 | devlink_reload_disable(devlink); |
e890acd5 MG |
267 | devlink_params_unregister(devlink, mlx5_devlink_params, |
268 | ARRAY_SIZE(mlx5_devlink_params)); | |
1f28d776 EBE |
269 | devlink_unregister(devlink); |
270 | } |