xref: /dpdk/drivers/net/nfp/nfpcore/nfp_nsp.c (revision e77506397fc8005c5129e22e9e2d15d5876790fd)
1c7e9729dSAlejandro Lucero /* SPDX-License-Identifier: BSD-3-Clause
2c7e9729dSAlejandro Lucero  * Copyright(c) 2018 Netronome Systems, Inc.
3c7e9729dSAlejandro Lucero  * All rights reserved.
4c7e9729dSAlejandro Lucero  */
5c7e9729dSAlejandro Lucero 
6acaa57efSChaoyong He #include "nfp_nsp.h"
7c7e9729dSAlejandro Lucero 
8a3460357SChaoyong He #include <nfp_platform.h>
9c7e9729dSAlejandro Lucero #include <rte_common.h>
10c7e9729dSAlejandro Lucero 
1152d810dcSJames Hershaw #include "nfp_logs.h"
12c7e9729dSAlejandro Lucero #include "nfp_resource.h"
13c7e9729dSAlejandro Lucero 
14acaa57efSChaoyong He /* Offsets relative to the CSR base */
15acaa57efSChaoyong He #define NSP_STATUS              0x00
16acaa57efSChaoyong He #define   NSP_STATUS_MAGIC      GENMASK_ULL(63, 48)
17acaa57efSChaoyong He #define   NSP_STATUS_MAJOR      GENMASK_ULL(47, 44)
18acaa57efSChaoyong He #define   NSP_STATUS_MINOR      GENMASK_ULL(43, 32)
19acaa57efSChaoyong He #define   NSP_STATUS_CODE       GENMASK_ULL(31, 16)
20acaa57efSChaoyong He #define   NSP_STATUS_RESULT     GENMASK_ULL(15, 8)
21acaa57efSChaoyong He #define   NSP_STATUS_BUSY       RTE_BIT64(0)
22acaa57efSChaoyong He 
23acaa57efSChaoyong He #define NSP_COMMAND             0x08
24acaa57efSChaoyong He #define   NSP_COMMAND_OPTION    GENMASK_ULL(63, 32)
25847aa891SPeng Zhang #define   NSP_COMMAND_VER_MAJOR GENMASK_ULL(31, 28)
26847aa891SPeng Zhang #define   NSP_COMMAND_CODE      GENMASK_ULL(27, 16)
27acaa57efSChaoyong He #define   NSP_COMMAND_DMA_BUF   RTE_BIT64(1)
28acaa57efSChaoyong He #define   NSP_COMMAND_START     RTE_BIT64(0)
29acaa57efSChaoyong He 
30acaa57efSChaoyong He /* CPP address to retrieve the data from */
31acaa57efSChaoyong He #define NSP_BUFFER              0x10
32acaa57efSChaoyong He #define   NSP_BUFFER_CPP        GENMASK_ULL(63, 40)
33acaa57efSChaoyong He #define   NSP_BUFFER_ADDRESS    GENMASK_ULL(39, 0)
34acaa57efSChaoyong He 
35acaa57efSChaoyong He #define NSP_DFLT_BUFFER         0x18
36acaa57efSChaoyong He #define   NSP_DFLT_BUFFER_CPP          GENMASK_ULL(63, 40)
37acaa57efSChaoyong He #define   NSP_DFLT_BUFFER_ADDRESS      GENMASK_ULL(39, 0)
38acaa57efSChaoyong He 
39acaa57efSChaoyong He #define NSP_DFLT_BUFFER_CONFIG  0x20
40acaa57efSChaoyong He #define   NSP_DFLT_BUFFER_SIZE_4KB     GENMASK_ULL(15, 8)
41acaa57efSChaoyong He #define   NSP_DFLT_BUFFER_SIZE_MB      GENMASK_ULL(7, 0)
42acaa57efSChaoyong He 
43acaa57efSChaoyong He #define NSP_MAGIC               0xab10
448ad2cc8fSPeng Zhang 
458ad2cc8fSPeng Zhang /*
468ad2cc8fSPeng Zhang  * ABI major version is bumped separately without resetting minor
478ad2cc8fSPeng Zhang  * version when the change in NSP is not compatible to old driver.
488ad2cc8fSPeng Zhang  */
498ad2cc8fSPeng Zhang #define NSP_MAJOR               1
508ad2cc8fSPeng Zhang 
518ad2cc8fSPeng Zhang /*
528ad2cc8fSPeng Zhang  * ABI minor version is bumped when new feature is introduced
538ad2cc8fSPeng Zhang  * while old driver can still work without this new feature.
548ad2cc8fSPeng Zhang  */
55acaa57efSChaoyong He #define NSP_MINOR               8
56acaa57efSChaoyong He 
57acaa57efSChaoyong He #define NSP_CODE_MAJOR          GENMASK_ULL(15, 12)
58acaa57efSChaoyong He #define NSP_CODE_MINOR          GENMASK_ULL(11, 0)
59acaa57efSChaoyong He 
60acaa57efSChaoyong He #define NFP_FW_LOAD_RET_MAJOR   GENMASK_ULL(15, 8)
61acaa57efSChaoyong He #define NFP_FW_LOAD_RET_MINOR   GENMASK_ULL(23, 16)
62acaa57efSChaoyong He 
639e76c352SChaoyong He #define NFP_HWINFO_LOOKUP_SIZE  GENMASK_ULL(11, 0)
649e76c352SChaoyong He 
65acaa57efSChaoyong He enum nfp_nsp_cmd {
66acaa57efSChaoyong He 	SPCODE_NOOP             = 0, /* No operation */
67acaa57efSChaoyong He 	SPCODE_SOFT_RESET       = 1, /* Soft reset the NFP */
68acaa57efSChaoyong He 	SPCODE_FW_DEFAULT       = 2, /* Load default (UNDI) FW */
69acaa57efSChaoyong He 	SPCODE_PHY_INIT         = 3, /* Initialize the PHY */
70acaa57efSChaoyong He 	SPCODE_MAC_INIT         = 4, /* Initialize the MAC */
71acaa57efSChaoyong He 	SPCODE_PHY_RXADAPT      = 5, /* Re-run PHY RX Adaptation */
72acaa57efSChaoyong He 	SPCODE_FW_LOAD          = 6, /* Load fw from buffer, len in option */
73acaa57efSChaoyong He 	SPCODE_ETH_RESCAN       = 7, /* Rescan ETHs, write ETH_TABLE to buf */
74acaa57efSChaoyong He 	SPCODE_ETH_CONTROL      = 8, /* Update media config from buffer */
75acaa57efSChaoyong He 	SPCODE_NSP_WRITE_FLASH  = 11, /* Load and flash image from buffer */
76acaa57efSChaoyong He 	SPCODE_NSP_SENSORS      = 12, /* Read NSP sensor(s) */
77acaa57efSChaoyong He 	SPCODE_NSP_IDENTIFY     = 13, /* Read NSP version */
78acaa57efSChaoyong He 	SPCODE_FW_STORED        = 16, /* If no FW loaded, load flash app FW */
79acaa57efSChaoyong He 	SPCODE_HWINFO_LOOKUP    = 17, /* Lookup HWinfo with overwrites etc. */
80acaa57efSChaoyong He 	SPCODE_HWINFO_SET       = 18, /* Set HWinfo entry */
81acaa57efSChaoyong He 	SPCODE_FW_LOADED        = 19, /* Is application firmware loaded */
82acaa57efSChaoyong He 	SPCODE_VERSIONS         = 21, /* Report FW versions */
83acaa57efSChaoyong He 	SPCODE_READ_SFF_EEPROM  = 22, /* Read module EEPROM */
84acaa57efSChaoyong He 	SPCODE_READ_MEDIA       = 23, /* Get the supported/advertised media for a port */
8508461d7bSPeng Zhang 	SPCODE_DEV_ACTIVATE	= 29, /* Activate hardware for multiple pfs case */
86acaa57efSChaoyong He };
87acaa57efSChaoyong He 
88acaa57efSChaoyong He static const struct {
89acaa57efSChaoyong He 	uint32_t code;
90acaa57efSChaoyong He 	const char *msg;
91acaa57efSChaoyong He } nsp_errors[] = {
92acaa57efSChaoyong He 	{ 6010, "could not map to phy for port" },
93acaa57efSChaoyong He 	{ 6011, "not an allowed rate/lanes for port" },
94acaa57efSChaoyong He 	{ 6012, "not an allowed rate/lanes for port" },
95acaa57efSChaoyong He 	{ 6013, "high/low error, change other port first" },
96acaa57efSChaoyong He 	{ 6014, "config not found in flash" },
97acaa57efSChaoyong He };
98acaa57efSChaoyong He 
99acaa57efSChaoyong He struct nfp_nsp {
100acaa57efSChaoyong He 	struct nfp_cpp *cpp;
101acaa57efSChaoyong He 	struct nfp_resource *res;
102acaa57efSChaoyong He 	struct {
103acaa57efSChaoyong He 		uint16_t major;
104acaa57efSChaoyong He 		uint16_t minor;
105acaa57efSChaoyong He 	} ver;
106acaa57efSChaoyong He 
107acaa57efSChaoyong He 	/** Eth table config state */
108acaa57efSChaoyong He 	bool modified;
109acaa57efSChaoyong He 	uint32_t idx;
110acaa57efSChaoyong He 	void *entries;
111acaa57efSChaoyong He };
112acaa57efSChaoyong He 
113acaa57efSChaoyong He /* NFP command argument structure */
114acaa57efSChaoyong He struct nfp_nsp_command_arg {
115acaa57efSChaoyong He 	uint16_t code;         /**< NFP SP Command Code */
116acaa57efSChaoyong He 	bool dma;              /**< @buf points to a host buffer, not NSP buffer */
117acaa57efSChaoyong He 	bool error_quiet;      /**< Don't print command error/warning */
118acaa57efSChaoyong He 	uint32_t timeout_sec;  /**< Timeout value to wait for completion in seconds */
119acaa57efSChaoyong He 	uint32_t option;       /**< NSP Command Argument */
120acaa57efSChaoyong He 	uint64_t buf;          /**< NSP Buffer Address */
121acaa57efSChaoyong He 	/** Callback for interpreting option if error occurred */
122acaa57efSChaoyong He 	void (*error_cb)(struct nfp_nsp *state, uint32_t ret_val);
123acaa57efSChaoyong He };
124acaa57efSChaoyong He 
125acaa57efSChaoyong He /* NFP command with buffer argument structure */
126acaa57efSChaoyong He struct nfp_nsp_command_buf_arg {
127acaa57efSChaoyong He 	struct nfp_nsp_command_arg arg;  /**< NFP command argument structure */
128acaa57efSChaoyong He 	const void *in_buf;              /**< Buffer with data for input */
129acaa57efSChaoyong He 	void *out_buf;                   /**< Buffer for output data */
130acaa57efSChaoyong He 	uint32_t in_size;                /**< Size of @in_buf */
131acaa57efSChaoyong He 	uint32_t out_size;               /**< Size of @out_buf */
132acaa57efSChaoyong He };
133acaa57efSChaoyong He 
134acaa57efSChaoyong He struct nfp_cpp *
135acaa57efSChaoyong He nfp_nsp_cpp(struct nfp_nsp *state)
136acaa57efSChaoyong He {
137acaa57efSChaoyong He 	return state->cpp;
138acaa57efSChaoyong He }
139acaa57efSChaoyong He 
140acaa57efSChaoyong He bool
141c7e9729dSAlejandro Lucero nfp_nsp_config_modified(struct nfp_nsp *state)
142c7e9729dSAlejandro Lucero {
143c7e9729dSAlejandro Lucero 	return state->modified;
144c7e9729dSAlejandro Lucero }
145c7e9729dSAlejandro Lucero 
146c7e9729dSAlejandro Lucero void
147d108b9e9SChaoyong He nfp_nsp_config_set_modified(struct nfp_nsp *state,
148acaa57efSChaoyong He 		bool modified)
149c7e9729dSAlejandro Lucero {
150c7e9729dSAlejandro Lucero 	state->modified = modified;
151c7e9729dSAlejandro Lucero }
152c7e9729dSAlejandro Lucero 
153c7e9729dSAlejandro Lucero void *
154c7e9729dSAlejandro Lucero nfp_nsp_config_entries(struct nfp_nsp *state)
155c7e9729dSAlejandro Lucero {
156c7e9729dSAlejandro Lucero 	return state->entries;
157c7e9729dSAlejandro Lucero }
158c7e9729dSAlejandro Lucero 
159c69debceSChaoyong He uint32_t
160c7e9729dSAlejandro Lucero nfp_nsp_config_idx(struct nfp_nsp *state)
161c7e9729dSAlejandro Lucero {
162c7e9729dSAlejandro Lucero 	return state->idx;
163c7e9729dSAlejandro Lucero }
164c7e9729dSAlejandro Lucero 
165c7e9729dSAlejandro Lucero void
166d108b9e9SChaoyong He nfp_nsp_config_set_state(struct nfp_nsp *state,
167d108b9e9SChaoyong He 		void *entries,
168c69debceSChaoyong He 		uint32_t idx)
169c7e9729dSAlejandro Lucero {
170c7e9729dSAlejandro Lucero 	state->entries = entries;
171c7e9729dSAlejandro Lucero 	state->idx = idx;
172c7e9729dSAlejandro Lucero }
173c7e9729dSAlejandro Lucero 
174c7e9729dSAlejandro Lucero void
175c7e9729dSAlejandro Lucero nfp_nsp_config_clear_state(struct nfp_nsp *state)
176c7e9729dSAlejandro Lucero {
177c7e9729dSAlejandro Lucero 	state->entries = NULL;
178c7e9729dSAlejandro Lucero 	state->idx = 0;
179c7e9729dSAlejandro Lucero }
180c7e9729dSAlejandro Lucero 
181c7e9729dSAlejandro Lucero static void
182c7e9729dSAlejandro Lucero nfp_nsp_print_extended_error(uint32_t ret_val)
183c7e9729dSAlejandro Lucero {
184c69debceSChaoyong He 	uint32_t i;
185c7e9729dSAlejandro Lucero 
186cbcbfd73SJames Hershaw 	if (ret_val == 0)
187c7e9729dSAlejandro Lucero 		return;
188c7e9729dSAlejandro Lucero 
189c69debceSChaoyong He 	for (i = 0; i < RTE_DIM(nsp_errors); i++)
190acaa57efSChaoyong He 		if (ret_val == nsp_errors[i].code)
191b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "Err msg: %s.", nsp_errors[i].msg);
192c7e9729dSAlejandro Lucero }
193c7e9729dSAlejandro Lucero 
194c7e9729dSAlejandro Lucero static int
195c7e9729dSAlejandro Lucero nfp_nsp_check(struct nfp_nsp *state)
196c7e9729dSAlejandro Lucero {
197c7e9729dSAlejandro Lucero 	int err;
198610bf14bSChaoyong He 	uint64_t reg;
199610bf14bSChaoyong He 	uint32_t nsp_cpp;
200610bf14bSChaoyong He 	uint64_t nsp_status;
201610bf14bSChaoyong He 	struct nfp_cpp *cpp = state->cpp;
202c7e9729dSAlejandro Lucero 
203c7e9729dSAlejandro Lucero 	nsp_cpp = nfp_resource_cpp_id(state->res);
204c7e9729dSAlejandro Lucero 	nsp_status = nfp_resource_address(state->res) + NSP_STATUS;
205c7e9729dSAlejandro Lucero 
206c7e9729dSAlejandro Lucero 	err = nfp_cpp_readq(cpp, nsp_cpp, nsp_status, &reg);
207efa766e1SChaoyong He 	if (err < 0) {
208b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NSP - CPP readq failed %d.", err);
209c7e9729dSAlejandro Lucero 		return err;
210efa766e1SChaoyong He 	}
211c7e9729dSAlejandro Lucero 
212c7e9729dSAlejandro Lucero 	if (FIELD_GET(NSP_STATUS_MAGIC, reg) != NSP_MAGIC) {
213b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Can not detect NFP Service Processor.");
214c7e9729dSAlejandro Lucero 		return -ENODEV;
215c7e9729dSAlejandro Lucero 	}
216c7e9729dSAlejandro Lucero 
217c7e9729dSAlejandro Lucero 	state->ver.major = FIELD_GET(NSP_STATUS_MAJOR, reg);
218c7e9729dSAlejandro Lucero 	state->ver.minor = FIELD_GET(NSP_STATUS_MINOR, reg);
219c7e9729dSAlejandro Lucero 
2208ad2cc8fSPeng Zhang 	if (state->ver.major > NSP_MAJOR || state->ver.minor < NSP_MINOR) {
221b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Unsupported ABI %hu.%hu.", state->ver.major,
222c7e9729dSAlejandro Lucero 				state->ver.minor);
223c7e9729dSAlejandro Lucero 		return -EINVAL;
224c7e9729dSAlejandro Lucero 	}
225c7e9729dSAlejandro Lucero 
2264aa75cadSChaoyong He 	if ((reg & NSP_STATUS_BUSY) != 0) {
2278412feedSZerun Fu 		PMD_DRV_LOG(DEBUG, "Service processor busy!");
228c7e9729dSAlejandro Lucero 		return -EBUSY;
229c7e9729dSAlejandro Lucero 	}
230c7e9729dSAlejandro Lucero 
231c7e9729dSAlejandro Lucero 	return 0;
232c7e9729dSAlejandro Lucero }
233c7e9729dSAlejandro Lucero 
2346d03aa61SChaoyong He /**
2356d03aa61SChaoyong He  * Prepare for communication and lock the NSP resource.
2366d03aa61SChaoyong He  *
2376d03aa61SChaoyong He  * @param cpp
2386d03aa61SChaoyong He  *   NFP CPP Handle
239c7e9729dSAlejandro Lucero  */
240c7e9729dSAlejandro Lucero struct nfp_nsp *
241c7e9729dSAlejandro Lucero nfp_nsp_open(struct nfp_cpp *cpp)
242c7e9729dSAlejandro Lucero {
243c7e9729dSAlejandro Lucero 	int err;
244610bf14bSChaoyong He 	struct nfp_nsp *state;
245610bf14bSChaoyong He 	struct nfp_resource *res;
246c7e9729dSAlejandro Lucero 
247c7e9729dSAlejandro Lucero 	res = nfp_resource_acquire(cpp, NFP_RESOURCE_NSP);
248efa766e1SChaoyong He 	if (res == NULL) {
249b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NSP - resource acquire failed.");
250c7e9729dSAlejandro Lucero 		return NULL;
251efa766e1SChaoyong He 	}
252c7e9729dSAlejandro Lucero 
253c7e9729dSAlejandro Lucero 	state = malloc(sizeof(*state));
254cbcbfd73SJames Hershaw 	if (state == NULL) {
255aa6b4a80SHuaxing Zhu 		PMD_DRV_LOG(ERR, "NSP - failed to malloc name %s", NFP_RESOURCE_NSP);
256c7e9729dSAlejandro Lucero 		nfp_resource_release(res);
257c7e9729dSAlejandro Lucero 		return NULL;
258c7e9729dSAlejandro Lucero 	}
259c7e9729dSAlejandro Lucero 	memset(state, 0, sizeof(*state));
260c7e9729dSAlejandro Lucero 	state->cpp = cpp;
261c7e9729dSAlejandro Lucero 	state->res = res;
262c7e9729dSAlejandro Lucero 
263c7e9729dSAlejandro Lucero 	err = nfp_nsp_check(state);
2644aa75cadSChaoyong He 	if (err != 0) {
265b6de4353SZerun Fu 		PMD_DRV_LOG(DEBUG, "NSP - check failed.");
266c7e9729dSAlejandro Lucero 		nfp_nsp_close(state);
267c7e9729dSAlejandro Lucero 		return NULL;
268c7e9729dSAlejandro Lucero 	}
269c7e9729dSAlejandro Lucero 
270c7e9729dSAlejandro Lucero 	return state;
271c7e9729dSAlejandro Lucero }
272c7e9729dSAlejandro Lucero 
2736d03aa61SChaoyong He /**
2746d03aa61SChaoyong He  * Clean up and unlock the NSP resource.
2756d03aa61SChaoyong He  *
2766d03aa61SChaoyong He  * @param state
2776d03aa61SChaoyong He  *   NFP SP state
278c7e9729dSAlejandro Lucero  */
279c7e9729dSAlejandro Lucero void
280c7e9729dSAlejandro Lucero nfp_nsp_close(struct nfp_nsp *state)
281c7e9729dSAlejandro Lucero {
282c7e9729dSAlejandro Lucero 	nfp_resource_release(state->res);
283c7e9729dSAlejandro Lucero 	free(state);
284c7e9729dSAlejandro Lucero }
285c7e9729dSAlejandro Lucero 
286c7e9729dSAlejandro Lucero uint16_t
287c7e9729dSAlejandro Lucero nfp_nsp_get_abi_ver_major(struct nfp_nsp *state)
288c7e9729dSAlejandro Lucero {
289c7e9729dSAlejandro Lucero 	return state->ver.major;
290c7e9729dSAlejandro Lucero }
291c7e9729dSAlejandro Lucero 
292c7e9729dSAlejandro Lucero uint16_t
293c7e9729dSAlejandro Lucero nfp_nsp_get_abi_ver_minor(struct nfp_nsp *state)
294c7e9729dSAlejandro Lucero {
295c7e9729dSAlejandro Lucero 	return state->ver.minor;
296c7e9729dSAlejandro Lucero }
297c7e9729dSAlejandro Lucero 
298c7e9729dSAlejandro Lucero static int
299d108b9e9SChaoyong He nfp_nsp_wait_reg(struct nfp_cpp *cpp,
300d108b9e9SChaoyong He 		uint64_t *reg,
301d108b9e9SChaoyong He 		uint32_t nsp_cpp,
302d108b9e9SChaoyong He 		uint64_t addr,
303d108b9e9SChaoyong He 		uint64_t mask,
304d108b9e9SChaoyong He 		uint64_t val)
305c7e9729dSAlejandro Lucero {
306c7e9729dSAlejandro Lucero 	int err;
307610bf14bSChaoyong He 	uint32_t count = 0;
308610bf14bSChaoyong He 	struct timespec wait;
309c7e9729dSAlejandro Lucero 
310c7e9729dSAlejandro Lucero 	wait.tv_sec = 0;
3116d03aa61SChaoyong He 	wait.tv_nsec = 25000000;     /* 25ms */
312c7e9729dSAlejandro Lucero 
313c7e9729dSAlejandro Lucero 	for (;;) {
314c7e9729dSAlejandro Lucero 		err = nfp_cpp_readq(cpp, nsp_cpp, addr, reg);
315efa766e1SChaoyong He 		if (err < 0) {
316b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "NSP - CPP readq failed.");
317c7e9729dSAlejandro Lucero 			return err;
318efa766e1SChaoyong He 		}
319c7e9729dSAlejandro Lucero 
320c7e9729dSAlejandro Lucero 		if ((*reg & mask) == val)
321c7e9729dSAlejandro Lucero 			return 0;
322c7e9729dSAlejandro Lucero 
323c7e9729dSAlejandro Lucero 		nanosleep(&wait, 0);
3246d03aa61SChaoyong He 		if (count++ > 1000)     /* 25ms * 1000 = 25s */
325c7e9729dSAlejandro Lucero 			return -ETIMEDOUT;
326c7e9729dSAlejandro Lucero 	}
327c7e9729dSAlejandro Lucero }
328c7e9729dSAlejandro Lucero 
3296d03aa61SChaoyong He /**
3306d03aa61SChaoyong He  * Execute a command on the NFP Service Processor
331c7e9729dSAlejandro Lucero  *
3326d03aa61SChaoyong He  * @param state
3336d03aa61SChaoyong He  *   NFP SP state
3346d03aa61SChaoyong He  * @param arg
3356d03aa61SChaoyong He  *   NFP command argument structure
336c7e9729dSAlejandro Lucero  *
3376d03aa61SChaoyong He  * @return
3386d03aa61SChaoyong He  *   - 0 for success with no result
3396d03aa61SChaoyong He  *   - Positive value for NSP completion with a result code
3406d03aa61SChaoyong He  *   - -EAGAIN if the NSP is not yet present
3416d03aa61SChaoyong He  *   - -ENODEV if the NSP is not a supported model
3426d03aa61SChaoyong He  *   - -EBUSY if the NSP is stuck
3436d03aa61SChaoyong He  *   - -EINTR if interrupted while waiting for completion
3446d03aa61SChaoyong He  *   - -ETIMEDOUT if the NSP took longer than @timeout_sec seconds to complete
345c7e9729dSAlejandro Lucero  */
346c7e9729dSAlejandro Lucero static int
347acaa57efSChaoyong He nfp_nsp_command_real(struct nfp_nsp *state,
348acaa57efSChaoyong He 		const struct nfp_nsp_command_arg *arg)
349c7e9729dSAlejandro Lucero {
350c7e9729dSAlejandro Lucero 	int err;
351610bf14bSChaoyong He 	uint64_t reg;
352610bf14bSChaoyong He 	uint32_t nsp_cpp;
353610bf14bSChaoyong He 	uint64_t ret_val;
354610bf14bSChaoyong He 	uint64_t nsp_base;
355610bf14bSChaoyong He 	uint64_t nsp_buffer;
356610bf14bSChaoyong He 	uint64_t nsp_status;
357610bf14bSChaoyong He 	uint64_t nsp_command;
358610bf14bSChaoyong He 	struct nfp_cpp *cpp = state->cpp;
359c7e9729dSAlejandro Lucero 
360c7e9729dSAlejandro Lucero 	nsp_cpp = nfp_resource_cpp_id(state->res);
361c7e9729dSAlejandro Lucero 	nsp_base = nfp_resource_address(state->res);
362c7e9729dSAlejandro Lucero 	nsp_status = nsp_base + NSP_STATUS;
363c7e9729dSAlejandro Lucero 	nsp_command = nsp_base + NSP_COMMAND;
364c7e9729dSAlejandro Lucero 	nsp_buffer = nsp_base + NSP_BUFFER;
365c7e9729dSAlejandro Lucero 
366c7e9729dSAlejandro Lucero 	err = nfp_nsp_check(state);
367efa766e1SChaoyong He 	if (err != 0) {
368b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Check NSP command failed.");
369c7e9729dSAlejandro Lucero 		return err;
370efa766e1SChaoyong He 	}
371c7e9729dSAlejandro Lucero 
372acaa57efSChaoyong He 	err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_buffer, arg->buf);
373aa6b4a80SHuaxing Zhu 	if (err < 0) {
374aa6b4a80SHuaxing Zhu 		PMD_DRV_LOG(ERR, "CPP write buffer failed. err %d", err);
375c7e9729dSAlejandro Lucero 		return err;
376aa6b4a80SHuaxing Zhu 	}
377c7e9729dSAlejandro Lucero 
378c7e9729dSAlejandro Lucero 	err = nfp_cpp_writeq(cpp, nsp_cpp, nsp_command,
379acaa57efSChaoyong He 			FIELD_PREP(NSP_COMMAND_OPTION, arg->option) |
380847aa891SPeng Zhang 			FIELD_PREP(NSP_COMMAND_VER_MAJOR, state->ver.major) |
381acaa57efSChaoyong He 			FIELD_PREP(NSP_COMMAND_CODE, arg->code) |
382acaa57efSChaoyong He 			FIELD_PREP(NSP_COMMAND_DMA_BUF, arg->dma) |
383c7e9729dSAlejandro Lucero 			FIELD_PREP(NSP_COMMAND_START, 1));
384aa6b4a80SHuaxing Zhu 	if (err < 0) {
385aa6b4a80SHuaxing Zhu 		PMD_DRV_LOG(ERR, "CPP write command failed. err %d", err);
386c7e9729dSAlejandro Lucero 		return err;
387aa6b4a80SHuaxing Zhu 	}
388c7e9729dSAlejandro Lucero 
389c7e9729dSAlejandro Lucero 	/* Wait for NSP_COMMAND_START to go to 0 */
390c7e9729dSAlejandro Lucero 	err = nfp_nsp_wait_reg(cpp, &reg, nsp_cpp, nsp_command,
391c7e9729dSAlejandro Lucero 			NSP_COMMAND_START, 0);
3924aa75cadSChaoyong He 	if (err != 0) {
393b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Error %d waiting for code %#04x to start.",
394acaa57efSChaoyong He 				err, arg->code);
395c7e9729dSAlejandro Lucero 		return err;
396c7e9729dSAlejandro Lucero 	}
397c7e9729dSAlejandro Lucero 
398c7e9729dSAlejandro Lucero 	/* Wait for NSP_STATUS_BUSY to go to 0 */
399d108b9e9SChaoyong He 	err = nfp_nsp_wait_reg(cpp, &reg, nsp_cpp, nsp_status,
400d108b9e9SChaoyong He 			NSP_STATUS_BUSY, 0);
4014aa75cadSChaoyong He 	if (err != 0) {
402b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Error %d waiting for code %#04x to complete.",
403acaa57efSChaoyong He 				err, arg->code);
404c7e9729dSAlejandro Lucero 		return err;
405c7e9729dSAlejandro Lucero 	}
406c7e9729dSAlejandro Lucero 
407c7e9729dSAlejandro Lucero 	err = nfp_cpp_readq(cpp, nsp_cpp, nsp_command, &ret_val);
408aa6b4a80SHuaxing Zhu 	if (err < 0) {
409aa6b4a80SHuaxing Zhu 		PMD_DRV_LOG(ERR, "CPP read return value failed. err %d", err);
410c7e9729dSAlejandro Lucero 		return err;
411aa6b4a80SHuaxing Zhu 	}
412f842b01aSChaoyong He 
413c7e9729dSAlejandro Lucero 	ret_val = FIELD_GET(NSP_COMMAND_OPTION, ret_val);
414c7e9729dSAlejandro Lucero 
415c7e9729dSAlejandro Lucero 	err = FIELD_GET(NSP_STATUS_RESULT, reg);
4164aa75cadSChaoyong He 	if (err != 0) {
417acaa57efSChaoyong He 		if (!arg->error_quiet)
418b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "Result (error) code set: %d (%d) command: %d.",
419acaa57efSChaoyong He 					-err, (int)ret_val, arg->code);
420acaa57efSChaoyong He 
421acaa57efSChaoyong He 		if (arg->error_cb != 0)
422acaa57efSChaoyong He 			arg->error_cb(state, ret_val);
423acaa57efSChaoyong He 		else
424c7e9729dSAlejandro Lucero 			nfp_nsp_print_extended_error(ret_val);
425acaa57efSChaoyong He 
426c7e9729dSAlejandro Lucero 		return -err;
427c7e9729dSAlejandro Lucero 	}
428c7e9729dSAlejandro Lucero 
429c7e9729dSAlejandro Lucero 	return ret_val;
430c7e9729dSAlejandro Lucero }
431c7e9729dSAlejandro Lucero 
432acaa57efSChaoyong He static int
433acaa57efSChaoyong He nfp_nsp_command(struct nfp_nsp *state,
434acaa57efSChaoyong He 		uint16_t code)
435acaa57efSChaoyong He {
436acaa57efSChaoyong He 	const struct nfp_nsp_command_arg arg = {
437acaa57efSChaoyong He 		.code = code,
438acaa57efSChaoyong He 	};
439acaa57efSChaoyong He 
440acaa57efSChaoyong He 	return nfp_nsp_command_real(state, &arg);
441acaa57efSChaoyong He }
442c7e9729dSAlejandro Lucero 
443c7e9729dSAlejandro Lucero static int
444acaa57efSChaoyong He nfp_nsp_command_buf_def(struct nfp_nsp *nsp,
445acaa57efSChaoyong He 		struct nfp_nsp_command_buf_arg *arg)
446c7e9729dSAlejandro Lucero {
447610bf14bSChaoyong He 	int err;
448610bf14bSChaoyong He 	int ret;
449610bf14bSChaoyong He 	uint64_t reg;
450c7e9729dSAlejandro Lucero 	uint32_t cpp_id;
451610bf14bSChaoyong He 	uint64_t cpp_buf;
452610bf14bSChaoyong He 	struct nfp_cpp *cpp = nsp->cpp;
453c7e9729dSAlejandro Lucero 
454acaa57efSChaoyong He 	err = nfp_cpp_readq(cpp, nfp_resource_cpp_id(nsp->res),
455acaa57efSChaoyong He 			nfp_resource_address(nsp->res) + NSP_DFLT_BUFFER,
456acaa57efSChaoyong He 			&reg);
457acaa57efSChaoyong He 	if (err < 0)
458acaa57efSChaoyong He 		return err;
459acaa57efSChaoyong He 
460acaa57efSChaoyong He 	cpp_id = FIELD_GET(NSP_DFLT_BUFFER_CPP, reg) << 8;
461acaa57efSChaoyong He 	cpp_buf = FIELD_GET(NSP_DFLT_BUFFER_ADDRESS, reg);
462acaa57efSChaoyong He 
463acaa57efSChaoyong He 	if (arg->in_buf != NULL && arg->in_size > 0) {
464acaa57efSChaoyong He 		err = nfp_cpp_write(cpp, cpp_id, cpp_buf,
465acaa57efSChaoyong He 				arg->in_buf, arg->in_size);
466acaa57efSChaoyong He 		if (err < 0)
467acaa57efSChaoyong He 			return err;
468acaa57efSChaoyong He 	}
469acaa57efSChaoyong He 
470acaa57efSChaoyong He 	/* Zero out remaining part of the buffer */
471acaa57efSChaoyong He 	if (arg->out_buf != NULL && arg->out_size > arg->in_size) {
472acaa57efSChaoyong He 		err = nfp_cpp_write(cpp, cpp_id, cpp_buf + arg->in_size,
473acaa57efSChaoyong He 				arg->out_buf, arg->out_size - arg->in_size);
474acaa57efSChaoyong He 		if (err < 0)
475acaa57efSChaoyong He 			return err;
476acaa57efSChaoyong He 	}
477acaa57efSChaoyong He 
478acaa57efSChaoyong He 	if (!FIELD_FIT(NSP_BUFFER_CPP, cpp_id >> 8) ||
479acaa57efSChaoyong He 			!FIELD_FIT(NSP_BUFFER_ADDRESS, cpp_buf)) {
480b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Buffer out of reach %#08x %#016lx.",
481acaa57efSChaoyong He 				cpp_id, cpp_buf);
482acaa57efSChaoyong He 		return -EINVAL;
483acaa57efSChaoyong He 	}
484acaa57efSChaoyong He 
485acaa57efSChaoyong He 	arg->arg.buf = FIELD_PREP(NSP_BUFFER_CPP, cpp_id >> 8) |
486acaa57efSChaoyong He 			FIELD_PREP(NSP_BUFFER_ADDRESS, cpp_buf);
487acaa57efSChaoyong He 	ret = nfp_nsp_command_real(nsp, &arg->arg);
488acaa57efSChaoyong He 	if (ret < 0) {
4899e76c352SChaoyong He 		if (!arg->arg.error_quiet)
490b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "NSP command failed.");
4919e76c352SChaoyong He 
492acaa57efSChaoyong He 		return ret;
493acaa57efSChaoyong He 	}
494acaa57efSChaoyong He 
495acaa57efSChaoyong He 	if (arg->out_buf != NULL && arg->out_size > 0) {
496acaa57efSChaoyong He 		err = nfp_cpp_read(cpp, cpp_id, cpp_buf,
497acaa57efSChaoyong He 				arg->out_buf, arg->out_size);
498acaa57efSChaoyong He 		if (err < 0)
499acaa57efSChaoyong He 			return err;
500acaa57efSChaoyong He 	}
501acaa57efSChaoyong He 
502acaa57efSChaoyong He 	return ret;
503acaa57efSChaoyong He }
504acaa57efSChaoyong He 
505acaa57efSChaoyong He #define SZ_1M 0x00100000
506acaa57efSChaoyong He #define SZ_4K 0x00001000
507acaa57efSChaoyong He 
508acaa57efSChaoyong He static int
509acaa57efSChaoyong He nfp_nsp_command_buf(struct nfp_nsp *nsp,
510acaa57efSChaoyong He 		struct nfp_nsp_command_buf_arg *arg)
511acaa57efSChaoyong He {
512acaa57efSChaoyong He 	int err;
513acaa57efSChaoyong He 	size_t size;
514acaa57efSChaoyong He 	uint64_t reg;
515acaa57efSChaoyong He 	size_t max_size;
516acaa57efSChaoyong He 	struct nfp_cpp *cpp = nsp->cpp;
517acaa57efSChaoyong He 
518c7e9729dSAlejandro Lucero 	if (nsp->ver.minor < 13) {
519b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NSP: Code %#04x with buffer not supported ABI %hu.%hu).",
520acaa57efSChaoyong He 				arg->arg.code, nsp->ver.major, nsp->ver.minor);
521c7e9729dSAlejandro Lucero 		return -EOPNOTSUPP;
522c7e9729dSAlejandro Lucero 	}
523c7e9729dSAlejandro Lucero 
524c7e9729dSAlejandro Lucero 	err = nfp_cpp_readq(cpp, nfp_resource_cpp_id(nsp->res),
525d108b9e9SChaoyong He 			nfp_resource_address(nsp->res) + NSP_DFLT_BUFFER_CONFIG,
526c7e9729dSAlejandro Lucero 			&reg);
527c7e9729dSAlejandro Lucero 	if (err < 0)
528c7e9729dSAlejandro Lucero 		return err;
529c7e9729dSAlejandro Lucero 
530acaa57efSChaoyong He 	max_size = RTE_MAX(arg->in_size, arg->out_size);
531acaa57efSChaoyong He 	size = FIELD_GET(NSP_DFLT_BUFFER_SIZE_MB, reg) * SZ_1M +
532acaa57efSChaoyong He 			FIELD_GET(NSP_DFLT_BUFFER_SIZE_4KB, reg) * SZ_4K;
533acaa57efSChaoyong He 	if (size < max_size) {
534b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NSP: default buffer too small for command %#04x (%zu < %zu).",
535acaa57efSChaoyong He 				arg->arg.code, size, max_size);
536c7e9729dSAlejandro Lucero 		return -EINVAL;
537c7e9729dSAlejandro Lucero 	}
538c7e9729dSAlejandro Lucero 
539acaa57efSChaoyong He 	return nfp_nsp_command_buf_def(nsp, arg);
540c7e9729dSAlejandro Lucero }
541c7e9729dSAlejandro Lucero 
542c7e9729dSAlejandro Lucero int
543c7e9729dSAlejandro Lucero nfp_nsp_wait(struct nfp_nsp *state)
544c7e9729dSAlejandro Lucero {
545c7e9729dSAlejandro Lucero 	int err;
546610bf14bSChaoyong He 	int count = 0;
547610bf14bSChaoyong He 	struct timespec wait;
548c7e9729dSAlejandro Lucero 
549c7e9729dSAlejandro Lucero 	wait.tv_sec = 0;
5506d03aa61SChaoyong He 	wait.tv_nsec = 25000000;    /* 25ms */
551c7e9729dSAlejandro Lucero 
552c7e9729dSAlejandro Lucero 	for (;;) {
553acaa57efSChaoyong He 		err = nfp_nsp_command(state, SPCODE_NOOP);
554c7e9729dSAlejandro Lucero 		if (err != -EAGAIN)
555c7e9729dSAlejandro Lucero 			break;
556c7e9729dSAlejandro Lucero 
557c7e9729dSAlejandro Lucero 		nanosleep(&wait, 0);
558c7e9729dSAlejandro Lucero 
5596d03aa61SChaoyong He 		if (count++ > 1000) {    /* 25ms * 1000 = 25s */
560c7e9729dSAlejandro Lucero 			err = -ETIMEDOUT;
561c7e9729dSAlejandro Lucero 			break;
562c7e9729dSAlejandro Lucero 		}
563c7e9729dSAlejandro Lucero 	}
564f842b01aSChaoyong He 
5654aa75cadSChaoyong He 	if (err != 0)
566b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NSP failed to respond %d.", err);
567c7e9729dSAlejandro Lucero 
568c7e9729dSAlejandro Lucero 	return err;
569c7e9729dSAlejandro Lucero }
570c7e9729dSAlejandro Lucero 
571c7e9729dSAlejandro Lucero int
572c7e9729dSAlejandro Lucero nfp_nsp_device_soft_reset(struct nfp_nsp *state)
573c7e9729dSAlejandro Lucero {
574acaa57efSChaoyong He 	return nfp_nsp_command(state, SPCODE_SOFT_RESET);
575c7e9729dSAlejandro Lucero }
576c7e9729dSAlejandro Lucero 
577c7e9729dSAlejandro Lucero int
578c7e9729dSAlejandro Lucero nfp_nsp_mac_reinit(struct nfp_nsp *state)
579c7e9729dSAlejandro Lucero {
580acaa57efSChaoyong He 	return nfp_nsp_command(state, SPCODE_MAC_INIT);
581acaa57efSChaoyong He }
582acaa57efSChaoyong He 
583acaa57efSChaoyong He static void
584acaa57efSChaoyong He nfp_nsp_load_fw_extended_msg(struct nfp_nsp *state,
585acaa57efSChaoyong He 		uint32_t ret_val)
586acaa57efSChaoyong He {
587acaa57efSChaoyong He 	uint32_t minor;
588acaa57efSChaoyong He 	uint32_t major;
589acaa57efSChaoyong He 	static const char * const major_msg[] = {
590acaa57efSChaoyong He 		/* 0 */ "Firmware from driver loaded",
591acaa57efSChaoyong He 		/* 1 */ "Firmware from flash loaded",
592acaa57efSChaoyong He 		/* 2 */ "Firmware loading failure",
593acaa57efSChaoyong He 	};
594acaa57efSChaoyong He 	static const char * const minor_msg[] = {
595acaa57efSChaoyong He 		/*  0 */ "",
596acaa57efSChaoyong He 		/*  1 */ "no named partition on flash",
597acaa57efSChaoyong He 		/*  2 */ "error reading from flash",
598acaa57efSChaoyong He 		/*  3 */ "can not deflate",
599acaa57efSChaoyong He 		/*  4 */ "not a trusted file",
600acaa57efSChaoyong He 		/*  5 */ "can not parse FW file",
601acaa57efSChaoyong He 		/*  6 */ "MIP not found in FW file",
602acaa57efSChaoyong He 		/*  7 */ "null firmware name in MIP",
603acaa57efSChaoyong He 		/*  8 */ "FW version none",
604acaa57efSChaoyong He 		/*  9 */ "FW build number none",
605acaa57efSChaoyong He 		/* 10 */ "no FW selection policy HWInfo key found",
606acaa57efSChaoyong He 		/* 11 */ "static FW selection policy",
607acaa57efSChaoyong He 		/* 12 */ "FW version has precedence",
608acaa57efSChaoyong He 		/* 13 */ "different FW application load requested",
609acaa57efSChaoyong He 		/* 14 */ "development build",
610acaa57efSChaoyong He 	};
611acaa57efSChaoyong He 
612acaa57efSChaoyong He 	major = FIELD_GET(NFP_FW_LOAD_RET_MAJOR, ret_val);
613acaa57efSChaoyong He 	minor = FIELD_GET(NFP_FW_LOAD_RET_MINOR, ret_val);
614acaa57efSChaoyong He 
615acaa57efSChaoyong He 	if (!nfp_nsp_has_stored_fw_load(state))
616acaa57efSChaoyong He 		return;
617acaa57efSChaoyong He 
618acaa57efSChaoyong He 	if (major >= RTE_DIM(major_msg))
619b6de4353SZerun Fu 		PMD_DRV_LOG(INFO, "FW loading status: %x.", ret_val);
620acaa57efSChaoyong He 	else if (minor >= RTE_DIM(minor_msg))
621b6de4353SZerun Fu 		PMD_DRV_LOG(INFO, "%s, reason code: %d.", major_msg[major], minor);
622acaa57efSChaoyong He 	else
623acaa57efSChaoyong He 		PMD_DRV_LOG(INFO, "%s%c %s", major_msg[major],
624acaa57efSChaoyong He 				minor != 0 ? ',' : '.', minor_msg[minor]);
625c7e9729dSAlejandro Lucero }
626c7e9729dSAlejandro Lucero 
627c7e9729dSAlejandro Lucero int
628d108b9e9SChaoyong He nfp_nsp_load_fw(struct nfp_nsp *state,
629d108b9e9SChaoyong He 		void *buf,
630c69debceSChaoyong He 		size_t size)
631c7e9729dSAlejandro Lucero {
632acaa57efSChaoyong He 	int ret;
633acaa57efSChaoyong He 	struct nfp_nsp_command_buf_arg load_fw = {
634acaa57efSChaoyong He 		{
635acaa57efSChaoyong He 			.code     = SPCODE_FW_LOAD,
636acaa57efSChaoyong He 			.option   = size,
637acaa57efSChaoyong He 			.error_cb = nfp_nsp_load_fw_extended_msg,
638acaa57efSChaoyong He 		},
639acaa57efSChaoyong He 		.in_buf  = buf,
640acaa57efSChaoyong He 		.in_size = size,
641acaa57efSChaoyong He 	};
642acaa57efSChaoyong He 
643acaa57efSChaoyong He 	ret = nfp_nsp_command_buf(state, &load_fw);
644acaa57efSChaoyong He 	if (ret < 0)
645acaa57efSChaoyong He 		return ret;
646acaa57efSChaoyong He 
647acaa57efSChaoyong He 	nfp_nsp_load_fw_extended_msg(state, ret);
648acaa57efSChaoyong He 
649acaa57efSChaoyong He 	return 0;
650c7e9729dSAlejandro Lucero }
651c7e9729dSAlejandro Lucero 
652f53439aaSPeng Zhang bool
653f53439aaSPeng Zhang nfp_nsp_fw_loaded(struct nfp_nsp *state)
654f53439aaSPeng Zhang {
655f53439aaSPeng Zhang 	return nfp_nsp_command(state, SPCODE_FW_LOADED) > 0;
656f53439aaSPeng Zhang }
657f53439aaSPeng Zhang 
658c7e9729dSAlejandro Lucero int
659d108b9e9SChaoyong He nfp_nsp_read_eth_table(struct nfp_nsp *state,
660d108b9e9SChaoyong He 		void *buf,
661c69debceSChaoyong He 		size_t size)
662c7e9729dSAlejandro Lucero {
663acaa57efSChaoyong He 	struct nfp_nsp_command_buf_arg eth_rescan = {
664acaa57efSChaoyong He 		{
665acaa57efSChaoyong He 			.code   = SPCODE_ETH_RESCAN,
666acaa57efSChaoyong He 			.option = size,
667acaa57efSChaoyong He 		},
668acaa57efSChaoyong He 		.out_buf  = buf,
669acaa57efSChaoyong He 		.out_size = size,
670acaa57efSChaoyong He 	};
671acaa57efSChaoyong He 
672acaa57efSChaoyong He 	return nfp_nsp_command_buf(state, &eth_rescan);
673c7e9729dSAlejandro Lucero }
674c7e9729dSAlejandro Lucero 
675c7e9729dSAlejandro Lucero int
676d108b9e9SChaoyong He nfp_nsp_write_eth_table(struct nfp_nsp *state,
677d108b9e9SChaoyong He 		const void *buf,
678c69debceSChaoyong He 		size_t size)
679c7e9729dSAlejandro Lucero {
680acaa57efSChaoyong He 	struct nfp_nsp_command_buf_arg eth_ctrl = {
681acaa57efSChaoyong He 		{
682acaa57efSChaoyong He 			.code   = SPCODE_ETH_CONTROL,
683acaa57efSChaoyong He 			.option = size,
684acaa57efSChaoyong He 		},
685acaa57efSChaoyong He 		.in_buf  = buf,
686acaa57efSChaoyong He 		.in_size = size,
687acaa57efSChaoyong He 	};
688acaa57efSChaoyong He 
689acaa57efSChaoyong He 	return nfp_nsp_command_buf(state, &eth_ctrl);
690c7e9729dSAlejandro Lucero }
691c7e9729dSAlejandro Lucero 
692c7e9729dSAlejandro Lucero int
693d108b9e9SChaoyong He nfp_nsp_read_identify(struct nfp_nsp *state,
694d108b9e9SChaoyong He 		void *buf,
695c69debceSChaoyong He 		size_t size)
696c7e9729dSAlejandro Lucero {
697acaa57efSChaoyong He 	struct nfp_nsp_command_buf_arg identify = {
698acaa57efSChaoyong He 		{
699acaa57efSChaoyong He 			.code   = SPCODE_NSP_IDENTIFY,
700acaa57efSChaoyong He 			.option = size,
701acaa57efSChaoyong He 		},
702acaa57efSChaoyong He 		.out_buf  = buf,
703acaa57efSChaoyong He 		.out_size = size,
704acaa57efSChaoyong He 	};
705acaa57efSChaoyong He 
706acaa57efSChaoyong He 	return nfp_nsp_command_buf(state, &identify);
707c7e9729dSAlejandro Lucero }
708c7e9729dSAlejandro Lucero 
709c7e9729dSAlejandro Lucero int
710d108b9e9SChaoyong He nfp_nsp_read_sensors(struct nfp_nsp *state,
711c69debceSChaoyong He 		uint32_t sensor_mask,
712d108b9e9SChaoyong He 		void *buf,
713c69debceSChaoyong He 		size_t size)
714c7e9729dSAlejandro Lucero {
715acaa57efSChaoyong He 	struct nfp_nsp_command_buf_arg sensors = {
716acaa57efSChaoyong He 		{
717acaa57efSChaoyong He 			.code   = SPCODE_NSP_SENSORS,
718acaa57efSChaoyong He 			.option = sensor_mask,
719acaa57efSChaoyong He 		},
720acaa57efSChaoyong He 		.out_buf  = buf,
721acaa57efSChaoyong He 		.out_size = size,
722acaa57efSChaoyong He 	};
723acaa57efSChaoyong He 
724acaa57efSChaoyong He 	return nfp_nsp_command_buf(state, &sensors);
725c7e9729dSAlejandro Lucero }
726c7a6970fSZerun Fu 
727c7a6970fSZerun Fu int
728c7a6970fSZerun Fu nfp_nsp_hwinfo_set(struct nfp_nsp *state,
729c7a6970fSZerun Fu 		const void *buf,
730c7a6970fSZerun Fu 		size_t size)
731c7a6970fSZerun Fu {
732c7a6970fSZerun Fu 	struct nfp_nsp_command_buf_arg hwinfo_set = {
733c7a6970fSZerun Fu 		{
734c7a6970fSZerun Fu 			.code   = SPCODE_HWINFO_SET,
735c7a6970fSZerun Fu 			.option = size,
736c7a6970fSZerun Fu 		},
737c7a6970fSZerun Fu 		.in_buf  = buf,
738c7a6970fSZerun Fu 		.in_size = size,
739c7a6970fSZerun Fu 	};
740c7a6970fSZerun Fu 
741c7a6970fSZerun Fu 	return nfp_nsp_command_buf(state, &hwinfo_set);
742c7a6970fSZerun Fu }
7433110ab73SZerun Fu 
7443110ab73SZerun Fu int
74508461d7bSPeng Zhang nfp_nsp_device_activate(struct nfp_nsp *state)
74608461d7bSPeng Zhang {
74708461d7bSPeng Zhang 	if (nfp_nsp_get_abi_ver_minor(state) < 38)
74808461d7bSPeng Zhang 		return -EOPNOTSUPP;
74908461d7bSPeng Zhang 
75008461d7bSPeng Zhang 	return nfp_nsp_command(state, SPCODE_DEV_ACTIVATE);
75108461d7bSPeng Zhang }
75208461d7bSPeng Zhang 
75308461d7bSPeng Zhang int
7543110ab73SZerun Fu nfp_nsp_read_media(struct nfp_nsp *state,
7553110ab73SZerun Fu 		void *buf,
7563110ab73SZerun Fu 		size_t size)
7573110ab73SZerun Fu {
7583110ab73SZerun Fu 	struct nfp_nsp_command_buf_arg media = {
7593110ab73SZerun Fu 		{
7603110ab73SZerun Fu 			.code   = SPCODE_READ_MEDIA,
7613110ab73SZerun Fu 			.option = size,
7623110ab73SZerun Fu 		},
7633110ab73SZerun Fu 		.out_buf  = buf,
7643110ab73SZerun Fu 		.out_size = size,
7653110ab73SZerun Fu 	};
7663110ab73SZerun Fu 
7673110ab73SZerun Fu 	return nfp_nsp_command_buf(state, &media);
7683110ab73SZerun Fu }
7699e76c352SChaoyong He 
7709e76c352SChaoyong He int
7719e76c352SChaoyong He nfp_nsp_load_stored_fw(struct nfp_nsp *state)
7729e76c352SChaoyong He {
7739e76c352SChaoyong He 	int ret;
7749e76c352SChaoyong He 	struct nfp_nsp_command_buf_arg fw_stored = {
7759e76c352SChaoyong He 		{
7769e76c352SChaoyong He 			.code     = SPCODE_FW_STORED,
7779e76c352SChaoyong He 			.error_cb = nfp_nsp_load_fw_extended_msg,
7789e76c352SChaoyong He 		},
7799e76c352SChaoyong He 	};
7809e76c352SChaoyong He 
7819e76c352SChaoyong He 	ret = nfp_nsp_command_buf(state, &fw_stored);
7829e76c352SChaoyong He 	if (ret < 0)
7839e76c352SChaoyong He 		return ret;
7849e76c352SChaoyong He 
7859e76c352SChaoyong He 	nfp_nsp_load_fw_extended_msg(state, ret);
7869e76c352SChaoyong He 
7879e76c352SChaoyong He 	return 0;
7889e76c352SChaoyong He }
7899e76c352SChaoyong He 
7909e76c352SChaoyong He static int
7919e76c352SChaoyong He nfp_nsp_hwinfo_lookup_real(struct nfp_nsp *state,
7929e76c352SChaoyong He 		void *buf,
7939e76c352SChaoyong He 		size_t size,
7949e76c352SChaoyong He 		bool optional)
7959e76c352SChaoyong He {
7969e76c352SChaoyong He 	struct nfp_nsp_command_buf_arg hwinfo_lookup = {
7979e76c352SChaoyong He 		{
7989e76c352SChaoyong He 			.code   = SPCODE_HWINFO_LOOKUP,
7999e76c352SChaoyong He 			.option = size,
8009e76c352SChaoyong He 			.error_quiet = optional,
8019e76c352SChaoyong He 		},
8029e76c352SChaoyong He 		.in_buf = buf,
8039e76c352SChaoyong He 		.in_size = size,
8049e76c352SChaoyong He 		.out_buf  = buf,
8059e76c352SChaoyong He 		.out_size = size,
8069e76c352SChaoyong He 	};
8079e76c352SChaoyong He 
8089e76c352SChaoyong He 	return nfp_nsp_command_buf(state, &hwinfo_lookup);
8099e76c352SChaoyong He }
8109e76c352SChaoyong He 
8117f693813SChaoyong He static int
8127f693813SChaoyong He nfp_nsp_read_module_eeprom_real(struct nfp_nsp *state,
8137f693813SChaoyong He 		void *buf,
8147f693813SChaoyong He 		uint32_t size)
8157f693813SChaoyong He {
8167f693813SChaoyong He 	struct nfp_nsp_command_buf_arg module_eeprom = {
8177f693813SChaoyong He 		{
8187f693813SChaoyong He 			.code   = SPCODE_READ_SFF_EEPROM,
8197f693813SChaoyong He 			.option = size,
8207f693813SChaoyong He 		},
8217f693813SChaoyong He 		.in_buf         = buf,
8227f693813SChaoyong He 		.in_size        = size,
8237f693813SChaoyong He 		.out_buf        = buf,
8247f693813SChaoyong He 		.out_size       = size,
8257f693813SChaoyong He 	};
8267f693813SChaoyong He 
8277f693813SChaoyong He 	return nfp_nsp_command_buf(state, &module_eeprom);
8287f693813SChaoyong He }
8297f693813SChaoyong He 
8307f693813SChaoyong He int
8317f693813SChaoyong He nfp_nsp_read_module_eeprom(struct nfp_nsp *state,
8327f693813SChaoyong He 		int eth_index,
8337f693813SChaoyong He 		uint32_t offset,
8347f693813SChaoyong He 		void *data,
8357f693813SChaoyong He 		uint32_t len,
8367f693813SChaoyong He 		uint32_t *read_len)
8377f693813SChaoyong He {
8387f693813SChaoyong He 	int ret;
8397f693813SChaoyong He 	int bufsz;
840*e7750639SAndre Muezerie 	struct __rte_packed_begin eeprom_buf {
8417f693813SChaoyong He 		uint8_t metalen;
8427f693813SChaoyong He 		rte_le16_t length;
8437f693813SChaoyong He 		rte_le16_t offset;
8447f693813SChaoyong He 		rte_le16_t readlen;
8457f693813SChaoyong He 		uint8_t eth_index;
8467f693813SChaoyong He 		uint8_t data[];
847*e7750639SAndre Muezerie 	} __rte_packed_end * buf;
8487f693813SChaoyong He 
8497f693813SChaoyong He 	/* Buffer must be large enough and rounded to the next block size. */
8507f693813SChaoyong He 	bufsz = sizeof(*(buf)) + sizeof((buf)->data[0]) *
8517f693813SChaoyong He 			(RTE_ALIGN_CEIL(len, NSP_SFF_EEPROM_BLOCK_LEN));
8527f693813SChaoyong He 	buf = calloc(1, bufsz);
8537f693813SChaoyong He 	if (buf == NULL)
8547f693813SChaoyong He 		return -ENOMEM;
8557f693813SChaoyong He 
8567f693813SChaoyong He 	buf->metalen = offsetof(struct eeprom_buf, data) / NSP_SFF_EEPROM_BLOCK_LEN;
8577f693813SChaoyong He 	buf->length = rte_cpu_to_le_16(len);
8587f693813SChaoyong He 	buf->offset = rte_cpu_to_le_16(offset);
8597f693813SChaoyong He 	buf->eth_index = eth_index;
8607f693813SChaoyong He 
8617f693813SChaoyong He 	ret = nfp_nsp_read_module_eeprom_real(state, buf, bufsz);
8627f693813SChaoyong He 	if (ret != 0)
8637f693813SChaoyong He 		goto free_exit;
8647f693813SChaoyong He 
8657f693813SChaoyong He 	if (rte_le_to_cpu_16(buf->readlen) < len) {
8667f693813SChaoyong He 		ret = -EIO;
8677f693813SChaoyong He 		goto free_exit;
8687f693813SChaoyong He 	}
8697f693813SChaoyong He 
8707f693813SChaoyong He 	if (len != 0)
8717f693813SChaoyong He 		memcpy(data, buf->data, len);
8727f693813SChaoyong He 
8737f693813SChaoyong He 	*read_len = len;
8747f693813SChaoyong He 
8757f693813SChaoyong He free_exit:
8767f693813SChaoyong He 	free(buf);
8777f693813SChaoyong He 	return ret;
8787f693813SChaoyong He }
8797f693813SChaoyong He 
8807f693813SChaoyong He int
8817f693813SChaoyong He nfp_nsp_hwinfo_lookup(struct nfp_nsp *state,
8827f693813SChaoyong He 		void *buf,
8837f693813SChaoyong He 		uint32_t size)
8847f693813SChaoyong He {
8857f693813SChaoyong He 	int ret;
8867f693813SChaoyong He 	uint32_t size_tmp;
8877f693813SChaoyong He 
8887f693813SChaoyong He 	if (!nfp_nsp_has_hwinfo_lookup(state)) {
8897f693813SChaoyong He 		PMD_DRV_LOG(ERR, "NSP HWinfo lookup not supported. Please update flash.");
8907f693813SChaoyong He 		return -EOPNOTSUPP;
8917f693813SChaoyong He 	}
8927f693813SChaoyong He 
8937f693813SChaoyong He 	size_tmp = RTE_MIN(size, NFP_HWINFO_LOOKUP_SIZE);
8947f693813SChaoyong He 
8957f693813SChaoyong He 	ret = nfp_nsp_hwinfo_lookup_real(state, buf, size, false);
8967f693813SChaoyong He 	if (ret != 0)
8977f693813SChaoyong He 		return ret;
8987f693813SChaoyong He 
8997f693813SChaoyong He 	if (strnlen(buf, size_tmp) == size_tmp) {
9007f693813SChaoyong He 		PMD_DRV_LOG(ERR, "NSP HWinfo value not NULL terminated.");
9017f693813SChaoyong He 		return -EINVAL;
9027f693813SChaoyong He 	}
9037f693813SChaoyong He 
9047f693813SChaoyong He 	return 0;
9057f693813SChaoyong He }
9067f693813SChaoyong He 
9079e76c352SChaoyong He int
9089e76c352SChaoyong He nfp_nsp_hwinfo_lookup_optional(struct nfp_nsp *state,
9099e76c352SChaoyong He 		void *buf,
9109e76c352SChaoyong He 		size_t size,
9119e76c352SChaoyong He 		const char *default_val)
9129e76c352SChaoyong He {
9139e76c352SChaoyong He 	int ret;
9149e76c352SChaoyong He 	size_t min_size;
9159e76c352SChaoyong He 
9169e76c352SChaoyong He 	if (strnlen(default_val, size) == size) {
917b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NSP HWinfo default value not NULL terminated.");
9189e76c352SChaoyong He 		return -EINVAL;
9199e76c352SChaoyong He 	}
9209e76c352SChaoyong He 
9219e76c352SChaoyong He 	if (!nfp_nsp_has_hwinfo_lookup(state))
9229e76c352SChaoyong He 		goto default_return;
9239e76c352SChaoyong He 
9249e76c352SChaoyong He 	min_size = RTE_MIN(size, NFP_HWINFO_LOOKUP_SIZE);
9259e76c352SChaoyong He 	ret = nfp_nsp_hwinfo_lookup_real(state, buf, min_size, true);
9269e76c352SChaoyong He 	if (ret != 0) {
9279e76c352SChaoyong He 		if (ret == -ENOENT)
9289e76c352SChaoyong He 			goto default_return;
9299e76c352SChaoyong He 
930b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NSP HWinfo lookup failed: %d.", ret);
9319e76c352SChaoyong He 		return ret;
9329e76c352SChaoyong He 	}
9339e76c352SChaoyong He 
9349e76c352SChaoyong He 	if (strnlen(buf, min_size) == min_size) {
935b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NSP HWinfo value not NULL terminated.");
9369e76c352SChaoyong He 		return -EINVAL;
9379e76c352SChaoyong He 	}
9389e76c352SChaoyong He 
9399e76c352SChaoyong He 	return 0;
9409e76c352SChaoyong He 
9419e76c352SChaoyong He default_return:
9429e76c352SChaoyong He 	strlcpy(buf, default_val, size);
9439e76c352SChaoyong He 	return 0;
9449e76c352SChaoyong He }
945