xref: /linux/drivers/dpll/zl3073x/devlink.c (revision ccde82e909467abdf098a8ee6f63e1ecf9a47ce5)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #include <linux/device/devres.h>
4 #include <linux/netlink.h>
5 #include <linux/sprintf.h>
6 #include <linux/types.h>
7 #include <net/devlink.h>
8 
9 #include "core.h"
10 #include "devlink.h"
11 #include "dpll.h"
12 #include "flash.h"
13 #include "fw.h"
14 #include "regs.h"
15 
16 /**
17  * zl3073x_devlink_info_get - Devlink device info callback
18  * @devlink: devlink structure pointer
19  * @req: devlink request pointer to store information
20  * @extack: netlink extack pointer to report errors
21  *
22  * Return: 0 on success, <0 on error
23  */
24 static int
25 zl3073x_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
26 			 struct netlink_ext_ack *extack)
27 {
28 	struct zl3073x_dev *zldev = devlink_priv(devlink);
29 	u16 id, revision, fw_ver;
30 	char buf[16];
31 	u32 cfg_ver;
32 	int rc;
33 
34 	rc = zl3073x_read_u16(zldev, ZL_REG_ID, &id);
35 	if (rc)
36 		return rc;
37 
38 	snprintf(buf, sizeof(buf), "%X", id);
39 	rc = devlink_info_version_fixed_put(req,
40 					    DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
41 					    buf);
42 	if (rc)
43 		return rc;
44 
45 	rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision);
46 	if (rc)
47 		return rc;
48 
49 	snprintf(buf, sizeof(buf), "%X", revision);
50 	rc = devlink_info_version_fixed_put(req,
51 					    DEVLINK_INFO_VERSION_GENERIC_ASIC_REV,
52 					    buf);
53 	if (rc)
54 		return rc;
55 
56 	rc = zl3073x_read_u16(zldev, ZL_REG_FW_VER, &fw_ver);
57 	if (rc)
58 		return rc;
59 
60 	snprintf(buf, sizeof(buf), "%u", fw_ver);
61 	rc = devlink_info_version_running_put(req,
62 					      DEVLINK_INFO_VERSION_GENERIC_FW,
63 					      buf);
64 	if (rc)
65 		return rc;
66 
67 	rc = zl3073x_read_u32(zldev, ZL_REG_CUSTOM_CONFIG_VER, &cfg_ver);
68 	if (rc)
69 		return rc;
70 
71 	/* No custom config version */
72 	if (cfg_ver == U32_MAX)
73 		return 0;
74 
75 	snprintf(buf, sizeof(buf), "%lu.%lu.%lu.%lu",
76 		 FIELD_GET(GENMASK(31, 24), cfg_ver),
77 		 FIELD_GET(GENMASK(23, 16), cfg_ver),
78 		 FIELD_GET(GENMASK(15, 8), cfg_ver),
79 		 FIELD_GET(GENMASK(7, 0), cfg_ver));
80 
81 	return devlink_info_version_running_put(req, "custom_cfg", buf);
82 }
83 
84 static int
85 zl3073x_devlink_reload_down(struct devlink *devlink, bool netns_change,
86 			    enum devlink_reload_action action,
87 			    enum devlink_reload_limit limit,
88 			    struct netlink_ext_ack *extack)
89 {
90 	struct zl3073x_dev *zldev = devlink_priv(devlink);
91 
92 	if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT)
93 		return -EOPNOTSUPP;
94 
95 	/* Stop normal operation */
96 	zl3073x_dev_stop(zldev);
97 
98 	return 0;
99 }
100 
101 static int
102 zl3073x_devlink_reload_up(struct devlink *devlink,
103 			  enum devlink_reload_action action,
104 			  enum devlink_reload_limit limit,
105 			  u32 *actions_performed,
106 			  struct netlink_ext_ack *extack)
107 {
108 	struct zl3073x_dev *zldev = devlink_priv(devlink);
109 	union devlink_param_value val;
110 	int rc;
111 
112 	if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT)
113 		return -EOPNOTSUPP;
114 
115 	rc = devl_param_driverinit_value_get(devlink,
116 					     DEVLINK_PARAM_GENERIC_ID_CLOCK_ID,
117 					     &val);
118 	if (rc)
119 		return rc;
120 
121 	if (zldev->clock_id != val.vu64) {
122 		dev_dbg(zldev->dev,
123 			"'clock_id' changed to %016llx\n", val.vu64);
124 		zldev->clock_id = val.vu64;
125 	}
126 
127 	/* Restart normal operation */
128 	rc = zl3073x_dev_start(zldev, false);
129 	if (rc)
130 		dev_warn(zldev->dev, "Failed to re-start normal operation\n");
131 
132 	*actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT);
133 
134 	return 0;
135 }
136 
137 void zl3073x_devlink_flash_notify(struct zl3073x_dev *zldev, const char *msg,
138 				  const char *component, u32 done, u32 total)
139 {
140 	struct devlink *devlink = priv_to_devlink(zldev);
141 
142 	devlink_flash_update_status_notify(devlink, msg, component, done,
143 					   total);
144 }
145 
146 /**
147  * zl3073x_devlink_flash_prepare - Prepare and enter flash mode
148  * @zldev: zl3073x device pointer
149  * @zlfw: pointer to loaded firmware
150  * @extack: netlink extack pointer to report errors
151  *
152  * The function stops normal operation and switches the device to flash mode.
153  * If an error occurs the normal operation is resumed.
154  *
155  * Return: 0 on success, <0 on error
156  */
157 static int
158 zl3073x_devlink_flash_prepare(struct zl3073x_dev *zldev,
159 			      struct zl3073x_fw *zlfw,
160 			      struct netlink_ext_ack *extack)
161 {
162 	struct zl3073x_fw_component *util;
163 	int rc;
164 
165 	util = zlfw->component[ZL_FW_COMPONENT_UTIL];
166 	if (!util) {
167 		zl3073x_devlink_flash_notify(zldev,
168 					     "Utility is missing in firmware",
169 					     NULL, 0, 0);
170 		zl3073x_fw_free(zlfw);
171 		return -ENOEXEC;
172 	}
173 
174 	/* Stop normal operation prior entering flash mode */
175 	zl3073x_dev_stop(zldev);
176 
177 	rc = zl3073x_flash_mode_enter(zldev, util->data, util->size, extack);
178 	if (rc) {
179 		zl3073x_devlink_flash_notify(zldev,
180 					     "Failed to enter flash mode",
181 					     NULL, 0, 0);
182 
183 		/* Resume normal operation */
184 		zl3073x_dev_start(zldev, true);
185 
186 		return rc;
187 	}
188 
189 	return 0;
190 }
191 
192 /**
193  * zl3073x_devlink_flash_finish - Leave flash mode and resume normal operation
194  * @zldev: zl3073x device pointer
195  * @extack: netlink extack pointer to report errors
196  *
197  * The function switches the device back to standard mode and resumes normal
198  * operation.
199  *
200  * Return: 0 on success, <0 on error
201  */
202 static int
203 zl3073x_devlink_flash_finish(struct zl3073x_dev *zldev,
204 			     struct netlink_ext_ack *extack)
205 {
206 	int rc;
207 
208 	/* Reset device CPU to normal mode */
209 	zl3073x_flash_mode_leave(zldev, extack);
210 
211 	/* Resume normal operation */
212 	rc = zl3073x_dev_start(zldev, true);
213 	if (rc)
214 		zl3073x_devlink_flash_notify(zldev,
215 					     "Failed to start normal operation",
216 					     NULL, 0, 0);
217 
218 	return rc;
219 }
220 
221 /**
222  * zl3073x_devlink_flash_update - Devlink flash update callback
223  * @devlink: devlink structure pointer
224  * @params: flashing parameters pointer
225  * @extack: netlink extack pointer to report errors
226  *
227  * Return: 0 on success, <0 on error
228  */
229 static int
230 zl3073x_devlink_flash_update(struct devlink *devlink,
231 			     struct devlink_flash_update_params *params,
232 			     struct netlink_ext_ack *extack)
233 {
234 	struct zl3073x_dev *zldev = devlink_priv(devlink);
235 	struct zl3073x_fw *zlfw;
236 	int rc = 0;
237 
238 	zlfw = zl3073x_fw_load(zldev, params->fw->data, params->fw->size,
239 			       extack);
240 	if (IS_ERR(zlfw)) {
241 		zl3073x_devlink_flash_notify(zldev, "Failed to load firmware",
242 					     NULL, 0, 0);
243 		rc = PTR_ERR(zlfw);
244 		goto finish;
245 	}
246 
247 	/* Stop normal operation and enter flash mode */
248 	rc = zl3073x_devlink_flash_prepare(zldev, zlfw, extack);
249 	if (rc)
250 		goto finish;
251 
252 	rc = zl3073x_fw_flash(zldev, zlfw, extack);
253 	if (rc) {
254 		zl3073x_devlink_flash_finish(zldev, extack);
255 		goto finish;
256 	}
257 
258 	/* Resume normal mode */
259 	rc = zl3073x_devlink_flash_finish(zldev, extack);
260 
261 finish:
262 	if (!IS_ERR(zlfw))
263 		zl3073x_fw_free(zlfw);
264 
265 	zl3073x_devlink_flash_notify(zldev,
266 				     rc ? "Flashing failed" : "Flashing done",
267 				     NULL, 0, 0);
268 
269 	return rc;
270 }
271 
272 static const struct devlink_ops zl3073x_devlink_ops = {
273 	.info_get = zl3073x_devlink_info_get,
274 	.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),
275 	.reload_down = zl3073x_devlink_reload_down,
276 	.reload_up = zl3073x_devlink_reload_up,
277 	.flash_update = zl3073x_devlink_flash_update,
278 };
279 
280 static void
281 zl3073x_devlink_free(void *ptr)
282 {
283 	devlink_free(ptr);
284 }
285 
286 /**
287  * zl3073x_devm_alloc - allocates zl3073x device structure
288  * @dev: pointer to device structure
289  *
290  * Allocates zl3073x device structure as device resource.
291  *
292  * Return: pointer to zl3073x device on success, error pointer on error
293  */
294 struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev)
295 {
296 	struct zl3073x_dev *zldev;
297 	struct devlink *devlink;
298 	int rc;
299 
300 	devlink = devlink_alloc(&zl3073x_devlink_ops, sizeof(*zldev), dev);
301 	if (!devlink)
302 		return ERR_PTR(-ENOMEM);
303 
304 	/* Add devres action to free devlink device */
305 	rc = devm_add_action_or_reset(dev, zl3073x_devlink_free, devlink);
306 	if (rc)
307 		return ERR_PTR(rc);
308 
309 	zldev = devlink_priv(devlink);
310 	zldev->dev = dev;
311 	dev_set_drvdata(zldev->dev, zldev);
312 
313 	return zldev;
314 }
315 EXPORT_SYMBOL_NS_GPL(zl3073x_devm_alloc, "ZL3073X");
316 
317 static int
318 zl3073x_devlink_param_clock_id_validate(struct devlink *devlink, u32 id,
319 					union devlink_param_value val,
320 					struct netlink_ext_ack *extack)
321 {
322 	if (!val.vu64) {
323 		NL_SET_ERR_MSG_MOD(extack, "'clock_id' must be non-zero");
324 		return -EINVAL;
325 	}
326 
327 	return 0;
328 }
329 
330 static const struct devlink_param zl3073x_devlink_params[] = {
331 	DEVLINK_PARAM_GENERIC(CLOCK_ID, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
332 			      NULL, NULL,
333 			      zl3073x_devlink_param_clock_id_validate),
334 };
335 
336 static void
337 zl3073x_devlink_unregister(void *ptr)
338 {
339 	struct devlink *devlink = priv_to_devlink(ptr);
340 
341 	devl_lock(devlink);
342 
343 	/* Unregister devlink params */
344 	devl_params_unregister(devlink, zl3073x_devlink_params,
345 			       ARRAY_SIZE(zl3073x_devlink_params));
346 
347 	/* Unregister devlink instance */
348 	devl_unregister(devlink);
349 
350 	devl_unlock(devlink);
351 }
352 
353 /**
354  * zl3073x_devlink_register - register devlink instance and params
355  * @zldev: zl3073x device to register the devlink for
356  *
357  * Register the devlink instance and parameters associated with the device.
358  *
359  * Return: 0 on success, <0 on error
360  */
361 int zl3073x_devlink_register(struct zl3073x_dev *zldev)
362 {
363 	struct devlink *devlink = priv_to_devlink(zldev);
364 	union devlink_param_value value;
365 	int rc;
366 
367 	devl_lock(devlink);
368 
369 	/* Register devlink params */
370 	rc = devl_params_register(devlink, zl3073x_devlink_params,
371 				  ARRAY_SIZE(zl3073x_devlink_params));
372 	if (rc) {
373 		devl_unlock(devlink);
374 
375 		return rc;
376 	}
377 
378 	value.vu64 = zldev->clock_id;
379 	devl_param_driverinit_value_set(devlink,
380 					DEVLINK_PARAM_GENERIC_ID_CLOCK_ID,
381 					value);
382 
383 	/* Register devlink instance */
384 	devl_register(devlink);
385 
386 	devl_unlock(devlink);
387 
388 	/* Add devres action to unregister devlink device */
389 	return devm_add_action_or_reset(zldev->dev, zl3073x_devlink_unregister,
390 					zldev);
391 }
392