xref: /linux/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c (revision 6eae2aeb60b6f1cfa97e6e8f296027f15173a67a)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2025, Intel Corporation. */
3 
4 #include "ixgbe.h"
5 #include "devlink.h"
6 
7 struct ixgbe_info_ctx {
8 	char buf[128];
9 	struct ixgbe_orom_info pending_orom;
10 	struct ixgbe_nvm_info pending_nvm;
11 	struct ixgbe_netlist_info pending_netlist;
12 	struct ixgbe_hw_dev_caps dev_caps;
13 };
14 
15 enum ixgbe_devlink_version_type {
16 	IXGBE_DL_VERSION_RUNNING,
17 	IXGBE_DL_VERSION_STORED
18 };
19 
20 static void ixgbe_info_get_dsn(struct ixgbe_adapter *adapter,
21 			       struct ixgbe_info_ctx *ctx)
22 {
23 	u8 dsn[8];
24 
25 	/* Copy the DSN into an array in Big Endian format */
26 	put_unaligned_be64(pci_get_dsn(adapter->pdev), dsn);
27 
28 	snprintf(ctx->buf, sizeof(ctx->buf), "%8phD", dsn);
29 }
30 
31 static void ixgbe_info_orom_ver(struct ixgbe_adapter *adapter,
32 				struct ixgbe_info_ctx *ctx,
33 				enum ixgbe_devlink_version_type type)
34 {
35 	struct ixgbe_hw *hw = &adapter->hw;
36 	struct ixgbe_nvm_version nvm_ver;
37 
38 	ctx->buf[0] = '\0';
39 
40 	if (hw->mac.type == ixgbe_mac_e610) {
41 		struct ixgbe_orom_info *orom = &adapter->hw.flash.orom;
42 
43 		if (type == IXGBE_DL_VERSION_STORED &&
44 		    ctx->dev_caps.common_cap.nvm_update_pending_orom)
45 			orom = &ctx->pending_orom;
46 
47 		snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u",
48 			 orom->major, orom->build, orom->patch);
49 		return;
50 	}
51 
52 	ixgbe_get_oem_prod_version(hw, &nvm_ver);
53 	if (nvm_ver.oem_valid) {
54 		snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x",
55 			 nvm_ver.oem_major, nvm_ver.oem_minor,
56 			 nvm_ver.oem_release);
57 
58 		return;
59 	}
60 
61 	ixgbe_get_orom_version(hw, &nvm_ver);
62 	if (nvm_ver.or_valid)
63 		snprintf(ctx->buf, sizeof(ctx->buf), "%d.%d.%d",
64 			 nvm_ver.or_major, nvm_ver.or_build, nvm_ver.or_patch);
65 }
66 
67 static void ixgbe_info_eetrack(struct ixgbe_adapter *adapter,
68 			       struct ixgbe_info_ctx *ctx,
69 			       enum ixgbe_devlink_version_type type)
70 {
71 	struct ixgbe_hw *hw = &adapter->hw;
72 	struct ixgbe_nvm_version nvm_ver;
73 
74 	if (hw->mac.type == ixgbe_mac_e610) {
75 		u32 eetrack = hw->flash.nvm.eetrack;
76 
77 		if (type == IXGBE_DL_VERSION_STORED &&
78 		    ctx->dev_caps.common_cap.nvm_update_pending_nvm)
79 			eetrack = ctx->pending_nvm.eetrack;
80 
81 		snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", eetrack);
82 		return;
83 	}
84 
85 	ixgbe_get_oem_prod_version(hw, &nvm_ver);
86 
87 	/* No ETRACK version for OEM */
88 	if (nvm_ver.oem_valid) {
89 		ctx->buf[0] = '\0';
90 		return;
91 	}
92 
93 	ixgbe_get_etk_id(hw, &nvm_ver);
94 	snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", nvm_ver.etk_id);
95 }
96 
97 static void ixgbe_info_fw_api(struct ixgbe_adapter *adapter,
98 			      struct ixgbe_info_ctx *ctx)
99 {
100 	struct ixgbe_hw *hw = &adapter->hw;
101 
102 	snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u",
103 		 hw->api_maj_ver, hw->api_min_ver, hw->api_patch);
104 }
105 
106 static void ixgbe_info_fw_build(struct ixgbe_adapter *adapter,
107 				struct ixgbe_info_ctx *ctx)
108 {
109 	struct ixgbe_hw *hw = &adapter->hw;
110 
111 	snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", hw->fw_build);
112 }
113 
114 static void ixgbe_info_fw_srev(struct ixgbe_adapter *adapter,
115 			       struct ixgbe_info_ctx *ctx,
116 			       enum ixgbe_devlink_version_type type)
117 {
118 	struct ixgbe_nvm_info *nvm = &adapter->hw.flash.nvm;
119 
120 	if (type == IXGBE_DL_VERSION_STORED &&
121 	    ctx->dev_caps.common_cap.nvm_update_pending_nvm)
122 		nvm = &ctx->pending_nvm;
123 
124 	snprintf(ctx->buf, sizeof(ctx->buf), "%u", nvm->srev);
125 }
126 
127 static void ixgbe_info_orom_srev(struct ixgbe_adapter *adapter,
128 				 struct ixgbe_info_ctx *ctx,
129 				 enum ixgbe_devlink_version_type type)
130 {
131 	struct ixgbe_orom_info *orom = &adapter->hw.flash.orom;
132 
133 	if (type == IXGBE_DL_VERSION_STORED &&
134 	    ctx->dev_caps.common_cap.nvm_update_pending_orom)
135 		orom = &ctx->pending_orom;
136 
137 	snprintf(ctx->buf, sizeof(ctx->buf), "%u", orom->srev);
138 }
139 
140 static void ixgbe_info_nvm_ver(struct ixgbe_adapter *adapter,
141 			       struct ixgbe_info_ctx *ctx,
142 			       enum ixgbe_devlink_version_type type)
143 {
144 	struct ixgbe_nvm_info *nvm = &adapter->hw.flash.nvm;
145 
146 	if (type == IXGBE_DL_VERSION_STORED &&
147 	    ctx->dev_caps.common_cap.nvm_update_pending_nvm)
148 		nvm = &ctx->pending_nvm;
149 
150 	snprintf(ctx->buf, sizeof(ctx->buf), "%x.%02x", nvm->major, nvm->minor);
151 }
152 
153 static void ixgbe_info_netlist_ver(struct ixgbe_adapter *adapter,
154 				   struct ixgbe_info_ctx *ctx,
155 				   enum ixgbe_devlink_version_type type)
156 {
157 	struct ixgbe_netlist_info *netlist = &adapter->hw.flash.netlist;
158 
159 	if (type == IXGBE_DL_VERSION_STORED &&
160 	    ctx->dev_caps.common_cap.nvm_update_pending_netlist)
161 		netlist = &ctx->pending_netlist;
162 
163 	/* The netlist version fields are BCD formatted */
164 	snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x-%x.%x.%x",
165 		 netlist->major, netlist->minor,
166 		 netlist->type >> 16, netlist->type & 0xFFFF,
167 		 netlist->rev, netlist->cust_ver);
168 }
169 
170 static void ixgbe_info_netlist_build(struct ixgbe_adapter *adapter,
171 				     struct ixgbe_info_ctx *ctx,
172 				     enum ixgbe_devlink_version_type type)
173 {
174 	struct ixgbe_netlist_info *netlist = &adapter->hw.flash.netlist;
175 
176 	if (type == IXGBE_DL_VERSION_STORED &&
177 	    ctx->dev_caps.common_cap.nvm_update_pending_netlist)
178 		netlist = &ctx->pending_netlist;
179 
180 	snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", netlist->hash);
181 }
182 
183 static int ixgbe_set_ctx_dev_caps(struct ixgbe_hw *hw,
184 				  struct ixgbe_info_ctx *ctx,
185 				  struct netlink_ext_ack *extack)
186 {
187 	bool *pending_orom, *pending_nvm, *pending_netlist;
188 	int err;
189 
190 	err = ixgbe_discover_dev_caps(hw, &ctx->dev_caps);
191 	if (err) {
192 		NL_SET_ERR_MSG_MOD(extack,
193 				   "Unable to discover device capabilities");
194 		return err;
195 	}
196 
197 	pending_orom = &ctx->dev_caps.common_cap.nvm_update_pending_orom;
198 	pending_nvm = &ctx->dev_caps.common_cap.nvm_update_pending_nvm;
199 	pending_netlist = &ctx->dev_caps.common_cap.nvm_update_pending_netlist;
200 
201 	if (*pending_orom) {
202 		err = ixgbe_get_inactive_orom_ver(hw, &ctx->pending_orom);
203 		if (err)
204 			*pending_orom = false;
205 	}
206 
207 	if (*pending_nvm) {
208 		err = ixgbe_get_inactive_nvm_ver(hw, &ctx->pending_nvm);
209 		if (err)
210 			*pending_nvm = false;
211 	}
212 
213 	if (*pending_netlist) {
214 		err = ixgbe_get_inactive_netlist_ver(hw, &ctx->pending_netlist);
215 		if (err)
216 			*pending_netlist = false;
217 	}
218 
219 	return 0;
220 }
221 
222 static int ixgbe_devlink_info_get_e610(struct ixgbe_adapter *adapter,
223 				       struct devlink_info_req *req,
224 				       struct ixgbe_info_ctx *ctx)
225 {
226 	int err;
227 
228 	ixgbe_info_fw_api(adapter, ctx);
229 	err = devlink_info_version_running_put(req,
230 					       DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API,
231 					       ctx->buf);
232 	if (err)
233 		return err;
234 
235 	ixgbe_info_fw_build(adapter, ctx);
236 	err = devlink_info_version_running_put(req, "fw.mgmt.build", ctx->buf);
237 	if (err)
238 		return err;
239 
240 	ixgbe_info_fw_srev(adapter, ctx, IXGBE_DL_VERSION_RUNNING);
241 	err = devlink_info_version_running_put(req, "fw.mgmt.srev", ctx->buf);
242 	if (err)
243 		return err;
244 
245 	ixgbe_info_orom_srev(adapter, ctx, IXGBE_DL_VERSION_RUNNING);
246 	err = devlink_info_version_running_put(req, "fw.undi.srev", ctx->buf);
247 	if (err)
248 		return err;
249 
250 	ixgbe_info_nvm_ver(adapter, ctx, IXGBE_DL_VERSION_RUNNING);
251 	err = devlink_info_version_running_put(req, "fw.psid.api", ctx->buf);
252 	if (err)
253 		return err;
254 
255 	ixgbe_info_netlist_ver(adapter, ctx, IXGBE_DL_VERSION_RUNNING);
256 	err = devlink_info_version_running_put(req, "fw.netlist", ctx->buf);
257 	if (err)
258 		return err;
259 
260 	ixgbe_info_netlist_build(adapter, ctx, IXGBE_DL_VERSION_RUNNING);
261 	return devlink_info_version_running_put(req, "fw.netlist.build",
262 						ctx->buf);
263 }
264 
265 static int
266 ixgbe_devlink_pending_info_get_e610(struct ixgbe_adapter *adapter,
267 				    struct devlink_info_req *req,
268 				    struct ixgbe_info_ctx *ctx)
269 {
270 	int err;
271 
272 	ixgbe_info_orom_ver(adapter, ctx, IXGBE_DL_VERSION_STORED);
273 	err = devlink_info_version_stored_put(req,
274 					      DEVLINK_INFO_VERSION_GENERIC_FW_UNDI,
275 					      ctx->buf);
276 	if (err)
277 		return err;
278 
279 	ixgbe_info_eetrack(adapter, ctx, IXGBE_DL_VERSION_STORED);
280 	err = devlink_info_version_stored_put(req,
281 					      DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
282 					      ctx->buf);
283 	if (err)
284 		return err;
285 
286 	ixgbe_info_fw_srev(adapter, ctx, IXGBE_DL_VERSION_STORED);
287 	err = devlink_info_version_stored_put(req, "fw.mgmt.srev", ctx->buf);
288 	if (err)
289 		return err;
290 
291 	ixgbe_info_orom_srev(adapter, ctx, IXGBE_DL_VERSION_STORED);
292 	err = devlink_info_version_stored_put(req, "fw.undi.srev", ctx->buf);
293 	if (err)
294 		return err;
295 
296 	ixgbe_info_nvm_ver(adapter, ctx, IXGBE_DL_VERSION_STORED);
297 	err = devlink_info_version_stored_put(req, "fw.psid.api", ctx->buf);
298 	if (err)
299 		return err;
300 
301 	ixgbe_info_netlist_ver(adapter, ctx, IXGBE_DL_VERSION_STORED);
302 	err = devlink_info_version_stored_put(req, "fw.netlist", ctx->buf);
303 	if (err)
304 		return err;
305 
306 	ixgbe_info_netlist_build(adapter, ctx, IXGBE_DL_VERSION_STORED);
307 	return devlink_info_version_stored_put(req, "fw.netlist.build",
308 					       ctx->buf);
309 }
310 
311 static int ixgbe_devlink_info_get(struct devlink *devlink,
312 				  struct devlink_info_req *req,
313 				  struct netlink_ext_ack *extack)
314 {
315 	struct ixgbe_adapter *adapter = devlink_priv(devlink);
316 	struct ixgbe_hw *hw = &adapter->hw;
317 	struct ixgbe_info_ctx *ctx;
318 	int err;
319 
320 	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
321 	if (!ctx)
322 		return -ENOMEM;
323 
324 	ixgbe_info_get_dsn(adapter, ctx);
325 	err = devlink_info_serial_number_put(req, ctx->buf);
326 	if (err)
327 		goto free_ctx;
328 
329 	err = hw->eeprom.ops.read_pba_string(hw, ctx->buf, sizeof(ctx->buf));
330 	if (err)
331 		goto free_ctx;
332 
333 	err = devlink_info_version_fixed_put(req,
334 					     DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
335 					     ctx->buf);
336 	if (err)
337 		goto free_ctx;
338 
339 	ixgbe_info_orom_ver(adapter, ctx, IXGBE_DL_VERSION_RUNNING);
340 	err = devlink_info_version_running_put(req,
341 					       DEVLINK_INFO_VERSION_GENERIC_FW_UNDI,
342 					       ctx->buf);
343 	if (err)
344 		goto free_ctx;
345 
346 	ixgbe_info_eetrack(adapter, ctx, IXGBE_DL_VERSION_RUNNING);
347 	err = devlink_info_version_running_put(req,
348 					       DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
349 					       ctx->buf);
350 	if (err || hw->mac.type != ixgbe_mac_e610)
351 		goto free_ctx;
352 
353 	err = ixgbe_set_ctx_dev_caps(hw, ctx, extack);
354 	if (err)
355 		goto free_ctx;
356 
357 	err = ixgbe_devlink_info_get_e610(adapter, req, ctx);
358 	if (err)
359 		goto free_ctx;
360 
361 	err = ixgbe_devlink_pending_info_get_e610(adapter, req, ctx);
362 free_ctx:
363 	kfree(ctx);
364 	return err;
365 }
366 
367 static const struct devlink_ops ixgbe_devlink_ops = {
368 	.info_get = ixgbe_devlink_info_get,
369 };
370 
371 /**
372  * ixgbe_allocate_devlink - Allocate devlink instance
373  * @dev: device to allocate devlink for
374  *
375  * Allocate a devlink instance for this physical function.
376  *
377  * Return: pointer to the device adapter structure on success,
378  * ERR_PTR(-ENOMEM) when allocation failed.
379  */
380 struct ixgbe_adapter *ixgbe_allocate_devlink(struct device *dev)
381 {
382 	struct ixgbe_adapter *adapter;
383 	struct devlink *devlink;
384 
385 	devlink = devlink_alloc(&ixgbe_devlink_ops, sizeof(*adapter), dev);
386 	if (!devlink)
387 		return ERR_PTR(-ENOMEM);
388 
389 	adapter = devlink_priv(devlink);
390 	adapter->devlink = devlink;
391 
392 	return adapter;
393 }
394 
395 /**
396  * ixgbe_devlink_set_switch_id - Set unique switch ID based on PCI DSN
397  * @adapter: pointer to the device adapter structure
398  * @ppid: struct with switch id information
399  */
400 static void ixgbe_devlink_set_switch_id(struct ixgbe_adapter *adapter,
401 					struct netdev_phys_item_id *ppid)
402 {
403 	u64 id = pci_get_dsn(adapter->pdev);
404 
405 	ppid->id_len = sizeof(id);
406 	put_unaligned_be64(id, &ppid->id);
407 }
408 
409 /**
410  * ixgbe_devlink_register_port - Register devlink port
411  * @adapter: pointer to the device adapter structure
412  *
413  * Create and register a devlink_port for this physical function.
414  *
415  * Return: 0 on success, error code on failure.
416  */
417 int ixgbe_devlink_register_port(struct ixgbe_adapter *adapter)
418 {
419 	struct devlink_port *devlink_port = &adapter->devlink_port;
420 	struct devlink *devlink = adapter->devlink;
421 	struct device *dev = &adapter->pdev->dev;
422 	struct devlink_port_attrs attrs = {};
423 	int err;
424 
425 	attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
426 	attrs.phys.port_number = adapter->hw.bus.func;
427 	ixgbe_devlink_set_switch_id(adapter, &attrs.switch_id);
428 
429 	devlink_port_attrs_set(devlink_port, &attrs);
430 
431 	err = devl_port_register(devlink, devlink_port, 0);
432 	if (err) {
433 		dev_err(dev,
434 			"devlink port registration failed, err %d\n", err);
435 	}
436 
437 	return err;
438 }
439