xref: /dpdk/drivers/net/nfp/nfpcore/nfp_nffw.c (revision b6de43530dfa30cbf6b70857e3835099701063d4)
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 
6c7e9729dSAlejandro Lucero #include "nfp_nffw.h"
7a68914baSChaoyong He 
8a68914baSChaoyong He #include "../nfp_logs.h"
9c7e9729dSAlejandro Lucero #include "nfp_mip.h"
10c7e9729dSAlejandro Lucero #include "nfp_resource.h"
11a68914baSChaoyong He #include "nfp6000/nfp6000.h"
12a68914baSChaoyong He 
13a68914baSChaoyong He /*
14a68914baSChaoyong He  * Init-CSR owner IDs for firmware map to firmware IDs which start at 4.
15a68914baSChaoyong He  * Lower IDs are reserved for target and loader IDs.
16a68914baSChaoyong He  */
17a68914baSChaoyong He #define NFFW_FWID_EXT   3 /* For active MEs that we didn't load. */
18a68914baSChaoyong He #define NFFW_FWID_BASE  4
19a68914baSChaoyong He 
20a68914baSChaoyong He #define NFFW_FWID_ALL   255
21a68914baSChaoyong He 
22a68914baSChaoyong He /*
23a68914baSChaoyong He  * NFFW_INFO_VERSION history:
24a68914baSChaoyong He  * 0: This was never actually used (before versioning), but it refers to
25a68914baSChaoyong He  *    the previous struct which had FWINFO_CNT = MEINFO_CNT = 120 that later
26a68914baSChaoyong He  *    changed to 200.
27a68914baSChaoyong He  * 1: First versioned struct, with
28a68914baSChaoyong He  *     FWINFO_CNT = 120
29a68914baSChaoyong He  *     MEINFO_CNT = 120
30a68914baSChaoyong He  * 2:  FWINFO_CNT = 200
31a68914baSChaoyong He  *     MEINFO_CNT = 200
32a68914baSChaoyong He  */
33a68914baSChaoyong He #define NFFW_INFO_VERSION_CURRENT 2
34a68914baSChaoyong He 
35a68914baSChaoyong He /* Enough for all current chip families */
36a68914baSChaoyong He #define NFFW_MEINFO_CNT_V1 120
37a68914baSChaoyong He #define NFFW_FWINFO_CNT_V1 120
38a68914baSChaoyong He #define NFFW_MEINFO_CNT_V2 200
39a68914baSChaoyong He #define NFFW_FWINFO_CNT_V2 200
40a68914baSChaoyong He 
41a68914baSChaoyong He /* nfp.nffw meinfo */
42a68914baSChaoyong He struct nffw_meinfo {
43a68914baSChaoyong He 	uint32_t ctxmask_fwid_meid;
44a68914baSChaoyong He };
45a68914baSChaoyong He 
46a68914baSChaoyong He struct nffw_fwinfo {
47a68914baSChaoyong He 	uint32_t loaded_mu_da_mip_off_hi;
48a68914baSChaoyong He 	uint32_t mip_cppid; /**< 0 means no MIP */
49a68914baSChaoyong He 	uint32_t mip_offset_lo;
50a68914baSChaoyong He };
51a68914baSChaoyong He 
52a68914baSChaoyong He struct nfp_nffw_info_v1 {
53a68914baSChaoyong He 	struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V1];
54a68914baSChaoyong He 	struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V1];
55a68914baSChaoyong He };
56a68914baSChaoyong He 
57a68914baSChaoyong He struct nfp_nffw_info_v2 {
58a68914baSChaoyong He 	struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V2];
59a68914baSChaoyong He 	struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V2];
60a68914baSChaoyong He };
61a68914baSChaoyong He 
62a68914baSChaoyong He struct nfp_nffw_info_data {
63a68914baSChaoyong He 	uint32_t flags[2];
64a68914baSChaoyong He 	union {
65a68914baSChaoyong He 		struct nfp_nffw_info_v1 v1;
66a68914baSChaoyong He 		struct nfp_nffw_info_v2 v2;
67a68914baSChaoyong He 	} info;
68a68914baSChaoyong He };
69a68914baSChaoyong He 
70a68914baSChaoyong He struct nfp_nffw_info {
71a68914baSChaoyong He 	struct nfp_cpp *cpp;
72a68914baSChaoyong He 	struct nfp_resource *res;
73a68914baSChaoyong He 
74a68914baSChaoyong He 	struct nfp_nffw_info_data fwinf;
75a68914baSChaoyong He };
76c7e9729dSAlejandro Lucero 
77c7e9729dSAlejandro Lucero /*
78c7e9729dSAlejandro Lucero  * flg_info_version = flags[0]<27:16>
79c7e9729dSAlejandro Lucero  * This is a small version counter intended only to detect if the current
80c7e9729dSAlejandro Lucero  * implementation can read the current struct. Struct changes should be very
81c7e9729dSAlejandro Lucero  * rare and as such a 12-bit counter should cover large spans of time. By the
82c7e9729dSAlejandro Lucero  * time it wraps around, we don't expect to have 4096 versions of this struct
83c7e9729dSAlejandro Lucero  * to be in use at the same time.
84c7e9729dSAlejandro Lucero  */
85c7e9729dSAlejandro Lucero static uint32_t
86c7e9729dSAlejandro Lucero nffw_res_info_version_get(const struct nfp_nffw_info_data *res)
87c7e9729dSAlejandro Lucero {
88c7e9729dSAlejandro Lucero 	return (res->flags[0] >> 16) & 0xfff;
89c7e9729dSAlejandro Lucero }
90c7e9729dSAlejandro Lucero 
91c7e9729dSAlejandro Lucero /* flg_init = flags[0]<0> */
92c7e9729dSAlejandro Lucero static uint32_t
93c7e9729dSAlejandro Lucero nffw_res_flg_init_get(const struct nfp_nffw_info_data *res)
94c7e9729dSAlejandro Lucero {
95c7e9729dSAlejandro Lucero 	return (res->flags[0] >> 0) & 1;
96c7e9729dSAlejandro Lucero }
97c7e9729dSAlejandro Lucero 
98588c5b10SChaoyong He /* loaded = loaded_mu_da_mip_off_hi<31:31> */
99c7e9729dSAlejandro Lucero static uint32_t
100c7e9729dSAlejandro Lucero nffw_fwinfo_loaded_get(const struct nffw_fwinfo *fi)
101c7e9729dSAlejandro Lucero {
102588c5b10SChaoyong He 	return (fi->loaded_mu_da_mip_off_hi >> 31) & 1;
103c7e9729dSAlejandro Lucero }
104c7e9729dSAlejandro Lucero 
105c7e9729dSAlejandro Lucero /* mip_cppid = mip_cppid */
106c7e9729dSAlejandro Lucero static uint32_t
107c7e9729dSAlejandro Lucero nffw_fwinfo_mip_cppid_get(const struct nffw_fwinfo *fi)
108c7e9729dSAlejandro Lucero {
109c7e9729dSAlejandro Lucero 	return fi->mip_cppid;
110c7e9729dSAlejandro Lucero }
111c7e9729dSAlejandro Lucero 
112588c5b10SChaoyong He /* loaded = loaded_mu_da_mip_off_hi<8:8> */
113c7e9729dSAlejandro Lucero static uint32_t
114c7e9729dSAlejandro Lucero nffw_fwinfo_mip_mu_da_get(const struct nffw_fwinfo *fi)
115c7e9729dSAlejandro Lucero {
116588c5b10SChaoyong He 	return (fi->loaded_mu_da_mip_off_hi >> 8) & 1;
117c7e9729dSAlejandro Lucero }
118c7e9729dSAlejandro Lucero 
119588c5b10SChaoyong He /* mip_offset = (loaded_mu_da_mip_off_hi<7:0> << 32) | mip_offset_lo */
120c7e9729dSAlejandro Lucero static uint64_t
121c7e9729dSAlejandro Lucero nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi)
122c7e9729dSAlejandro Lucero {
123588c5b10SChaoyong He 	uint64_t mip_off_hi = fi->loaded_mu_da_mip_off_hi;
124c7e9729dSAlejandro Lucero 
125c7e9729dSAlejandro Lucero 	return (mip_off_hi & 0xFF) << 32 | fi->mip_offset_lo;
126c7e9729dSAlejandro Lucero }
127c7e9729dSAlejandro Lucero 
128c69debceSChaoyong He static uint32_t
129d108b9e9SChaoyong He nffw_res_fwinfos(struct nfp_nffw_info_data *fwinf,
130d108b9e9SChaoyong He 		struct nffw_fwinfo **arr)
131c7e9729dSAlejandro Lucero {
132c7e9729dSAlejandro Lucero 	/*
133c7e9729dSAlejandro Lucero 	 * For the this code, version 0 is most likely to be version 1 in this
134c7e9729dSAlejandro Lucero 	 * case. Since the kernel driver does not take responsibility for
135c7e9729dSAlejandro Lucero 	 * initialising the nfp.nffw resource, any previous code (CA firmware or
136c7e9729dSAlejandro Lucero 	 * userspace) that left the version 0 and did set the init flag is going
137c7e9729dSAlejandro Lucero 	 * to be version 1.
138c7e9729dSAlejandro Lucero 	 */
139c7e9729dSAlejandro Lucero 	switch (nffw_res_info_version_get(fwinf)) {
140c7e9729dSAlejandro Lucero 	case 0:
141c7e9729dSAlejandro Lucero 	case 1:
142c7e9729dSAlejandro Lucero 		*arr = &fwinf->info.v1.fwinfo[0];
143c7e9729dSAlejandro Lucero 		return NFFW_FWINFO_CNT_V1;
144c7e9729dSAlejandro Lucero 	case 2:
145c7e9729dSAlejandro Lucero 		*arr = &fwinf->info.v2.fwinfo[0];
146c7e9729dSAlejandro Lucero 		return NFFW_FWINFO_CNT_V2;
147c7e9729dSAlejandro Lucero 	default:
148c7e9729dSAlejandro Lucero 		*arr = NULL;
149c7e9729dSAlejandro Lucero 		return 0;
150c7e9729dSAlejandro Lucero 	}
151c7e9729dSAlejandro Lucero }
152c7e9729dSAlejandro Lucero 
1536d03aa61SChaoyong He /**
1546d03aa61SChaoyong He  * Acquire the lock on the NFFW table
155c7e9729dSAlejandro Lucero  *
1566d03aa61SChaoyong He  * @param cpp
1576d03aa61SChaoyong He  *   NFP CPP handle
1586d03aa61SChaoyong He  *
1596d03aa61SChaoyong He  * @return
1606d03aa61SChaoyong He  *   NFFW info pointer, or NULL on failure
161c7e9729dSAlejandro Lucero  */
162c7e9729dSAlejandro Lucero struct nfp_nffw_info *
163c7e9729dSAlejandro Lucero nfp_nffw_info_open(struct nfp_cpp *cpp)
164c7e9729dSAlejandro Lucero {
165c7e9729dSAlejandro Lucero 	int err;
166610bf14bSChaoyong He 	uint32_t info_ver;
167610bf14bSChaoyong He 	struct nfp_nffw_info *state;
168610bf14bSChaoyong He 	struct nfp_nffw_info_data *fwinf;
169c7e9729dSAlejandro Lucero 
170c7e9729dSAlejandro Lucero 	state = malloc(sizeof(*state));
171cbcbfd73SJames Hershaw 	if (state == NULL)
172c7e9729dSAlejandro Lucero 		return NULL;
173c7e9729dSAlejandro Lucero 
174c7e9729dSAlejandro Lucero 	memset(state, 0, sizeof(*state));
175c7e9729dSAlejandro Lucero 
176c7e9729dSAlejandro Lucero 	state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW);
177efa766e1SChaoyong He 	if (state->res == NULL) {
178*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NFFW - acquire resource failed.");
179c7e9729dSAlejandro Lucero 		goto err_free;
180efa766e1SChaoyong He 	}
181c7e9729dSAlejandro Lucero 
182c7e9729dSAlejandro Lucero 	fwinf = &state->fwinf;
183c7e9729dSAlejandro Lucero 
184c7e9729dSAlejandro Lucero 	if (sizeof(*fwinf) > nfp_resource_size(state->res))
185c7e9729dSAlejandro Lucero 		goto err_release;
186c7e9729dSAlejandro Lucero 
187c7e9729dSAlejandro Lucero 	err = nfp_cpp_read(cpp, nfp_resource_cpp_id(state->res),
188c7e9729dSAlejandro Lucero 			nfp_resource_address(state->res),
189c7e9729dSAlejandro Lucero 			fwinf, sizeof(*fwinf));
190efa766e1SChaoyong He 	if (err < (int)sizeof(*fwinf)) {
191*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "NFFW - CPP read error %d.", err);
192c7e9729dSAlejandro Lucero 		goto err_release;
193efa766e1SChaoyong He 	}
194c7e9729dSAlejandro Lucero 
195cbcbfd73SJames Hershaw 	if (nffw_res_flg_init_get(fwinf) == 0)
196c7e9729dSAlejandro Lucero 		goto err_release;
197c7e9729dSAlejandro Lucero 
198c7e9729dSAlejandro Lucero 	info_ver = nffw_res_info_version_get(fwinf);
199c7e9729dSAlejandro Lucero 	if (info_ver > NFFW_INFO_VERSION_CURRENT)
200c7e9729dSAlejandro Lucero 		goto err_release;
201c7e9729dSAlejandro Lucero 
202c7e9729dSAlejandro Lucero 	state->cpp = cpp;
203c7e9729dSAlejandro Lucero 	return state;
204c7e9729dSAlejandro Lucero 
205c7e9729dSAlejandro Lucero err_release:
206c7e9729dSAlejandro Lucero 	nfp_resource_release(state->res);
207c7e9729dSAlejandro Lucero err_free:
208c7e9729dSAlejandro Lucero 	free(state);
209c7e9729dSAlejandro Lucero 	return NULL;
210c7e9729dSAlejandro Lucero }
211c7e9729dSAlejandro Lucero 
2126d03aa61SChaoyong He /**
2136d03aa61SChaoyong He  * Release the lock on the NFFW table
214c7e9729dSAlejandro Lucero  *
2156d03aa61SChaoyong He  * @param state
2166d03aa61SChaoyong He  *   NFFW info pointer
217c7e9729dSAlejandro Lucero  */
218c7e9729dSAlejandro Lucero void
219c7e9729dSAlejandro Lucero nfp_nffw_info_close(struct nfp_nffw_info *state)
220c7e9729dSAlejandro Lucero {
221c7e9729dSAlejandro Lucero 	nfp_resource_release(state->res);
222c7e9729dSAlejandro Lucero 	free(state);
223c7e9729dSAlejandro Lucero }
224c7e9729dSAlejandro Lucero 
2256d03aa61SChaoyong He /**
2266d03aa61SChaoyong He  * Return the first firmware ID in the NFFW
227c7e9729dSAlejandro Lucero  *
2286d03aa61SChaoyong He  * @param state
2296d03aa61SChaoyong He  *   NFFW info pointer
2306d03aa61SChaoyong He  *
2316d03aa61SChaoyong He  * @return:
2326d03aa61SChaoyong He  *   First NFFW firmware info, NULL on failure
233c7e9729dSAlejandro Lucero  */
234c7e9729dSAlejandro Lucero static struct nffw_fwinfo *
235c7e9729dSAlejandro Lucero nfp_nffw_info_fwid_first(struct nfp_nffw_info *state)
236c7e9729dSAlejandro Lucero {
237610bf14bSChaoyong He 	uint32_t i;
238610bf14bSChaoyong He 	uint32_t cnt;
239c7e9729dSAlejandro Lucero 	struct nffw_fwinfo *fwinfo;
240c7e9729dSAlejandro Lucero 
241c7e9729dSAlejandro Lucero 	cnt = nffw_res_fwinfos(&state->fwinf, &fwinfo);
242cbcbfd73SJames Hershaw 	if (cnt == 0)
243c7e9729dSAlejandro Lucero 		return NULL;
244c7e9729dSAlejandro Lucero 
245c7e9729dSAlejandro Lucero 	for (i = 0; i < cnt; i++)
2464aa75cadSChaoyong He 		if (nffw_fwinfo_loaded_get(&fwinfo[i]) != 0)
247c7e9729dSAlejandro Lucero 			return &fwinfo[i];
248c7e9729dSAlejandro Lucero 
249c7e9729dSAlejandro Lucero 	return NULL;
250c7e9729dSAlejandro Lucero }
251c7e9729dSAlejandro Lucero 
2526d03aa61SChaoyong He /**
2536d03aa61SChaoyong He  * Retrieve the location of the first FW's MIP
254c7e9729dSAlejandro Lucero  *
2556d03aa61SChaoyong He  * @param state
2566d03aa61SChaoyong He  *   NFFW info pointer
2576d03aa61SChaoyong He  * @param cpp_id
2586d03aa61SChaoyong He  *   Pointer to the CPP ID of the MIP
2596d03aa61SChaoyong He  * @param off
2606d03aa61SChaoyong He  *   Pointer to the CPP Address of the MIP
2616d03aa61SChaoyong He  *
2626d03aa61SChaoyong He  * @return
2636d03aa61SChaoyong He  *   0, or -ERRNO
264c7e9729dSAlejandro Lucero  */
265c7e9729dSAlejandro Lucero int
266d108b9e9SChaoyong He nfp_nffw_info_mip_first(struct nfp_nffw_info *state,
267d108b9e9SChaoyong He 		uint32_t *cpp_id,
268588c5b10SChaoyong He 		uint64_t *offset)
269c7e9729dSAlejandro Lucero {
270c7e9729dSAlejandro Lucero 	struct nffw_fwinfo *fwinfo;
271c7e9729dSAlejandro Lucero 
272c7e9729dSAlejandro Lucero 	fwinfo = nfp_nffw_info_fwid_first(state);
273cbcbfd73SJames Hershaw 	if (fwinfo == NULL)
274c7e9729dSAlejandro Lucero 		return -EINVAL;
275c7e9729dSAlejandro Lucero 
276c7e9729dSAlejandro Lucero 	*cpp_id = nffw_fwinfo_mip_cppid_get(fwinfo);
277588c5b10SChaoyong He 	*offset = nffw_fwinfo_mip_offset_get(fwinfo);
278c7e9729dSAlejandro Lucero 
2794aa75cadSChaoyong He 	if (nffw_fwinfo_mip_mu_da_get(fwinfo) != 0) {
280a68914baSChaoyong He 		int locality_off = nfp_cpp_mu_locality_lsb(state->cpp);
281c7e9729dSAlejandro Lucero 
282588c5b10SChaoyong He 		*offset &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
283588c5b10SChaoyong He 		*offset |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
284c7e9729dSAlejandro Lucero 	}
285c7e9729dSAlejandro Lucero 
286c7e9729dSAlejandro Lucero 	return 0;
287c7e9729dSAlejandro Lucero }
288