xref: /linux/drivers/net/ethernet/meta/fbnic/fbnic_devlink.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */
3 
4 #include <linux/unaligned.h>
5 #include <linux/pci.h>
6 #include <linux/pldmfw.h>
7 #include <linux/types.h>
8 #include <net/devlink.h>
9 
10 #include "fbnic.h"
11 #include "fbnic_tlv.h"
12 
13 #define FBNIC_SN_STR_LEN	24
14 
fbnic_version_running_put(struct devlink_info_req * req,struct fbnic_fw_ver * fw_ver,char * ver_name)15 static int fbnic_version_running_put(struct devlink_info_req *req,
16 				     struct fbnic_fw_ver *fw_ver,
17 				     char *ver_name)
18 {
19 	char running_ver[FBNIC_FW_VER_MAX_SIZE];
20 	int err;
21 
22 	fbnic_mk_fw_ver_str(fw_ver->version, running_ver);
23 	err = devlink_info_version_running_put(req, ver_name, running_ver);
24 	if (err)
25 		return err;
26 
27 	if (strlen(fw_ver->commit) > 0) {
28 		char commit_name[FBNIC_SN_STR_LEN];
29 
30 		snprintf(commit_name, FBNIC_SN_STR_LEN, "%s.commit", ver_name);
31 		err = devlink_info_version_running_put(req, commit_name,
32 						       fw_ver->commit);
33 		if (err)
34 			return err;
35 	}
36 
37 	return 0;
38 }
39 
fbnic_version_stored_put(struct devlink_info_req * req,struct fbnic_fw_ver * fw_ver,char * ver_name)40 static int fbnic_version_stored_put(struct devlink_info_req *req,
41 				    struct fbnic_fw_ver *fw_ver,
42 				    char *ver_name)
43 {
44 	char stored_ver[FBNIC_FW_VER_MAX_SIZE];
45 	int err;
46 
47 	fbnic_mk_fw_ver_str(fw_ver->version, stored_ver);
48 	err = devlink_info_version_stored_put(req, ver_name, stored_ver);
49 	if (err)
50 		return err;
51 
52 	if (strlen(fw_ver->commit) > 0) {
53 		char commit_name[FBNIC_SN_STR_LEN];
54 
55 		snprintf(commit_name, FBNIC_SN_STR_LEN, "%s.commit", ver_name);
56 		err = devlink_info_version_stored_put(req, commit_name,
57 						      fw_ver->commit);
58 		if (err)
59 			return err;
60 	}
61 
62 	return 0;
63 }
64 
fbnic_devlink_info_get(struct devlink * devlink,struct devlink_info_req * req,struct netlink_ext_ack * extack)65 static int fbnic_devlink_info_get(struct devlink *devlink,
66 				  struct devlink_info_req *req,
67 				  struct netlink_ext_ack *extack)
68 {
69 	struct fbnic_dev *fbd = devlink_priv(devlink);
70 	int err;
71 
72 	err = fbnic_version_running_put(req, &fbd->fw_cap.running.mgmt,
73 					DEVLINK_INFO_VERSION_GENERIC_FW);
74 	if (err)
75 		return err;
76 
77 	err = fbnic_version_running_put(req, &fbd->fw_cap.running.bootloader,
78 					DEVLINK_INFO_VERSION_GENERIC_FW_BOOTLOADER);
79 	if (err)
80 		return err;
81 
82 	err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.mgmt,
83 				       DEVLINK_INFO_VERSION_GENERIC_FW);
84 	if (err)
85 		return err;
86 
87 	err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.bootloader,
88 				       DEVLINK_INFO_VERSION_GENERIC_FW_BOOTLOADER);
89 	if (err)
90 		return err;
91 
92 	err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.undi,
93 				       DEVLINK_INFO_VERSION_GENERIC_FW_UNDI);
94 	if (err)
95 		return err;
96 
97 	if (fbd->dsn) {
98 		unsigned char serial[FBNIC_SN_STR_LEN];
99 		u8 dsn[8];
100 
101 		put_unaligned_be64(fbd->dsn, dsn);
102 		err = snprintf(serial, FBNIC_SN_STR_LEN, "%8phD", dsn);
103 		if (err < 0)
104 			return err;
105 
106 		err = devlink_info_serial_number_put(req, serial);
107 		if (err)
108 			return err;
109 	}
110 
111 	return 0;
112 }
113 
114 static bool
fbnic_pldm_match_record(struct pldmfw * context,struct pldmfw_record * record)115 fbnic_pldm_match_record(struct pldmfw *context, struct pldmfw_record *record)
116 {
117 	struct pldmfw_desc_tlv *desc;
118 	u32 anti_rollback_ver = 0;
119 	struct devlink *devlink;
120 	struct fbnic_dev *fbd;
121 	struct pci_dev *pdev;
122 
123 	/* First, use the standard PCI matching function */
124 	if (!pldmfw_op_pci_match_record(context, record))
125 		return false;
126 
127 	pdev = to_pci_dev(context->dev);
128 	fbd = pci_get_drvdata(pdev);
129 	devlink = priv_to_devlink(fbd);
130 
131 	/* If PCI match is successful, check for vendor-specific descriptors */
132 	list_for_each_entry(desc, &record->descs, entry) {
133 		if (desc->type != PLDM_DESC_ID_VENDOR_DEFINED)
134 			continue;
135 
136 		if (desc->size < 21 || desc->data[0] != 1 ||
137 		    desc->data[1] != 15)
138 			continue;
139 
140 		if (memcmp(desc->data + 2, "AntiRollbackVer", 15) != 0)
141 			continue;
142 
143 		anti_rollback_ver = get_unaligned_le32(desc->data + 17);
144 		break;
145 	}
146 
147 	/* Compare versions and return error if they do not match */
148 	if (anti_rollback_ver < fbd->fw_cap.anti_rollback_version) {
149 		char buf[128];
150 
151 		snprintf(buf, sizeof(buf),
152 			 "New firmware anti-rollback version (0x%x) is older than device version (0x%x)!",
153 			 anti_rollback_ver, fbd->fw_cap.anti_rollback_version);
154 		devlink_flash_update_status_notify(devlink, buf,
155 						   "Anti-Rollback", 0, 0);
156 
157 		return false;
158 	}
159 
160 	return true;
161 }
162 
163 static int
fbnic_flash_start(struct fbnic_dev * fbd,struct pldmfw_component * component)164 fbnic_flash_start(struct fbnic_dev *fbd, struct pldmfw_component *component)
165 {
166 	struct fbnic_fw_completion *cmpl;
167 	int err;
168 
169 	cmpl = fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_FW_START_UPGRADE_REQ);
170 	if (!cmpl)
171 		return -ENOMEM;
172 
173 	err = fbnic_fw_xmit_fw_start_upgrade(fbd, cmpl,
174 					     component->identifier,
175 					     component->component_size);
176 	if (err)
177 		goto cmpl_free;
178 
179 	/* Wait for firmware to ack firmware upgrade start */
180 	if (wait_for_completion_timeout(&cmpl->done, 10 * HZ))
181 		err = cmpl->result;
182 	else
183 		err = -ETIMEDOUT;
184 
185 	fbnic_mbx_clear_cmpl(fbd, cmpl);
186 cmpl_free:
187 	fbnic_fw_put_cmpl(cmpl);
188 
189 	return err;
190 }
191 
192 static int
fbnic_flash_component(struct pldmfw * context,struct pldmfw_component * component)193 fbnic_flash_component(struct pldmfw *context,
194 		      struct pldmfw_component *component)
195 {
196 	const u8 *data = component->component_data;
197 	const u32 size = component->component_size;
198 	struct fbnic_fw_completion *cmpl;
199 	const char *component_name;
200 	struct devlink *devlink;
201 	struct fbnic_dev *fbd;
202 	struct pci_dev *pdev;
203 	u32 offset = 0;
204 	u32 length = 0;
205 	char buf[32];
206 	int err;
207 
208 	pdev = to_pci_dev(context->dev);
209 	fbd = pci_get_drvdata(pdev);
210 	devlink = priv_to_devlink(fbd);
211 
212 	switch (component->identifier) {
213 	case QSPI_SECTION_CMRT:
214 		component_name = "boot1";
215 		break;
216 	case QSPI_SECTION_CONTROL_FW:
217 		component_name = "boot2";
218 		break;
219 	case QSPI_SECTION_OPTION_ROM:
220 		component_name = "option-rom";
221 		break;
222 	default:
223 		snprintf(buf, sizeof(buf), "Unknown component ID %u!",
224 			 component->identifier);
225 		devlink_flash_update_status_notify(devlink, buf, NULL, 0,
226 						   size);
227 		return -EINVAL;
228 	}
229 
230 	/* Once firmware receives the request to start upgrading it responds
231 	 * with two messages:
232 	 * 1. An ACK that it received the message and possible error code
233 	 *    indicating that an upgrade is not currently possible.
234 	 * 2. A request for the first chunk of data
235 	 *
236 	 * Setup completions for write before issuing the start message so
237 	 * the driver can catch both messages.
238 	 */
239 	cmpl = fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_FW_WRITE_CHUNK_REQ);
240 	if (!cmpl)
241 		return -ENOMEM;
242 
243 	err = fbnic_mbx_set_cmpl(fbd, cmpl);
244 	if (err)
245 		goto cmpl_free;
246 
247 	devlink_flash_update_timeout_notify(devlink, "Initializing",
248 					    component_name, 15);
249 	err = fbnic_flash_start(fbd, component);
250 	if (err)
251 		goto err_no_msg;
252 
253 	while (offset < size) {
254 		if (!wait_for_completion_timeout(&cmpl->done, 15 * HZ)) {
255 			err = -ETIMEDOUT;
256 			break;
257 		}
258 
259 		err = cmpl->result;
260 		if (err)
261 			break;
262 
263 		/* Verify firmware is requesting the next chunk in the seq. */
264 		if (cmpl->u.fw_update.offset != offset + length) {
265 			err = -EFAULT;
266 			break;
267 		}
268 
269 		offset = cmpl->u.fw_update.offset;
270 		length = cmpl->u.fw_update.length;
271 
272 		if (length > TLV_MAX_DATA || offset + length > size) {
273 			err = -EFAULT;
274 			break;
275 		}
276 
277 		devlink_flash_update_status_notify(devlink, "Flashing",
278 						   component_name,
279 						   offset, size);
280 
281 		/* Mailbox will set length to 0 once it receives the finish
282 		 * message.
283 		 */
284 		if (!length)
285 			continue;
286 
287 		reinit_completion(&cmpl->done);
288 		err = fbnic_fw_xmit_fw_write_chunk(fbd, data, offset, length,
289 						   0);
290 		if (err)
291 			break;
292 	}
293 
294 	if (err) {
295 		fbnic_fw_xmit_fw_write_chunk(fbd, NULL, 0, 0, err);
296 err_no_msg:
297 		snprintf(buf, sizeof(buf), "Mailbox encountered error %d!",
298 			 err);
299 		devlink_flash_update_status_notify(devlink, buf,
300 						   component_name, 0, 0);
301 	}
302 
303 	fbnic_mbx_clear_cmpl(fbd, cmpl);
304 cmpl_free:
305 	fbnic_fw_put_cmpl(cmpl);
306 
307 	return err;
308 }
309 
310 static const struct pldmfw_ops fbnic_pldmfw_ops = {
311 	.match_record = fbnic_pldm_match_record,
312 	.flash_component = fbnic_flash_component,
313 };
314 
315 static int
fbnic_devlink_flash_update(struct devlink * devlink,struct devlink_flash_update_params * params,struct netlink_ext_ack * extack)316 fbnic_devlink_flash_update(struct devlink *devlink,
317 			   struct devlink_flash_update_params *params,
318 			   struct netlink_ext_ack *extack)
319 {
320 	struct fbnic_dev *fbd = devlink_priv(devlink);
321 	const struct firmware *fw = params->fw;
322 	struct device *dev = fbd->dev;
323 	struct pldmfw context;
324 	char *err_msg;
325 	int err;
326 
327 	context.ops = &fbnic_pldmfw_ops;
328 	context.dev = dev;
329 
330 	err = pldmfw_flash_image(&context, fw);
331 	if (err) {
332 		switch (err) {
333 		case -EINVAL:
334 			err_msg = "Invalid image";
335 			break;
336 		case -EOPNOTSUPP:
337 			err_msg = "Unsupported image";
338 			break;
339 		case -ENOMEM:
340 			err_msg = "Out of memory";
341 			break;
342 		case -EFAULT:
343 			err_msg = "Invalid header";
344 			break;
345 		case -ENOENT:
346 			err_msg = "No matching record";
347 			break;
348 		case -ENODEV:
349 			err_msg = "No matching device";
350 			break;
351 		case -ETIMEDOUT:
352 			err_msg = "Timed out waiting for reply";
353 			break;
354 		default:
355 			err_msg = "Unknown error";
356 			break;
357 		}
358 
359 		NL_SET_ERR_MSG_FMT_MOD(extack,
360 				       "Failed to flash PLDM Image: %s (error: %d)",
361 				       err_msg, err);
362 	}
363 
364 	return err;
365 }
366 
367 static const struct devlink_ops fbnic_devlink_ops = {
368 	.info_get	= fbnic_devlink_info_get,
369 	.flash_update	= fbnic_devlink_flash_update,
370 };
371 
fbnic_devlink_free(struct fbnic_dev * fbd)372 void fbnic_devlink_free(struct fbnic_dev *fbd)
373 {
374 	struct devlink *devlink = priv_to_devlink(fbd);
375 
376 	devlink_free(devlink);
377 }
378 
fbnic_devlink_alloc(struct pci_dev * pdev)379 struct fbnic_dev *fbnic_devlink_alloc(struct pci_dev *pdev)
380 {
381 	void __iomem * const *iomap_table;
382 	struct devlink *devlink;
383 	struct fbnic_dev *fbd;
384 
385 	devlink = devlink_alloc(&fbnic_devlink_ops, sizeof(struct fbnic_dev),
386 				&pdev->dev);
387 	if (!devlink)
388 		return NULL;
389 
390 	fbd = devlink_priv(devlink);
391 	pci_set_drvdata(pdev, fbd);
392 	fbd->dev = &pdev->dev;
393 
394 	iomap_table = pcim_iomap_table(pdev);
395 	fbd->uc_addr0 = iomap_table[0];
396 	fbd->uc_addr4 = iomap_table[4];
397 
398 	fbd->dsn = pci_get_dsn(pdev);
399 	fbd->mps = pcie_get_mps(pdev);
400 	fbd->readrq = pcie_get_readrq(pdev);
401 
402 	fbd->mac_addr_boundary = FBNIC_RPC_TCAM_MACDA_DEFAULT_BOUNDARY;
403 
404 	return fbd;
405 }
406 
fbnic_devlink_register(struct fbnic_dev * fbd)407 void fbnic_devlink_register(struct fbnic_dev *fbd)
408 {
409 	struct devlink *devlink = priv_to_devlink(fbd);
410 
411 	devlink_register(devlink);
412 }
413 
fbnic_devlink_unregister(struct fbnic_dev * fbd)414 void fbnic_devlink_unregister(struct fbnic_dev *fbd)
415 {
416 	struct devlink *devlink = priv_to_devlink(fbd);
417 
418 	devlink_unregister(devlink);
419 }
420