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