xref: /linux/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c (revision 8210ff738077ed3581e022e5cc8721aa041d42cb)
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 };
10 
11 static void ixgbe_info_get_dsn(struct ixgbe_adapter *adapter,
12 			       struct ixgbe_info_ctx *ctx)
13 {
14 	u8 dsn[8];
15 
16 	/* Copy the DSN into an array in Big Endian format */
17 	put_unaligned_be64(pci_get_dsn(adapter->pdev), dsn);
18 
19 	snprintf(ctx->buf, sizeof(ctx->buf), "%8phD", dsn);
20 }
21 
22 static void ixgbe_info_orom_ver(struct ixgbe_adapter *adapter,
23 				struct ixgbe_info_ctx *ctx)
24 {
25 	struct ixgbe_hw *hw = &adapter->hw;
26 	struct ixgbe_nvm_version nvm_ver;
27 
28 	ctx->buf[0] = '\0';
29 
30 	if (hw->mac.type == ixgbe_mac_e610) {
31 		struct ixgbe_orom_info *orom = &adapter->hw.flash.orom;
32 
33 		snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u",
34 			 orom->major, orom->build, orom->patch);
35 		return;
36 	}
37 
38 	ixgbe_get_oem_prod_version(hw, &nvm_ver);
39 	if (nvm_ver.oem_valid) {
40 		snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x",
41 			 nvm_ver.oem_major, nvm_ver.oem_minor,
42 			 nvm_ver.oem_release);
43 
44 		return;
45 	}
46 
47 	ixgbe_get_orom_version(hw, &nvm_ver);
48 	if (nvm_ver.or_valid)
49 		snprintf(ctx->buf, sizeof(ctx->buf), "%d.%d.%d",
50 			 nvm_ver.or_major, nvm_ver.or_build, nvm_ver.or_patch);
51 }
52 
53 static void ixgbe_info_eetrack(struct ixgbe_adapter *adapter,
54 			       struct ixgbe_info_ctx *ctx)
55 {
56 	struct ixgbe_hw *hw = &adapter->hw;
57 	struct ixgbe_nvm_version nvm_ver;
58 
59 	if (hw->mac.type == ixgbe_mac_e610) {
60 		snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x",
61 			 hw->flash.nvm.eetrack);
62 		return;
63 	}
64 
65 	ixgbe_get_oem_prod_version(hw, &nvm_ver);
66 
67 	/* No ETRACK version for OEM */
68 	if (nvm_ver.oem_valid) {
69 		ctx->buf[0] = '\0';
70 		return;
71 	}
72 
73 	ixgbe_get_etk_id(hw, &nvm_ver);
74 	snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", nvm_ver.etk_id);
75 }
76 
77 static void ixgbe_info_fw_api(struct ixgbe_adapter *adapter,
78 			      struct ixgbe_info_ctx *ctx)
79 {
80 	struct ixgbe_hw *hw = &adapter->hw;
81 
82 	snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u",
83 		 hw->api_maj_ver, hw->api_min_ver, hw->api_patch);
84 }
85 
86 static void ixgbe_info_fw_build(struct ixgbe_adapter *adapter,
87 				struct ixgbe_info_ctx *ctx)
88 {
89 	struct ixgbe_hw *hw = &adapter->hw;
90 
91 	snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", hw->fw_build);
92 }
93 
94 static void ixgbe_info_fw_srev(struct ixgbe_adapter *adapter,
95 			       struct ixgbe_info_ctx *ctx)
96 {
97 	struct ixgbe_nvm_info *nvm = &adapter->hw.flash.nvm;
98 
99 	snprintf(ctx->buf, sizeof(ctx->buf), "%u", nvm->srev);
100 }
101 
102 static void ixgbe_info_orom_srev(struct ixgbe_adapter *adapter,
103 				 struct ixgbe_info_ctx *ctx)
104 {
105 	struct ixgbe_orom_info *orom = &adapter->hw.flash.orom;
106 
107 	snprintf(ctx->buf, sizeof(ctx->buf), "%u", orom->srev);
108 }
109 
110 static void ixgbe_info_nvm_ver(struct ixgbe_adapter *adapter,
111 			       struct ixgbe_info_ctx *ctx)
112 {
113 	struct ixgbe_nvm_info *nvm = &adapter->hw.flash.nvm;
114 
115 	snprintf(ctx->buf, sizeof(ctx->buf), "%x.%02x", nvm->major, nvm->minor);
116 }
117 
118 static void ixgbe_info_netlist_ver(struct ixgbe_adapter *adapter,
119 				   struct ixgbe_info_ctx *ctx)
120 {
121 	struct ixgbe_netlist_info *netlist = &adapter->hw.flash.netlist;
122 
123 	/* The netlist version fields are BCD formatted */
124 	snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x-%x.%x.%x",
125 		 netlist->major, netlist->minor,
126 		 netlist->type >> 16, netlist->type & 0xFFFF,
127 		 netlist->rev, netlist->cust_ver);
128 }
129 
130 static void ixgbe_info_netlist_build(struct ixgbe_adapter *adapter,
131 				     struct ixgbe_info_ctx *ctx)
132 {
133 	struct ixgbe_netlist_info *netlist = &adapter->hw.flash.netlist;
134 
135 	snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", netlist->hash);
136 }
137 
138 static int ixgbe_devlink_info_get_e610(struct ixgbe_adapter *adapter,
139 				       struct devlink_info_req *req,
140 				       struct ixgbe_info_ctx *ctx)
141 {
142 	int err;
143 
144 	ixgbe_info_fw_api(adapter, ctx);
145 	err = devlink_info_version_running_put(req,
146 					       DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API,
147 					       ctx->buf);
148 	if (err)
149 		return err;
150 
151 	ixgbe_info_fw_build(adapter, ctx);
152 	err = devlink_info_version_running_put(req, "fw.mgmt.build", ctx->buf);
153 	if (err)
154 		return err;
155 
156 	ixgbe_info_fw_srev(adapter, ctx);
157 	err = devlink_info_version_running_put(req, "fw.mgmt.srev", ctx->buf);
158 	if (err)
159 		return err;
160 
161 	ixgbe_info_orom_srev(adapter, ctx);
162 	err = devlink_info_version_running_put(req, "fw.undi.srev", ctx->buf);
163 	if (err)
164 		return err;
165 
166 	ixgbe_info_nvm_ver(adapter, ctx);
167 	err = devlink_info_version_running_put(req, "fw.psid.api", ctx->buf);
168 	if (err)
169 		return err;
170 
171 	ixgbe_info_netlist_ver(adapter, ctx);
172 	err = devlink_info_version_running_put(req, "fw.netlist", ctx->buf);
173 	if (err)
174 		return err;
175 
176 	ixgbe_info_netlist_build(adapter, ctx);
177 	return devlink_info_version_running_put(req, "fw.netlist.build",
178 						ctx->buf);
179 }
180 
181 static int ixgbe_devlink_info_get(struct devlink *devlink,
182 				  struct devlink_info_req *req,
183 				  struct netlink_ext_ack *extack)
184 {
185 	struct ixgbe_adapter *adapter = devlink_priv(devlink);
186 	struct ixgbe_hw *hw = &adapter->hw;
187 	struct ixgbe_info_ctx *ctx;
188 	int err;
189 
190 	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
191 	if (!ctx)
192 		return -ENOMEM;
193 
194 	ixgbe_info_get_dsn(adapter, ctx);
195 	err = devlink_info_serial_number_put(req, ctx->buf);
196 	if (err)
197 		goto free_ctx;
198 
199 	err = ixgbe_read_pba_string_generic(hw, ctx->buf, sizeof(ctx->buf));
200 	if (err)
201 		goto free_ctx;
202 
203 	err = devlink_info_version_fixed_put(req,
204 					     DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
205 					     ctx->buf);
206 	if (err)
207 		goto free_ctx;
208 
209 	ixgbe_info_orom_ver(adapter, ctx);
210 	err = devlink_info_version_running_put(req,
211 					       DEVLINK_INFO_VERSION_GENERIC_FW_UNDI,
212 					       ctx->buf);
213 	if (err)
214 		goto free_ctx;
215 
216 	ixgbe_info_eetrack(adapter, ctx);
217 	err = devlink_info_version_running_put(req,
218 					       DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
219 					       ctx->buf);
220 	if (err || hw->mac.type != ixgbe_mac_e610)
221 		goto free_ctx;
222 
223 	err = ixgbe_devlink_info_get_e610(adapter, req, ctx);
224 free_ctx:
225 	kfree(ctx);
226 	return err;
227 }
228 
229 static const struct devlink_ops ixgbe_devlink_ops = {
230 	.info_get = ixgbe_devlink_info_get,
231 };
232 
233 /**
234  * ixgbe_allocate_devlink - Allocate devlink instance
235  * @dev: device to allocate devlink for
236  *
237  * Allocate a devlink instance for this physical function.
238  *
239  * Return: pointer to the device adapter structure on success,
240  * ERR_PTR(-ENOMEM) when allocation failed.
241  */
242 struct ixgbe_adapter *ixgbe_allocate_devlink(struct device *dev)
243 {
244 	struct ixgbe_adapter *adapter;
245 	struct devlink *devlink;
246 
247 	devlink = devlink_alloc(&ixgbe_devlink_ops, sizeof(*adapter), dev);
248 	if (!devlink)
249 		return ERR_PTR(-ENOMEM);
250 
251 	adapter = devlink_priv(devlink);
252 	adapter->devlink = devlink;
253 
254 	return adapter;
255 }
256 
257 /**
258  * ixgbe_devlink_set_switch_id - Set unique switch ID based on PCI DSN
259  * @adapter: pointer to the device adapter structure
260  * @ppid: struct with switch id information
261  */
262 static void ixgbe_devlink_set_switch_id(struct ixgbe_adapter *adapter,
263 					struct netdev_phys_item_id *ppid)
264 {
265 	u64 id = pci_get_dsn(adapter->pdev);
266 
267 	ppid->id_len = sizeof(id);
268 	put_unaligned_be64(id, &ppid->id);
269 }
270 
271 /**
272  * ixgbe_devlink_register_port - Register devlink port
273  * @adapter: pointer to the device adapter structure
274  *
275  * Create and register a devlink_port for this physical function.
276  *
277  * Return: 0 on success, error code on failure.
278  */
279 int ixgbe_devlink_register_port(struct ixgbe_adapter *adapter)
280 {
281 	struct devlink_port *devlink_port = &adapter->devlink_port;
282 	struct devlink *devlink = adapter->devlink;
283 	struct device *dev = &adapter->pdev->dev;
284 	struct devlink_port_attrs attrs = {};
285 	int err;
286 
287 	attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
288 	attrs.phys.port_number = adapter->hw.bus.func;
289 	ixgbe_devlink_set_switch_id(adapter, &attrs.switch_id);
290 
291 	devlink_port_attrs_set(devlink_port, &attrs);
292 
293 	err = devl_port_register(devlink, devlink_port, 0);
294 	if (err) {
295 		dev_err(dev,
296 			"devlink port registration failed, err %d\n", err);
297 	}
298 
299 	return err;
300 }
301