Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/dpll/zl3073x/devlink.c
29268 views
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
return -ENOEXEC;
171
}
172
173
/* Stop normal operation prior entering flash mode */
174
zl3073x_dev_stop(zldev);
175
176
rc = zl3073x_flash_mode_enter(zldev, util->data, util->size, extack);
177
if (rc) {
178
zl3073x_devlink_flash_notify(zldev,
179
"Failed to enter flash mode",
180
NULL, 0, 0);
181
182
/* Resume normal operation */
183
zl3073x_dev_start(zldev, true);
184
185
return rc;
186
}
187
188
return 0;
189
}
190
191
/**
192
* zl3073x_devlink_flash_finish - Leave flash mode and resume normal operation
193
* @zldev: zl3073x device pointer
194
* @extack: netlink extack pointer to report errors
195
*
196
* The function switches the device back to standard mode and resumes normal
197
* operation.
198
*
199
* Return: 0 on success, <0 on error
200
*/
201
static int
202
zl3073x_devlink_flash_finish(struct zl3073x_dev *zldev,
203
struct netlink_ext_ack *extack)
204
{
205
int rc;
206
207
/* Reset device CPU to normal mode */
208
zl3073x_flash_mode_leave(zldev, extack);
209
210
/* Resume normal operation */
211
rc = zl3073x_dev_start(zldev, true);
212
if (rc)
213
zl3073x_devlink_flash_notify(zldev,
214
"Failed to start normal operation",
215
NULL, 0, 0);
216
217
return rc;
218
}
219
220
/**
221
* zl3073x_devlink_flash_update - Devlink flash update callback
222
* @devlink: devlink structure pointer
223
* @params: flashing parameters pointer
224
* @extack: netlink extack pointer to report errors
225
*
226
* Return: 0 on success, <0 on error
227
*/
228
static int
229
zl3073x_devlink_flash_update(struct devlink *devlink,
230
struct devlink_flash_update_params *params,
231
struct netlink_ext_ack *extack)
232
{
233
struct zl3073x_dev *zldev = devlink_priv(devlink);
234
struct zl3073x_fw *zlfw;
235
int rc = 0;
236
237
zlfw = zl3073x_fw_load(zldev, params->fw->data, params->fw->size,
238
extack);
239
if (IS_ERR(zlfw)) {
240
zl3073x_devlink_flash_notify(zldev, "Failed to load firmware",
241
NULL, 0, 0);
242
rc = PTR_ERR(zlfw);
243
goto finish;
244
}
245
246
/* Stop normal operation and enter flash mode */
247
rc = zl3073x_devlink_flash_prepare(zldev, zlfw, extack);
248
if (rc)
249
goto finish;
250
251
rc = zl3073x_fw_flash(zldev, zlfw, extack);
252
if (rc) {
253
zl3073x_devlink_flash_finish(zldev, extack);
254
goto finish;
255
}
256
257
/* Resume normal mode */
258
rc = zl3073x_devlink_flash_finish(zldev, extack);
259
260
finish:
261
if (!IS_ERR(zlfw))
262
zl3073x_fw_free(zlfw);
263
264
zl3073x_devlink_flash_notify(zldev,
265
rc ? "Flashing failed" : "Flashing done",
266
NULL, 0, 0);
267
268
return rc;
269
}
270
271
static const struct devlink_ops zl3073x_devlink_ops = {
272
.info_get = zl3073x_devlink_info_get,
273
.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),
274
.reload_down = zl3073x_devlink_reload_down,
275
.reload_up = zl3073x_devlink_reload_up,
276
.flash_update = zl3073x_devlink_flash_update,
277
};
278
279
static void
280
zl3073x_devlink_free(void *ptr)
281
{
282
devlink_free(ptr);
283
}
284
285
/**
286
* zl3073x_devm_alloc - allocates zl3073x device structure
287
* @dev: pointer to device structure
288
*
289
* Allocates zl3073x device structure as device resource.
290
*
291
* Return: pointer to zl3073x device on success, error pointer on error
292
*/
293
struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev)
294
{
295
struct zl3073x_dev *zldev;
296
struct devlink *devlink;
297
int rc;
298
299
devlink = devlink_alloc(&zl3073x_devlink_ops, sizeof(*zldev), dev);
300
if (!devlink)
301
return ERR_PTR(-ENOMEM);
302
303
/* Add devres action to free devlink device */
304
rc = devm_add_action_or_reset(dev, zl3073x_devlink_free, devlink);
305
if (rc)
306
return ERR_PTR(rc);
307
308
zldev = devlink_priv(devlink);
309
zldev->dev = dev;
310
dev_set_drvdata(zldev->dev, zldev);
311
312
return zldev;
313
}
314
EXPORT_SYMBOL_NS_GPL(zl3073x_devm_alloc, "ZL3073X");
315
316
static int
317
zl3073x_devlink_param_clock_id_validate(struct devlink *devlink, u32 id,
318
union devlink_param_value val,
319
struct netlink_ext_ack *extack)
320
{
321
if (!val.vu64) {
322
NL_SET_ERR_MSG_MOD(extack, "'clock_id' must be non-zero");
323
return -EINVAL;
324
}
325
326
return 0;
327
}
328
329
static const struct devlink_param zl3073x_devlink_params[] = {
330
DEVLINK_PARAM_GENERIC(CLOCK_ID, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
331
NULL, NULL,
332
zl3073x_devlink_param_clock_id_validate),
333
};
334
335
static void
336
zl3073x_devlink_unregister(void *ptr)
337
{
338
struct devlink *devlink = priv_to_devlink(ptr);
339
340
devl_lock(devlink);
341
342
/* Unregister devlink params */
343
devl_params_unregister(devlink, zl3073x_devlink_params,
344
ARRAY_SIZE(zl3073x_devlink_params));
345
346
/* Unregister devlink instance */
347
devl_unregister(devlink);
348
349
devl_unlock(devlink);
350
}
351
352
/**
353
* zl3073x_devlink_register - register devlink instance and params
354
* @zldev: zl3073x device to register the devlink for
355
*
356
* Register the devlink instance and parameters associated with the device.
357
*
358
* Return: 0 on success, <0 on error
359
*/
360
int zl3073x_devlink_register(struct zl3073x_dev *zldev)
361
{
362
struct devlink *devlink = priv_to_devlink(zldev);
363
union devlink_param_value value;
364
int rc;
365
366
devl_lock(devlink);
367
368
/* Register devlink params */
369
rc = devl_params_register(devlink, zl3073x_devlink_params,
370
ARRAY_SIZE(zl3073x_devlink_params));
371
if (rc) {
372
devl_unlock(devlink);
373
374
return rc;
375
}
376
377
value.vu64 = zldev->clock_id;
378
devl_param_driverinit_value_set(devlink,
379
DEVLINK_PARAM_GENERIC_ID_CLOCK_ID,
380
value);
381
382
/* Register devlink instance */
383
devl_register(devlink);
384
385
devl_unlock(devlink);
386
387
/* Add devres action to unregister devlink device */
388
return devm_add_action_or_reset(zldev->dev, zl3073x_devlink_unregister,
389
zldev);
390
}
391
392