1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2025, Intel Corporation. */
3
4#include "ixgbe.h"
5#include "devlink.h"
6#include "ixgbe_fw_update.h"
7
8struct ixgbe_info_ctx {
9 char buf[128];
10 struct ixgbe_orom_info pending_orom;
11 struct ixgbe_nvm_info pending_nvm;
12 struct ixgbe_netlist_info pending_netlist;
13 struct ixgbe_hw_dev_caps dev_caps;
14};
15
16enum ixgbe_devlink_version_type {
17 IXGBE_DL_VERSION_RUNNING,
18 IXGBE_DL_VERSION_STORED
19};
20
21static void ixgbe_info_get_dsn(struct ixgbe_adapter *adapter,
22 struct ixgbe_info_ctx *ctx)
23{
24 u8 dsn[8];
25
26 /* Copy the DSN into an array in Big Endian format */
27 put_unaligned_be64(val: pci_get_dsn(dev: adapter->pdev), p: dsn);
28
29 snprintf(buf: ctx->buf, size: sizeof(ctx->buf), fmt: "%8phD", dsn);
30}
31
32static void ixgbe_info_orom_ver(struct ixgbe_adapter *adapter,
33 struct ixgbe_info_ctx *ctx,
34 enum ixgbe_devlink_version_type type)
35{
36 struct ixgbe_hw *hw = &adapter->hw;
37 struct ixgbe_nvm_version nvm_ver;
38
39 ctx->buf[0] = '\0';
40
41 if (hw->mac.type == ixgbe_mac_e610) {
42 struct ixgbe_orom_info *orom = &adapter->hw.flash.orom;
43
44 if (type == IXGBE_DL_VERSION_STORED &&
45 ctx->dev_caps.common_cap.nvm_update_pending_orom)
46 orom = &ctx->pending_orom;
47
48 snprintf(buf: ctx->buf, size: sizeof(ctx->buf), fmt: "%u.%u.%u",
49 orom->major, orom->build, orom->patch);
50 return;
51 }
52
53 ixgbe_get_oem_prod_version(hw, nvm_ver: &nvm_ver);
54 if (nvm_ver.oem_valid) {
55 snprintf(buf: ctx->buf, size: sizeof(ctx->buf), fmt: "%x.%x.%x",
56 nvm_ver.oem_major, nvm_ver.oem_minor,
57 nvm_ver.oem_release);
58
59 return;
60 }
61
62 ixgbe_get_orom_version(hw, nvm_ver: &nvm_ver);
63 if (nvm_ver.or_valid)
64 snprintf(buf: ctx->buf, size: sizeof(ctx->buf), fmt: "%d.%d.%d",
65 nvm_ver.or_major, nvm_ver.or_build, nvm_ver.or_patch);
66}
67
68static void ixgbe_info_eetrack(struct ixgbe_adapter *adapter,
69 struct ixgbe_info_ctx *ctx,
70 enum ixgbe_devlink_version_type type)
71{
72 struct ixgbe_hw *hw = &adapter->hw;
73 struct ixgbe_nvm_version nvm_ver;
74
75 if (hw->mac.type == ixgbe_mac_e610) {
76 u32 eetrack = hw->flash.nvm.eetrack;
77
78 if (type == IXGBE_DL_VERSION_STORED &&
79 ctx->dev_caps.common_cap.nvm_update_pending_nvm)
80 eetrack = ctx->pending_nvm.eetrack;
81
82 snprintf(buf: ctx->buf, size: sizeof(ctx->buf), fmt: "0x%08x", eetrack);
83 return;
84 }
85
86 ixgbe_get_oem_prod_version(hw, nvm_ver: &nvm_ver);
87
88 /* No ETRACK version for OEM */
89 if (nvm_ver.oem_valid) {
90 ctx->buf[0] = '\0';
91 return;
92 }
93
94 ixgbe_get_etk_id(hw, nvm_ver: &nvm_ver);
95 snprintf(buf: ctx->buf, size: sizeof(ctx->buf), fmt: "0x%08x", nvm_ver.etk_id);
96}
97
98static void ixgbe_info_fw_api(struct ixgbe_adapter *adapter,
99 struct ixgbe_info_ctx *ctx)
100{
101 struct ixgbe_hw *hw = &adapter->hw;
102
103 snprintf(buf: ctx->buf, size: sizeof(ctx->buf), fmt: "%u.%u.%u",
104 hw->api_maj_ver, hw->api_min_ver, hw->api_patch);
105}
106
107static void ixgbe_info_fw_build(struct ixgbe_adapter *adapter,
108 struct ixgbe_info_ctx *ctx)
109{
110 struct ixgbe_hw *hw = &adapter->hw;
111
112 snprintf(buf: ctx->buf, size: sizeof(ctx->buf), fmt: "0x%08x", hw->fw_build);
113}
114
115static void ixgbe_info_fw_srev(struct ixgbe_adapter *adapter,
116 struct ixgbe_info_ctx *ctx,
117 enum ixgbe_devlink_version_type type)
118{
119 struct ixgbe_nvm_info *nvm = &adapter->hw.flash.nvm;
120
121 if (type == IXGBE_DL_VERSION_STORED &&
122 ctx->dev_caps.common_cap.nvm_update_pending_nvm)
123 nvm = &ctx->pending_nvm;
124
125 snprintf(buf: ctx->buf, size: sizeof(ctx->buf), fmt: "%u", nvm->srev);
126}
127
128static void ixgbe_info_orom_srev(struct ixgbe_adapter *adapter,
129 struct ixgbe_info_ctx *ctx,
130 enum ixgbe_devlink_version_type type)
131{
132 struct ixgbe_orom_info *orom = &adapter->hw.flash.orom;
133
134 if (type == IXGBE_DL_VERSION_STORED &&
135 ctx->dev_caps.common_cap.nvm_update_pending_orom)
136 orom = &ctx->pending_orom;
137
138 snprintf(buf: ctx->buf, size: sizeof(ctx->buf), fmt: "%u", orom->srev);
139}
140
141static void ixgbe_info_nvm_ver(struct ixgbe_adapter *adapter,
142 struct ixgbe_info_ctx *ctx,
143 enum ixgbe_devlink_version_type type)
144{
145 struct ixgbe_nvm_info *nvm = &adapter->hw.flash.nvm;
146
147 if (type == IXGBE_DL_VERSION_STORED &&
148 ctx->dev_caps.common_cap.nvm_update_pending_nvm)
149 nvm = &ctx->pending_nvm;
150
151 snprintf(buf: ctx->buf, size: sizeof(ctx->buf), fmt: "%x.%02x", nvm->major, nvm->minor);
152}
153
154static void ixgbe_info_netlist_ver(struct ixgbe_adapter *adapter,
155 struct ixgbe_info_ctx *ctx,
156 enum ixgbe_devlink_version_type type)
157{
158 struct ixgbe_netlist_info *netlist = &adapter->hw.flash.netlist;
159
160 if (type == IXGBE_DL_VERSION_STORED &&
161 ctx->dev_caps.common_cap.nvm_update_pending_netlist)
162 netlist = &ctx->pending_netlist;
163
164 /* The netlist version fields are BCD formatted */
165 snprintf(buf: ctx->buf, size: sizeof(ctx->buf), fmt: "%x.%x.%x-%x.%x.%x",
166 netlist->major, netlist->minor,
167 netlist->type >> 16, netlist->type & 0xFFFF,
168 netlist->rev, netlist->cust_ver);
169}
170
171static void ixgbe_info_netlist_build(struct ixgbe_adapter *adapter,
172 struct ixgbe_info_ctx *ctx,
173 enum ixgbe_devlink_version_type type)
174{
175 struct ixgbe_netlist_info *netlist = &adapter->hw.flash.netlist;
176
177 if (type == IXGBE_DL_VERSION_STORED &&
178 ctx->dev_caps.common_cap.nvm_update_pending_netlist)
179 netlist = &ctx->pending_netlist;
180
181 snprintf(buf: ctx->buf, size: sizeof(ctx->buf), fmt: "0x%08x", netlist->hash);
182}
183
184static int ixgbe_set_ctx_dev_caps(struct ixgbe_hw *hw,
185 struct ixgbe_info_ctx *ctx,
186 struct netlink_ext_ack *extack)
187{
188 bool *pending_orom, *pending_nvm, *pending_netlist;
189 int err;
190
191 err = ixgbe_discover_dev_caps(hw, dev_caps: &ctx->dev_caps);
192 if (err) {
193 NL_SET_ERR_MSG_MOD(extack,
194 "Unable to discover device capabilities");
195 return err;
196 }
197
198 pending_orom = &ctx->dev_caps.common_cap.nvm_update_pending_orom;
199 pending_nvm = &ctx->dev_caps.common_cap.nvm_update_pending_nvm;
200 pending_netlist = &ctx->dev_caps.common_cap.nvm_update_pending_netlist;
201
202 if (*pending_orom) {
203 err = ixgbe_get_inactive_orom_ver(hw, orom: &ctx->pending_orom);
204 if (err)
205 *pending_orom = false;
206 }
207
208 if (*pending_nvm) {
209 err = ixgbe_get_inactive_nvm_ver(hw, nvm: &ctx->pending_nvm);
210 if (err)
211 *pending_nvm = false;
212 }
213
214 if (*pending_netlist) {
215 err = ixgbe_get_inactive_netlist_ver(hw, netlist: &ctx->pending_netlist);
216 if (err)
217 *pending_netlist = false;
218 }
219
220 return 0;
221}
222
223static int ixgbe_devlink_info_get_e610(struct ixgbe_adapter *adapter,
224 struct devlink_info_req *req,
225 struct ixgbe_info_ctx *ctx)
226{
227 int err;
228
229 ixgbe_info_fw_api(adapter, ctx);
230 err = devlink_info_version_running_put(req,
231 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API,
232 version_value: ctx->buf);
233 if (err)
234 return err;
235
236 ixgbe_info_fw_build(adapter, ctx);
237 err = devlink_info_version_running_put(req, version_name: "fw.mgmt.build", version_value: ctx->buf);
238 if (err)
239 return err;
240
241 ixgbe_info_fw_srev(adapter, ctx, type: IXGBE_DL_VERSION_RUNNING);
242 err = devlink_info_version_running_put(req, version_name: "fw.mgmt.srev", version_value: ctx->buf);
243 if (err)
244 return err;
245
246 ixgbe_info_orom_srev(adapter, ctx, type: IXGBE_DL_VERSION_RUNNING);
247 err = devlink_info_version_running_put(req, version_name: "fw.undi.srev", version_value: ctx->buf);
248 if (err)
249 return err;
250
251 ixgbe_info_nvm_ver(adapter, ctx, type: IXGBE_DL_VERSION_RUNNING);
252 err = devlink_info_version_running_put(req, version_name: "fw.psid.api", version_value: ctx->buf);
253 if (err)
254 return err;
255
256 ixgbe_info_netlist_ver(adapter, ctx, type: IXGBE_DL_VERSION_RUNNING);
257 err = devlink_info_version_running_put(req, version_name: "fw.netlist", version_value: ctx->buf);
258 if (err)
259 return err;
260
261 ixgbe_info_netlist_build(adapter, ctx, type: IXGBE_DL_VERSION_RUNNING);
262 return devlink_info_version_running_put(req, version_name: "fw.netlist.build",
263 version_value: ctx->buf);
264}
265
266static int
267ixgbe_devlink_pending_info_get_e610(struct ixgbe_adapter *adapter,
268 struct devlink_info_req *req,
269 struct ixgbe_info_ctx *ctx)
270{
271 int err;
272
273 ixgbe_info_orom_ver(adapter, ctx, type: IXGBE_DL_VERSION_STORED);
274 err = devlink_info_version_stored_put(req,
275 DEVLINK_INFO_VERSION_GENERIC_FW_UNDI,
276 version_value: ctx->buf);
277 if (err)
278 return err;
279
280 ixgbe_info_eetrack(adapter, ctx, type: IXGBE_DL_VERSION_STORED);
281 err = devlink_info_version_stored_put(req,
282 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
283 version_value: ctx->buf);
284 if (err)
285 return err;
286
287 ixgbe_info_fw_srev(adapter, ctx, type: IXGBE_DL_VERSION_STORED);
288 err = devlink_info_version_stored_put(req, version_name: "fw.mgmt.srev", version_value: ctx->buf);
289 if (err)
290 return err;
291
292 ixgbe_info_orom_srev(adapter, ctx, type: IXGBE_DL_VERSION_STORED);
293 err = devlink_info_version_stored_put(req, version_name: "fw.undi.srev", version_value: ctx->buf);
294 if (err)
295 return err;
296
297 ixgbe_info_nvm_ver(adapter, ctx, type: IXGBE_DL_VERSION_STORED);
298 err = devlink_info_version_stored_put(req, version_name: "fw.psid.api", version_value: ctx->buf);
299 if (err)
300 return err;
301
302 ixgbe_info_netlist_ver(adapter, ctx, type: IXGBE_DL_VERSION_STORED);
303 err = devlink_info_version_stored_put(req, version_name: "fw.netlist", version_value: ctx->buf);
304 if (err)
305 return err;
306
307 ixgbe_info_netlist_build(adapter, ctx, type: IXGBE_DL_VERSION_STORED);
308 return devlink_info_version_stored_put(req, version_name: "fw.netlist.build",
309 version_value: ctx->buf);
310}
311
312static int ixgbe_devlink_info_get(struct devlink *devlink,
313 struct devlink_info_req *req,
314 struct netlink_ext_ack *extack)
315{
316 struct ixgbe_adapter *adapter = devlink_priv(devlink);
317 struct ixgbe_hw *hw = &adapter->hw;
318 struct ixgbe_info_ctx *ctx;
319 int err;
320
321 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
322 if (!ctx)
323 return -ENOMEM;
324
325 if (hw->mac.type == ixgbe_mac_e610)
326 ixgbe_refresh_fw_version(adapter);
327
328 ixgbe_info_get_dsn(adapter, ctx);
329 err = devlink_info_serial_number_put(req, sn: ctx->buf);
330 if (err)
331 goto free_ctx;
332
333 err = hw->eeprom.ops.read_pba_string(hw, ctx->buf, sizeof(ctx->buf));
334 if (err)
335 goto free_ctx;
336
337 err = devlink_info_version_fixed_put(req,
338 DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
339 version_value: ctx->buf);
340 if (err)
341 goto free_ctx;
342
343 ixgbe_info_orom_ver(adapter, ctx, type: IXGBE_DL_VERSION_RUNNING);
344 err = devlink_info_version_running_put(req,
345 DEVLINK_INFO_VERSION_GENERIC_FW_UNDI,
346 version_value: ctx->buf);
347 if (err)
348 goto free_ctx;
349
350 ixgbe_info_eetrack(adapter, ctx, type: IXGBE_DL_VERSION_RUNNING);
351 err = devlink_info_version_running_put(req,
352 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
353 version_value: ctx->buf);
354 if (err || hw->mac.type != ixgbe_mac_e610)
355 goto free_ctx;
356
357 err = ixgbe_set_ctx_dev_caps(hw, ctx, extack);
358 if (err)
359 goto free_ctx;
360
361 err = ixgbe_devlink_info_get_e610(adapter, req, ctx);
362 if (err)
363 goto free_ctx;
364
365 err = ixgbe_devlink_pending_info_get_e610(adapter, req, ctx);
366free_ctx:
367 kfree(objp: ctx);
368 return err;
369}
370
371/**
372 * ixgbe_devlink_reload_empr_start - Start EMP reset to activate new firmware
373 * @devlink: pointer to the devlink instance to reload
374 * @netns_change: if true, the network namespace is changing
375 * @action: the action to perform. Must be DEVLINK_RELOAD_ACTION_FW_ACTIVATE
376 * @limit: limits on what reload should do, such as not resetting
377 * @extack: netlink extended ACK structure
378 *
379 * Allow user to activate new Embedded Management Processor firmware by
380 * issuing device specific EMP reset. Called in response to
381 * a DEVLINK_CMD_RELOAD with the DEVLINK_RELOAD_ACTION_FW_ACTIVATE.
382 *
383 * Note that teardown and rebuild of the driver state happens automatically as
384 * part of an interrupt and watchdog task. This is because all physical
385 * functions on the device must be able to reset when an EMP reset occurs from
386 * any source.
387 *
388 * Return: the exit code of the operation.
389 */
390static int ixgbe_devlink_reload_empr_start(struct devlink *devlink,
391 bool netns_change,
392 enum devlink_reload_action action,
393 enum devlink_reload_limit limit,
394 struct netlink_ext_ack *extack)
395{
396 struct ixgbe_adapter *adapter = devlink_priv(devlink);
397 struct ixgbe_hw *hw = &adapter->hw;
398 u8 pending;
399 int err;
400
401 if (hw->mac.type != ixgbe_mac_e610)
402 return -EOPNOTSUPP;
403
404 err = ixgbe_get_pending_updates(adapter, pending: &pending, extack);
405 if (err)
406 return err;
407
408 /* Pending is a bitmask of which flash banks have a pending update,
409 * including the main NVM bank, the Option ROM bank, and the netlist
410 * bank. If any of these bits are set, then there is a pending update
411 * waiting to be activated.
412 */
413 if (!pending) {
414 NL_SET_ERR_MSG_MOD(extack, "No pending firmware update");
415 return -ECANCELED;
416 }
417
418 if (adapter->fw_emp_reset_disabled) {
419 NL_SET_ERR_MSG_MOD(extack,
420 "EMP reset is not available. To activate firmware, a reboot or power cycle is needed");
421 return -ECANCELED;
422 }
423
424 err = ixgbe_aci_nvm_update_empr(hw);
425 if (err)
426 NL_SET_ERR_MSG_MOD(extack,
427 "Failed to trigger EMP device reset to reload firmware");
428
429 return err;
430}
431
432/*Wait for 10 sec with 0.5 sec tic. EMPR takes no less than half of a sec */
433#define IXGBE_DEVLINK_RELOAD_TIMEOUT_SEC 20
434
435/**
436 * ixgbe_devlink_reload_empr_finish - finishes EMP reset
437 * @devlink: pointer to the devlink instance
438 * @action: the action to perform.
439 * @limit: limits on what reload should do
440 * @actions_performed: actions performed
441 * @extack: netlink extended ACK structure
442 *
443 * Wait for new NVM to be loaded during EMP reset.
444 *
445 * Return: -ETIME when timer is exceeded, 0 on success.
446 */
447static int ixgbe_devlink_reload_empr_finish(struct devlink *devlink,
448 enum devlink_reload_action action,
449 enum devlink_reload_limit limit,
450 u32 *actions_performed,
451 struct netlink_ext_ack *extack)
452{
453 struct ixgbe_adapter *adapter = devlink_priv(devlink);
454 struct ixgbe_hw *hw = &adapter->hw;
455 int i = 0;
456 u32 fwsm;
457
458 do {
459 /* Just right away after triggering EMP reset the FWSM register
460 * may be not cleared yet, so begin the loop with the delay
461 * in order to not check the not updated register.
462 */
463 mdelay(500);
464
465 fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw));
466
467 if (i++ >= IXGBE_DEVLINK_RELOAD_TIMEOUT_SEC)
468 return -ETIME;
469
470 } while (!(fwsm & IXGBE_FWSM_FW_VAL_BIT));
471
472 *actions_performed = BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE);
473
474 adapter->flags2 &= ~(IXGBE_FLAG2_API_MISMATCH |
475 IXGBE_FLAG2_FW_ROLLBACK);
476
477 return 0;
478}
479
480static const struct devlink_ops ixgbe_devlink_ops = {
481 .info_get = ixgbe_devlink_info_get,
482 .supported_flash_update_params =
483 DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK,
484 .flash_update = ixgbe_flash_pldm_image,
485 .reload_actions = BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE),
486 .reload_down = ixgbe_devlink_reload_empr_start,
487 .reload_up = ixgbe_devlink_reload_empr_finish,
488};
489
490/**
491 * ixgbe_allocate_devlink - Allocate devlink instance
492 * @dev: device to allocate devlink for
493 *
494 * Allocate a devlink instance for this physical function.
495 *
496 * Return: pointer to the device adapter structure on success,
497 * ERR_PTR(-ENOMEM) when allocation failed.
498 */
499struct ixgbe_adapter *ixgbe_allocate_devlink(struct device *dev)
500{
501 struct ixgbe_adapter *adapter;
502 struct devlink *devlink;
503
504 devlink = devlink_alloc(ops: &ixgbe_devlink_ops, priv_size: sizeof(*adapter), dev);
505 if (!devlink)
506 return ERR_PTR(error: -ENOMEM);
507
508 adapter = devlink_priv(devlink);
509 adapter->devlink = devlink;
510
511 return adapter;
512}
513
514/**
515 * ixgbe_devlink_set_switch_id - Set unique switch ID based on PCI DSN
516 * @adapter: pointer to the device adapter structure
517 * @ppid: struct with switch id information
518 */
519static void ixgbe_devlink_set_switch_id(struct ixgbe_adapter *adapter,
520 struct netdev_phys_item_id *ppid)
521{
522 u64 id = pci_get_dsn(dev: adapter->pdev);
523
524 ppid->id_len = sizeof(id);
525 put_unaligned_be64(val: id, p: &ppid->id);
526}
527
528/**
529 * ixgbe_devlink_register_port - Register devlink port
530 * @adapter: pointer to the device adapter structure
531 *
532 * Create and register a devlink_port for this physical function.
533 *
534 * Return: 0 on success, error code on failure.
535 */
536int ixgbe_devlink_register_port(struct ixgbe_adapter *adapter)
537{
538 struct devlink_port *devlink_port = &adapter->devlink_port;
539 struct devlink *devlink = adapter->devlink;
540 struct device *dev = &adapter->pdev->dev;
541 struct devlink_port_attrs attrs = {};
542 int err;
543
544 attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
545 attrs.phys.port_number = adapter->hw.bus.func;
546 ixgbe_devlink_set_switch_id(adapter, ppid: &attrs.switch_id);
547
548 devlink_port_attrs_set(devlink_port, devlink_port_attrs: &attrs);
549
550 err = devl_port_register(devlink, devlink_port, port_index: 0);
551 if (err) {
552 dev_err(dev,
553 "devlink port registration failed, err %d\n", err);
554 }
555
556 return err;
557}
558

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of linux/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c