xref: /dpdk/drivers/net/nfp/nfpcore/nfp_nsp.c (revision e77506397fc8005c5129e22e9e2d15d5876790fd)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Netronome Systems, Inc.
3  * All rights reserved.
4  */
5 
6 #include "nfp_nsp.h"
7 
8 #include <nfp_platform.h>
9 #include <rte_common.h>
10 
11 #include "nfp_logs.h"
12 #include "nfp_resource.h"
13 
14 /* Offsets relative to the CSR base */
15 #define NSP_STATUS              0x00
16 #define   NSP_STATUS_MAGIC      GENMASK_ULL(63, 48)
17 #define   NSP_STATUS_MAJOR      GENMASK_ULL(47, 44)
18 #define   NSP_STATUS_MINOR      GENMASK_ULL(43, 32)
19 #define   NSP_STATUS_CODE       GENMASK_ULL(31, 16)
20 #define   NSP_STATUS_RESULT     GENMASK_ULL(15, 8)
21 #define   NSP_STATUS_BUSY       RTE_BIT64(0)
22 
23 #define NSP_COMMAND             0x08
24 #define   NSP_COMMAND_OPTION    GENMASK_ULL(63, 32)
25 #define   NSP_COMMAND_VER_MAJOR GENMASK_ULL(31, 28)
26 #define   NSP_COMMAND_CODE      GENMASK_ULL(27, 16)
27 #define   NSP_COMMAND_DMA_BUF   RTE_BIT64(1)
28 #define   NSP_COMMAND_START     RTE_BIT64(0)
29 
30 /* CPP address to retrieve the data from */
31 #define NSP_BUFFER              0x10
32 #define   NSP_BUFFER_CPP        GENMASK_ULL(63, 40)
33 #define   NSP_BUFFER_ADDRESS    GENMASK_ULL(39, 0)
34 
35 #define NSP_DFLT_BUFFER         0x18
36 #define   NSP_DFLT_BUFFER_CPP          GENMASK_ULL(63, 40)
37 #define   NSP_DFLT_BUFFER_ADDRESS      GENMASK_ULL(39, 0)
38 
39 #define NSP_DFLT_BUFFER_CONFIG  0x20
40 #define   NSP_DFLT_BUFFER_SIZE_4KB     GENMASK_ULL(15, 8)
41 #define   NSP_DFLT_BUFFER_SIZE_MB      GENMASK_ULL(7, 0)
42 
43 #define NSP_MAGIC               0xab10
44 
45 /*
46  * ABI major version is bumped separately without resetting minor
47  * version when the change in NSP is not compatible to old driver.
48  */
49 #define NSP_MAJOR               1
50 
51 /*
52  * ABI minor version is bumped when new feature is introduced
53  * while old driver can still work without this new feature.
54  */
55 #define NSP_MINOR               8
56 
57 #define NSP_CODE_MAJOR          GENMASK_ULL(15, 12)
58 #define NSP_CODE_MINOR          GENMASK_ULL(11, 0)
59 
60 #define NFP_FW_LOAD_RET_MAJOR   GENMASK_ULL(15, 8)
61 #define NFP_FW_LOAD_RET_MINOR   GENMASK_ULL(23, 16)
62 
63 #define NFP_HWINFO_LOOKUP_SIZE  GENMASK_ULL(11, 0)
64 
65 enum nfp_nsp_cmd {
66 	SPCODE_NOOP             = 0, /* No operation */
67 	SPCODE_SOFT_RESET       = 1, /* Soft reset the NFP */
68 	SPCODE_FW_DEFAULT       = 2, /* Load default (UNDI) FW */
69 	SPCODE_PHY_INIT         = 3, /* Initialize the PHY */
70 	SPCODE_MAC_INIT         = 4, /* Initialize the MAC */
71 	SPCODE_PHY_RXADAPT      = 5, /* Re-run PHY RX Adaptation */
72 	SPCODE_FW_LOAD          = 6, /* Load fw from buffer, len in option */
73 	SPCODE_ETH_RESCAN       = 7, /* Rescan ETHs, write ETH_TABLE to buf */
74 	SPCODE_ETH_CONTROL      = 8, /* Update media config from buffer */
75 	SPCODE_NSP_WRITE_FLASH  = 11, /* Load and flash image from buffer */
76 	SPCODE_NSP_SENSORS      = 12, /* Read NSP sensor(s) */
77 	SPCODE_NSP_IDENTIFY     = 13, /* Read NSP version */
78 	SPCODE_FW_STORED        = 16, /* If no FW loaded, load flash app FW */
79 	SPCODE_HWINFO_LOOKUP    = 17, /* Lookup HWinfo with overwrites etc. */
80 	SPCODE_HWINFO_SET       = 18, /* Set HWinfo entry */
81 	SPCODE_FW_LOADED        = 19, /* Is application firmware loaded */
82 	SPCODE_VERSIONS         = 21, /* Report FW versions */
83 	SPCODE_READ_SFF_EEPROM  = 22, /* Read module EEPROM */
84 	SPCODE_READ_MEDIA       = 23, /* Get the supported/advertised media for a port */
85 	SPCODE_DEV_ACTIVATE	= 29, /* Activate hardware for multiple pfs case */
86 };
87 
88 static const struct {
89 	uint32_t code;
90 	const char *msg;
91 } nsp_errors[] = {
92 	{ 6010, "could not map to phy for port" },
93 	{ 6011, "not an allowed rate/lanes for port" },
94 	{ 6012, "not an allowed rate/lanes for port" },
95 	{ 6013, "high/low error, change other port first" },
96 	{ 6014, "config not found in flash" },
97 };
98 
99 struct nfp_nsp {
100 	struct nfp_cpp *cpp;
101 	struct nfp_resource *res;
102 	struct {
103 		uint16_t major;
104 		uint16_t minor;
105 	} ver;
106 
107 	/** Eth table config state */
108 	bool modified;
109 	uint32_t idx;
110 	void *entries;
111 };
112 
113 /* NFP command argument structure */
114 struct nfp_nsp_command_arg {
115 	uint16_t code;         /**< NFP SP Command Code */
116 	bool dma;              /**< @buf points to a host buffer, not NSP buffer */
117 	bool error_quiet;      /**< Don't print command error/warning */
118 	uint32_t timeout_sec;  /**< Timeout value to wait for completion in seconds */
119 	uint32_t option;       /**< NSP Command Argument */
120 	uint64_t buf;          /**< NSP Buffer Address */
121 	/** Callback for interpreting option if error occurred */
122 	void (*error_cb)(struct nfp_nsp *state, uint32_t ret_val);
123 };
124 
125 /* NFP command with buffer argument structure */
126 struct nfp_nsp_command_buf_arg {
127 	struct nfp_nsp_command_arg arg;  /**< NFP command argument structure */
128 	const void *in_buf;              /**< Buffer with data for input */
129 	void *out_buf;                   /**< Buffer for output data */
130 	uint32_t in_size;                /**< Size of @in_buf */
131 	uint32_t out_size;               /**< Size of @out_buf */
132 };
133 
134 struct nfp_cpp *
135 nfp_nsp_cpp(struct nfp_nsp *state)
136 {
137 	return state->cpp;
138 }
139 
140 bool
141 nfp_nsp_config_modified(struct nfp_nsp *state)
142 {
143 	return state->modified;
144 }
145 
146 void
147 nfp_nsp_config_set_modified(struct nfp_nsp *state,
148 		bool modified)
149 {
150 	state->modified = modified;
151 }
152 
153 void *
154 nfp_nsp_config_entries(struct nfp_nsp *state)
155 {
156 	return state->entries;
157 }
158 
159 uint32_t
160 nfp_nsp_config_idx(struct nfp_nsp *state)
161 {
162 	return state->idx;
163 }
164 
165 void
166 nfp_nsp_config_set_state(struct nfp_nsp *state,
167 		void *entries,
168 		uint32_t idx)
169 {
170 	state->entries = entries;
171 	state->idx = idx;
172 }
173 
174 void
175 nfp_nsp_config_clear_state(struct nfp_nsp *state)
176 {
177 	state->entries = NULL;
178 	state->idx = 0;
179 }
180 
181 static void
182 nfp_nsp_print_extended_error(uint32_t ret_val)
183 {
184 	uint32_t i;
185 
186 	if (ret_val == 0)
187 		return;
188 
189 	for (i = 0; i < RTE_DIM(nsp_errors); i++)
190 		if (ret_val == nsp_errors[i].code)
191 			PMD_DRV_LOG(ERR, "Err msg: %s.", nsp_errors[i].msg);
192 }
193 
194 static int
195 nfp_nsp_check(struct nfp_nsp *state)
196 {
197 	int err;
198 	uint64_t reg;
199 	uint32_t nsp_cpp;
200 	uint64_t nsp_status;
201 	struct nfp_cpp *cpp = state->cpp;
202 
203 	nsp_cpp = nfp_resource_cpp_id(state->res);
204 	nsp_status = nfp_resource_address(state->res) + NSP_STATUS;
205 
206 	err = nfp_cpp_readq(cpp, nsp_cpp, nsp_status, &reg);
207 	if (err < 0) {
208 		PMD_DRV_LOG(ERR, "NSP - CPP readq failed %d.", err);
209 		return err;
210 	}
211 
212 	if (FIELD_GET(NSP_STATUS_MAGIC, reg) != NSP_MAGIC) {
213 		PMD_DRV_LOG(ERR, "Can not detect NFP Service Processor.");
214 		return -ENODEV;
215 	}
216 
217 	state->ver.major = FIELD_GET(NSP_STATUS_MAJOR, reg);
218 	state->ver.minor = FIELD_GET(NSP_STATUS_MINOR, reg);
219 
220 	if (state->ver.major > NSP_MAJOR || state->ver.minor < NSP_MINOR) {
221 		PMD_DRV_LOG(ERR, "Unsupported ABI %hu.%hu.", state->ver.major,
222 				state->ver.minor);
223 		return -EINVAL;
224 	}
225 
226 	if ((reg & NSP_STATUS_BUSY) != 0) {
227 		PMD_DRV_LOG(DEBUG, "Service processor busy!");
228 		return -EBUSY;
229 	}
230 
231 	return 0;
232 }
233 
234 /**
235  * Prepare for communication and lock the NSP resource.
236  *
237  * @param cpp
238  *   NFP CPP Handle
239  */
240 struct nfp_nsp *
241 nfp_nsp_open(struct nfp_cpp *cpp)
242 {
243 	int err;
244 	struct nfp_nsp *state;
245 	struct nfp_resource *res;
246 
247 	res = nfp_resource_acquire(cpp, NFP_RESOURCE_NSP);
248 	if (res == NULL) {
249 		PMD_DRV_LOG(ERR, "NSP - resource acquire failed.");
250 		return NULL;
251 	}
252 
253 	state = malloc(sizeof(*state));
254 	if (state == NULL) {
255 		PMD_DRV_LOG(ERR, "NSP - failed to malloc name %s", NFP_RESOURCE_NSP);
256 		nfp_resource_release(res);
257 		return NULL;
258 	}
259 	memset(state, 0, sizeof(*state));
260 	state->cpp = cpp;
261 	state->res = res;
262 
263 	err = nfp_nsp_check(state);
264 	if (err != 0) {
265 		PMD_DRV_LOG(DEBUG, "NSP - check failed.");
266 		nfp_nsp_close(state);
267 		return NULL;
268 	}
269 
270 	return state;
271 }
272 
273 /**
274  * Clean up and unlock the NSP resource.
275  *
276  * @param state
277  *   NFP SP state
278  */
279 void
280 nfp_nsp_close(struct nfp_nsp *state)
281 {
282 	nfp_resource_release(state->res);
283 	free(state);
284 }
285 
286 uint16_t
287 nfp_nsp_get_abi_ver_major(struct nfp_nsp *state)
288 {
289 	return state->ver.major;
290 }
291 
292 uint16_t
293 nfp_nsp_get_abi_ver_minor(struct nfp_nsp *state)
294 {
295 	return state->ver.minor;
296 }
297 
298 static int
299 nfp_nsp_wait_reg(struct nfp_cpp *cpp,
300 		uint64_t *reg,
301 		uint32_t nsp_cpp,
302 		uint64_t addr,
303 		uint64_t mask,
304 		uint64_t val)
305 {
306 	int err;
307 	uint32_t count = 0;
308 	struct timespec wait;
309 
310 	wait.tv_sec = 0;
311 	wait.tv_nsec = 25000000;     /* 25ms */
312 
313 	for (;;) {
314 		err = nfp_cpp_readq(cpp, nsp_cpp, addr, reg);
315 		if (err < 0) {
316 			PMD_DRV_LOG(ERR, "NSP - CPP readq failed.");
317 			return err;
318 		}
319 
320 		if ((*reg & mask) == val)
321 			return 0;
322 
323 		nanosleep(&wait, 0);
324 		if (count++ > 1000)     /* 25ms * 1000 = 25s */
325 			return -ETIMEDOUT;
326 	}
327 }
328 
329 /**
330  * Execute a command on the NFP Service Processor
331  *
332  * @param state
333  *   NFP SP state
334  * @param arg
335  *   NFP command argument structure
336  *
337  * @return
338  *   - 0 for success with no result
339  *   - Positive value for NSP completion with a result code
340  *   - -EAGAIN if the NSP is not yet present
341  *   - -ENODEV if the NSP is not a supported model
342  *   - -EBUSY if the NSP is stuck
343  *   - -EINTR if interrupted while waiting for completion
344  *   - -ETIMEDOUT if the NSP took longer than @timeout_sec seconds to complete
345  */
346 static int
347 nfp_nsp_command_real(struct nfp_nsp *state,
348 		const struct nfp_nsp_command_arg *arg)
349 {
350 	int err;
351 	uint64_t reg;
352 	uint32_t nsp_cpp;
353 	uint64_t ret_val;
354 	uint64_t nsp_base;
355 	uint64_t nsp_buffer;
356 	uint64_t nsp_status;
357 	uint64_t nsp_command;
358 	struct nfp_cpp *cpp = state->cpp;
359 
360 	nsp_cpp = nfp_resource_cpp_id(state->res);
361 	nsp_base = nfp_resource_address(state->res);
362 	nsp_status = nsp_base + NSP_STATUS;
363 	nsp_command = nsp_base + NSP_COMMAND;
364 	nsp_buffer = nsp_base + NSP_BUFFER;
365 
366 	err = nfp_nsp_check(state);
367 	if (err != 0) {
368 		PMD_DRV_LOG(ERR, "Check NSP command failed.");
369 		return err;
370 	}
371 
372 	err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_buffer, arg->buf);
373 	if (err < 0) {
374 		PMD_DRV_LOG(ERR, "CPP write buffer failed. err %d", err);
375 		return err;
376 	}
377 
378 	err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_command,
379 			FIELD_PREP(NSP_COMMAND_OPTION, arg->option) |
380 			FIELD_PREP(NSP_COMMAND_VER_MAJOR, state->ver.major) |
381 			FIELD_PREP(NSP_COMMAND_CODE, arg->code) |
382 			FIELD_PREP(NSP_COMMAND_DMA_BUF, arg->dma) |
383 			FIELD_PREP(NSP_COMMAND_START, 1));
384 	if (err < 0) {
385 		PMD_DRV_LOG(ERR, "CPP write command failed. err %d", err);
386 		return err;
387 	}
388 
389 	/* Wait for NSP_COMMAND_START to go to 0 */
390 	err = nfp_nsp_wait_reg(cpp, &reg, nsp_cpp, nsp_command,
391 			NSP_COMMAND_START, 0);
392 	if (err != 0) {
393 		PMD_DRV_LOG(ERR, "Error %d waiting for code %#04x to start.",
394 				err, arg->code);
395 		return err;
396 	}
397 
398 	/* Wait for NSP_STATUS_BUSY to go to 0 */
399 	err = nfp_nsp_wait_reg(cpp, &reg, nsp_cpp, nsp_status,
400 			NSP_STATUS_BUSY, 0);
401 	if (err != 0) {
402 		PMD_DRV_LOG(ERR, "Error %d waiting for code %#04x to complete.",
403 				err, arg->code);
404 		return err;
405 	}
406 
407 	err = nfp_cpp_readq(cpp, nsp_cpp, nsp_command, &ret_val);
408 	if (err < 0) {
409 		PMD_DRV_LOG(ERR, "CPP read return value failed. err %d", err);
410 		return err;
411 	}
412 
413 	ret_val = FIELD_GET(NSP_COMMAND_OPTION, ret_val);
414 
415 	err = FIELD_GET(NSP_STATUS_RESULT, reg);
416 	if (err != 0) {
417 		if (!arg->error_quiet)
418 			PMD_DRV_LOG(ERR, "Result (error) code set: %d (%d) command: %d.",
419 					-err, (int)ret_val, arg->code);
420 
421 		if (arg->error_cb != 0)
422 			arg->error_cb(state, ret_val);
423 		else
424 			nfp_nsp_print_extended_error(ret_val);
425 
426 		return -err;
427 	}
428 
429 	return ret_val;
430 }
431 
432 static int
433 nfp_nsp_command(struct nfp_nsp *state,
434 		uint16_t code)
435 {
436 	const struct nfp_nsp_command_arg arg = {
437 		.code = code,
438 	};
439 
440 	return nfp_nsp_command_real(state, &arg);
441 }
442 
443 static int
444 nfp_nsp_command_buf_def(struct nfp_nsp *nsp,
445 		struct nfp_nsp_command_buf_arg *arg)
446 {
447 	int err;
448 	int ret;
449 	uint64_t reg;
450 	uint32_t cpp_id;
451 	uint64_t cpp_buf;
452 	struct nfp_cpp *cpp = nsp->cpp;
453 
454 	err = nfp_cpp_readq(cpp, nfp_resource_cpp_id(nsp->res),
455 			nfp_resource_address(nsp->res) + NSP_DFLT_BUFFER,
456 			&reg);
457 	if (err < 0)
458 		return err;
459 
460 	cpp_id = FIELD_GET(NSP_DFLT_BUFFER_CPP, reg) << 8;
461 	cpp_buf = FIELD_GET(NSP_DFLT_BUFFER_ADDRESS, reg);
462 
463 	if (arg->in_buf != NULL && arg->in_size > 0) {
464 		err = nfp_cpp_write(cpp, cpp_id, cpp_buf,
465 				arg->in_buf, arg->in_size);
466 		if (err < 0)
467 			return err;
468 	}
469 
470 	/* Zero out remaining part of the buffer */
471 	if (arg->out_buf != NULL && arg->out_size > arg->in_size) {
472 		err = nfp_cpp_write(cpp, cpp_id, cpp_buf + arg->in_size,
473 				arg->out_buf, arg->out_size - arg->in_size);
474 		if (err < 0)
475 			return err;
476 	}
477 
478 	if (!FIELD_FIT(NSP_BUFFER_CPP, cpp_id >> 8) ||
479 			!FIELD_FIT(NSP_BUFFER_ADDRESS, cpp_buf)) {
480 		PMD_DRV_LOG(ERR, "Buffer out of reach %#08x %#016lx.",
481 				cpp_id, cpp_buf);
482 		return -EINVAL;
483 	}
484 
485 	arg->arg.buf = FIELD_PREP(NSP_BUFFER_CPP, cpp_id >> 8) |
486 			FIELD_PREP(NSP_BUFFER_ADDRESS, cpp_buf);
487 	ret = nfp_nsp_command_real(nsp, &arg->arg);
488 	if (ret < 0) {
489 		if (!arg->arg.error_quiet)
490 			PMD_DRV_LOG(ERR, "NSP command failed.");
491 
492 		return ret;
493 	}
494 
495 	if (arg->out_buf != NULL && arg->out_size > 0) {
496 		err = nfp_cpp_read(cpp, cpp_id, cpp_buf,
497 				arg->out_buf, arg->out_size);
498 		if (err < 0)
499 			return err;
500 	}
501 
502 	return ret;
503 }
504 
505 #define SZ_1M 0x00100000
506 #define SZ_4K 0x00001000
507 
508 static int
509 nfp_nsp_command_buf(struct nfp_nsp *nsp,
510 		struct nfp_nsp_command_buf_arg *arg)
511 {
512 	int err;
513 	size_t size;
514 	uint64_t reg;
515 	size_t max_size;
516 	struct nfp_cpp *cpp = nsp->cpp;
517 
518 	if (nsp->ver.minor < 13) {
519 		PMD_DRV_LOG(ERR, "NSP: Code %#04x with buffer not supported ABI %hu.%hu).",
520 				arg->arg.code, nsp->ver.major, nsp->ver.minor);
521 		return -EOPNOTSUPP;
522 	}
523 
524 	err = nfp_cpp_readq(cpp, nfp_resource_cpp_id(nsp->res),
525 			nfp_resource_address(nsp->res) + NSP_DFLT_BUFFER_CONFIG,
526 			&reg);
527 	if (err < 0)
528 		return err;
529 
530 	max_size = RTE_MAX(arg->in_size, arg->out_size);
531 	size = FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M +
532 			FIELD_GET(NSP_DFLT_BUFFER_SIZE_4KB, reg) * SZ_4K;
533 	if (size < max_size) {
534 		PMD_DRV_LOG(ERR, "NSP: default buffer too small for command %#04x (%zu < %zu).",
535 				arg->arg.code, size, max_size);
536 		return -EINVAL;
537 	}
538 
539 	return nfp_nsp_command_buf_def(nsp, arg);
540 }
541 
542 int
543 nfp_nsp_wait(struct nfp_nsp *state)
544 {
545 	int err;
546 	int count = 0;
547 	struct timespec wait;
548 
549 	wait.tv_sec = 0;
550 	wait.tv_nsec = 25000000;    /* 25ms */
551 
552 	for (;;) {
553 		err = nfp_nsp_command(state, SPCODE_NOOP);
554 		if (err != -EAGAIN)
555 			break;
556 
557 		nanosleep(&wait, 0);
558 
559 		if (count++ > 1000) {    /* 25ms * 1000 = 25s */
560 			err = -ETIMEDOUT;
561 			break;
562 		}
563 	}
564 
565 	if (err != 0)
566 		PMD_DRV_LOG(ERR, "NSP failed to respond %d.", err);
567 
568 	return err;
569 }
570 
571 int
572 nfp_nsp_device_soft_reset(struct nfp_nsp *state)
573 {
574 	return nfp_nsp_command(state, SPCODE_SOFT_RESET);
575 }
576 
577 int
578 nfp_nsp_mac_reinit(struct nfp_nsp *state)
579 {
580 	return nfp_nsp_command(state, SPCODE_MAC_INIT);
581 }
582 
583 static void
584 nfp_nsp_load_fw_extended_msg(struct nfp_nsp *state,
585 		uint32_t ret_val)
586 {
587 	uint32_t minor;
588 	uint32_t major;
589 	static const char * const major_msg[] = {
590 		/* 0 */ "Firmware from driver loaded",
591 		/* 1 */ "Firmware from flash loaded",
592 		/* 2 */ "Firmware loading failure",
593 	};
594 	static const char * const minor_msg[] = {
595 		/*  0 */ "",
596 		/*  1 */ "no named partition on flash",
597 		/*  2 */ "error reading from flash",
598 		/*  3 */ "can not deflate",
599 		/*  4 */ "not a trusted file",
600 		/*  5 */ "can not parse FW file",
601 		/*  6 */ "MIP not found in FW file",
602 		/*  7 */ "null firmware name in MIP",
603 		/*  8 */ "FW version none",
604 		/*  9 */ "FW build number none",
605 		/* 10 */ "no FW selection policy HWInfo key found",
606 		/* 11 */ "static FW selection policy",
607 		/* 12 */ "FW version has precedence",
608 		/* 13 */ "different FW application load requested",
609 		/* 14 */ "development build",
610 	};
611 
612 	major = FIELD_GET(NFP_FW_LOAD_RET_MAJOR, ret_val);
613 	minor = FIELD_GET(NFP_FW_LOAD_RET_MINOR, ret_val);
614 
615 	if (!nfp_nsp_has_stored_fw_load(state))
616 		return;
617 
618 	if (major >= RTE_DIM(major_msg))
619 		PMD_DRV_LOG(INFO, "FW loading status: %x.", ret_val);
620 	else if (minor >= RTE_DIM(minor_msg))
621 		PMD_DRV_LOG(INFO, "%s, reason code: %d.", major_msg[major], minor);
622 	else
623 		PMD_DRV_LOG(INFO, "%s%c %s", major_msg[major],
624 				minor != 0 ? ',' : '.', minor_msg[minor]);
625 }
626 
627 int
628 nfp_nsp_load_fw(struct nfp_nsp *state,
629 		void *buf,
630 		size_t size)
631 {
632 	int ret;
633 	struct nfp_nsp_command_buf_arg load_fw = {
634 		{
635 			.code     = SPCODE_FW_LOAD,
636 			.option   = size,
637 			.error_cb = nfp_nsp_load_fw_extended_msg,
638 		},
639 		.in_buf  = buf,
640 		.in_size = size,
641 	};
642 
643 	ret = nfp_nsp_command_buf(state, &load_fw);
644 	if (ret < 0)
645 		return ret;
646 
647 	nfp_nsp_load_fw_extended_msg(state, ret);
648 
649 	return 0;
650 }
651 
652 bool
653 nfp_nsp_fw_loaded(struct nfp_nsp *state)
654 {
655 	return nfp_nsp_command(state, SPCODE_FW_LOADED) > 0;
656 }
657 
658 int
659 nfp_nsp_read_eth_table(struct nfp_nsp *state,
660 		void *buf,
661 		size_t size)
662 {
663 	struct nfp_nsp_command_buf_arg eth_rescan = {
664 		{
665 			.code   = SPCODE_ETH_RESCAN,
666 			.option = size,
667 		},
668 		.out_buf  = buf,
669 		.out_size = size,
670 	};
671 
672 	return nfp_nsp_command_buf(state, &eth_rescan);
673 }
674 
675 int
676 nfp_nsp_write_eth_table(struct nfp_nsp *state,
677 		const void *buf,
678 		size_t size)
679 {
680 	struct nfp_nsp_command_buf_arg eth_ctrl = {
681 		{
682 			.code   = SPCODE_ETH_CONTROL,
683 			.option = size,
684 		},
685 		.in_buf  = buf,
686 		.in_size = size,
687 	};
688 
689 	return nfp_nsp_command_buf(state, &eth_ctrl);
690 }
691 
692 int
693 nfp_nsp_read_identify(struct nfp_nsp *state,
694 		void *buf,
695 		size_t size)
696 {
697 	struct nfp_nsp_command_buf_arg identify = {
698 		{
699 			.code   = SPCODE_NSP_IDENTIFY,
700 			.option = size,
701 		},
702 		.out_buf  = buf,
703 		.out_size = size,
704 	};
705 
706 	return nfp_nsp_command_buf(state, &identify);
707 }
708 
709 int
710 nfp_nsp_read_sensors(struct nfp_nsp *state,
711 		uint32_t sensor_mask,
712 		void *buf,
713 		size_t size)
714 {
715 	struct nfp_nsp_command_buf_arg sensors = {
716 		{
717 			.code   = SPCODE_NSP_SENSORS,
718 			.option = sensor_mask,
719 		},
720 		.out_buf  = buf,
721 		.out_size = size,
722 	};
723 
724 	return nfp_nsp_command_buf(state, &sensors);
725 }
726 
727 int
728 nfp_nsp_hwinfo_set(struct nfp_nsp *state,
729 		const void *buf,
730 		size_t size)
731 {
732 	struct nfp_nsp_command_buf_arg hwinfo_set = {
733 		{
734 			.code   = SPCODE_HWINFO_SET,
735 			.option = size,
736 		},
737 		.in_buf  = buf,
738 		.in_size = size,
739 	};
740 
741 	return nfp_nsp_command_buf(state, &hwinfo_set);
742 }
743 
744 int
745 nfp_nsp_device_activate(struct nfp_nsp *state)
746 {
747 	if (nfp_nsp_get_abi_ver_minor(state) < 38)
748 		return -EOPNOTSUPP;
749 
750 	return nfp_nsp_command(state, SPCODE_DEV_ACTIVATE);
751 }
752 
753 int
754 nfp_nsp_read_media(struct nfp_nsp *state,
755 		void *buf,
756 		size_t size)
757 {
758 	struct nfp_nsp_command_buf_arg media = {
759 		{
760 			.code   = SPCODE_READ_MEDIA,
761 			.option = size,
762 		},
763 		.out_buf  = buf,
764 		.out_size = size,
765 	};
766 
767 	return nfp_nsp_command_buf(state, &media);
768 }
769 
770 int
771 nfp_nsp_load_stored_fw(struct nfp_nsp *state)
772 {
773 	int ret;
774 	struct nfp_nsp_command_buf_arg fw_stored = {
775 		{
776 			.code     = SPCODE_FW_STORED,
777 			.error_cb = nfp_nsp_load_fw_extended_msg,
778 		},
779 	};
780 
781 	ret = nfp_nsp_command_buf(state, &fw_stored);
782 	if (ret < 0)
783 		return ret;
784 
785 	nfp_nsp_load_fw_extended_msg(state, ret);
786 
787 	return 0;
788 }
789 
790 static int
791 nfp_nsp_hwinfo_lookup_real(struct nfp_nsp *state,
792 		void *buf,
793 		size_t size,
794 		bool optional)
795 {
796 	struct nfp_nsp_command_buf_arg hwinfo_lookup = {
797 		{
798 			.code   = SPCODE_HWINFO_LOOKUP,
799 			.option = size,
800 			.error_quiet = optional,
801 		},
802 		.in_buf = buf,
803 		.in_size = size,
804 		.out_buf  = buf,
805 		.out_size = size,
806 	};
807 
808 	return nfp_nsp_command_buf(state, &hwinfo_lookup);
809 }
810 
811 static int
812 nfp_nsp_read_module_eeprom_real(struct nfp_nsp *state,
813 		void *buf,
814 		uint32_t size)
815 {
816 	struct nfp_nsp_command_buf_arg module_eeprom = {
817 		{
818 			.code   = SPCODE_READ_SFF_EEPROM,
819 			.option = size,
820 		},
821 		.in_buf         = buf,
822 		.in_size        = size,
823 		.out_buf        = buf,
824 		.out_size       = size,
825 	};
826 
827 	return nfp_nsp_command_buf(state, &module_eeprom);
828 }
829 
830 int
831 nfp_nsp_read_module_eeprom(struct nfp_nsp *state,
832 		int eth_index,
833 		uint32_t offset,
834 		void *data,
835 		uint32_t len,
836 		uint32_t *read_len)
837 {
838 	int ret;
839 	int bufsz;
840 	struct __rte_packed_begin eeprom_buf {
841 		uint8_t metalen;
842 		rte_le16_t length;
843 		rte_le16_t offset;
844 		rte_le16_t readlen;
845 		uint8_t eth_index;
846 		uint8_t data[];
847 	} __rte_packed_end * buf;
848 
849 	/* Buffer must be large enough and rounded to the next block size. */
850 	bufsz = sizeof(*(buf)) + sizeof((buf)->data[0]) *
851 			(RTE_ALIGN_CEIL(len, NSP_SFF_EEPROM_BLOCK_LEN));
852 	buf = calloc(1, bufsz);
853 	if (buf == NULL)
854 		return -ENOMEM;
855 
856 	buf->metalen = offsetof(struct eeprom_buf, data) / NSP_SFF_EEPROM_BLOCK_LEN;
857 	buf->length = rte_cpu_to_le_16(len);
858 	buf->offset = rte_cpu_to_le_16(offset);
859 	buf->eth_index = eth_index;
860 
861 	ret = nfp_nsp_read_module_eeprom_real(state, buf, bufsz);
862 	if (ret != 0)
863 		goto free_exit;
864 
865 	if (rte_le_to_cpu_16(buf->readlen) < len) {
866 		ret = -EIO;
867 		goto free_exit;
868 	}
869 
870 	if (len != 0)
871 		memcpy(data, buf->data, len);
872 
873 	*read_len = len;
874 
875 free_exit:
876 	free(buf);
877 	return ret;
878 }
879 
880 int
881 nfp_nsp_hwinfo_lookup(struct nfp_nsp *state,
882 		void *buf,
883 		uint32_t size)
884 {
885 	int ret;
886 	uint32_t size_tmp;
887 
888 	if (!nfp_nsp_has_hwinfo_lookup(state)) {
889 		PMD_DRV_LOG(ERR, "NSP HWinfo lookup not supported. Please update flash.");
890 		return -EOPNOTSUPP;
891 	}
892 
893 	size_tmp = RTE_MIN(size, NFP_HWINFO_LOOKUP_SIZE);
894 
895 	ret = nfp_nsp_hwinfo_lookup_real(state, buf, size, false);
896 	if (ret != 0)
897 		return ret;
898 
899 	if (strnlen(buf, size_tmp) == size_tmp) {
900 		PMD_DRV_LOG(ERR, "NSP HWinfo value not NULL terminated.");
901 		return -EINVAL;
902 	}
903 
904 	return 0;
905 }
906 
907 int
908 nfp_nsp_hwinfo_lookup_optional(struct nfp_nsp *state,
909 		void *buf,
910 		size_t size,
911 		const char *default_val)
912 {
913 	int ret;
914 	size_t min_size;
915 
916 	if (strnlen(default_val, size) == size) {
917 		PMD_DRV_LOG(ERR, "NSP HWinfo default value not NULL terminated.");
918 		return -EINVAL;
919 	}
920 
921 	if (!nfp_nsp_has_hwinfo_lookup(state))
922 		goto default_return;
923 
924 	min_size = RTE_MIN(size, NFP_HWINFO_LOOKUP_SIZE);
925 	ret = nfp_nsp_hwinfo_lookup_real(state, buf, min_size, true);
926 	if (ret != 0) {
927 		if (ret == -ENOENT)
928 			goto default_return;
929 
930 		PMD_DRV_LOG(ERR, "NSP HWinfo lookup failed: %d.", ret);
931 		return ret;
932 	}
933 
934 	if (strnlen(buf, min_size) == min_size) {
935 		PMD_DRV_LOG(ERR, "NSP HWinfo value not NULL terminated.");
936 		return -EINVAL;
937 	}
938 
939 	return 0;
940 
941 default_return:
942 	strlcpy(buf, default_val, size);
943 	return 0;
944 }
945