xref: /f-stack/dpdk/drivers/net/nfp/nfpcore/nfp_nffw.c (revision d30ea906)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Netronome Systems, Inc.
3  * All rights reserved.
4  */
5 
6 #include "nfp_cpp.h"
7 #include "nfp_nffw.h"
8 #include "nfp_mip.h"
9 #include "nfp6000/nfp6000.h"
10 #include "nfp_resource.h"
11 
12 /*
13  * flg_info_version = flags[0]<27:16>
14  * This is a small version counter intended only to detect if the current
15  * implementation can read the current struct. Struct changes should be very
16  * rare and as such a 12-bit counter should cover large spans of time. By the
17  * time it wraps around, we don't expect to have 4096 versions of this struct
18  * to be in use at the same time.
19  */
20 static uint32_t
nffw_res_info_version_get(const struct nfp_nffw_info_data * res)21 nffw_res_info_version_get(const struct nfp_nffw_info_data *res)
22 {
23 	return (res->flags[0] >> 16) & 0xfff;
24 }
25 
26 /* flg_init = flags[0]<0> */
27 static uint32_t
nffw_res_flg_init_get(const struct nfp_nffw_info_data * res)28 nffw_res_flg_init_get(const struct nfp_nffw_info_data *res)
29 {
30 	return (res->flags[0] >> 0) & 1;
31 }
32 
33 /* loaded = loaded__mu_da__mip_off_hi<31:31> */
34 static uint32_t
nffw_fwinfo_loaded_get(const struct nffw_fwinfo * fi)35 nffw_fwinfo_loaded_get(const struct nffw_fwinfo *fi)
36 {
37 	return (fi->loaded__mu_da__mip_off_hi >> 31) & 1;
38 }
39 
40 /* mip_cppid = mip_cppid */
41 static uint32_t
nffw_fwinfo_mip_cppid_get(const struct nffw_fwinfo * fi)42 nffw_fwinfo_mip_cppid_get(const struct nffw_fwinfo *fi)
43 {
44 	return fi->mip_cppid;
45 }
46 
47 /* loaded = loaded__mu_da__mip_off_hi<8:8> */
48 static uint32_t
nffw_fwinfo_mip_mu_da_get(const struct nffw_fwinfo * fi)49 nffw_fwinfo_mip_mu_da_get(const struct nffw_fwinfo *fi)
50 {
51 	return (fi->loaded__mu_da__mip_off_hi >> 8) & 1;
52 }
53 
54 /* mip_offset = (loaded__mu_da__mip_off_hi<7:0> << 8) | mip_offset_lo */
55 static uint64_t
nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo * fi)56 nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi)
57 {
58 	uint64_t mip_off_hi = fi->loaded__mu_da__mip_off_hi;
59 
60 	return (mip_off_hi & 0xFF) << 32 | fi->mip_offset_lo;
61 }
62 
63 #define NFP_IMB_TGTADDRESSMODECFG_MODE_of(_x)		(((_x) >> 13) & 0x7)
64 #define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE		BIT(12)
65 #define   NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_32_BIT	0
66 #define   NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_40_BIT	BIT(12)
67 
68 static int
nfp_mip_mu_locality_lsb(struct nfp_cpp * cpp)69 nfp_mip_mu_locality_lsb(struct nfp_cpp *cpp)
70 {
71 	unsigned int mode, addr40;
72 	uint32_t xpbaddr, imbcppat;
73 	int err;
74 
75 	/* Hardcoded XPB IMB Base, island 0 */
76 	xpbaddr = 0x000a0000 + NFP_CPP_TARGET_MU * 4;
77 	err = nfp_xpb_readl(cpp, xpbaddr, &imbcppat);
78 	if (err < 0)
79 		return err;
80 
81 	mode = NFP_IMB_TGTADDRESSMODECFG_MODE_of(imbcppat);
82 	addr40 = !!(imbcppat & NFP_IMB_TGTADDRESSMODECFG_ADDRMODE);
83 
84 	return nfp_cppat_mu_locality_lsb(mode, addr40);
85 }
86 
87 static unsigned int
nffw_res_fwinfos(struct nfp_nffw_info_data * fwinf,struct nffw_fwinfo ** arr)88 nffw_res_fwinfos(struct nfp_nffw_info_data *fwinf, struct nffw_fwinfo **arr)
89 {
90 	/*
91 	 * For the this code, version 0 is most likely to be version 1 in this
92 	 * case. Since the kernel driver does not take responsibility for
93 	 * initialising the nfp.nffw resource, any previous code (CA firmware or
94 	 * userspace) that left the version 0 and did set the init flag is going
95 	 * to be version 1.
96 	 */
97 	switch (nffw_res_info_version_get(fwinf)) {
98 	case 0:
99 	case 1:
100 		*arr = &fwinf->info.v1.fwinfo[0];
101 		return NFFW_FWINFO_CNT_V1;
102 	case 2:
103 		*arr = &fwinf->info.v2.fwinfo[0];
104 		return NFFW_FWINFO_CNT_V2;
105 	default:
106 		*arr = NULL;
107 		return 0;
108 	}
109 }
110 
111 /*
112  * nfp_nffw_info_open() - Acquire the lock on the NFFW table
113  * @cpp:	NFP CPP handle
114  *
115  * Return: 0, or -ERRNO
116  */
117 struct nfp_nffw_info *
nfp_nffw_info_open(struct nfp_cpp * cpp)118 nfp_nffw_info_open(struct nfp_cpp *cpp)
119 {
120 	struct nfp_nffw_info_data *fwinf;
121 	struct nfp_nffw_info *state;
122 	uint32_t info_ver;
123 	int err;
124 
125 	state = malloc(sizeof(*state));
126 	if (!state)
127 		return NULL;
128 
129 	memset(state, 0, sizeof(*state));
130 
131 	state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW);
132 	if (!state->res)
133 		goto err_free;
134 
135 	fwinf = &state->fwinf;
136 
137 	if (sizeof(*fwinf) > nfp_resource_size(state->res))
138 		goto err_release;
139 
140 	err = nfp_cpp_read(cpp, nfp_resource_cpp_id(state->res),
141 			   nfp_resource_address(state->res),
142 			   fwinf, sizeof(*fwinf));
143 	if (err < (int)sizeof(*fwinf))
144 		goto err_release;
145 
146 	if (!nffw_res_flg_init_get(fwinf))
147 		goto err_release;
148 
149 	info_ver = nffw_res_info_version_get(fwinf);
150 	if (info_ver > NFFW_INFO_VERSION_CURRENT)
151 		goto err_release;
152 
153 	state->cpp = cpp;
154 	return state;
155 
156 err_release:
157 	nfp_resource_release(state->res);
158 err_free:
159 	free(state);
160 	return NULL;
161 }
162 
163 /*
164  * nfp_nffw_info_release() - Release the lock on the NFFW table
165  * @state:	NFP FW info state
166  *
167  * Return: 0, or -ERRNO
168  */
169 void
nfp_nffw_info_close(struct nfp_nffw_info * state)170 nfp_nffw_info_close(struct nfp_nffw_info *state)
171 {
172 	nfp_resource_release(state->res);
173 	free(state);
174 }
175 
176 /*
177  * nfp_nffw_info_fwid_first() - Return the first firmware ID in the NFFW
178  * @state:	NFP FW info state
179  *
180  * Return: First NFFW firmware info, NULL on failure
181  */
182 static struct nffw_fwinfo *
nfp_nffw_info_fwid_first(struct nfp_nffw_info * state)183 nfp_nffw_info_fwid_first(struct nfp_nffw_info *state)
184 {
185 	struct nffw_fwinfo *fwinfo;
186 	unsigned int cnt, i;
187 
188 	cnt = nffw_res_fwinfos(&state->fwinf, &fwinfo);
189 	if (!cnt)
190 		return NULL;
191 
192 	for (i = 0; i < cnt; i++)
193 		if (nffw_fwinfo_loaded_get(&fwinfo[i]))
194 			return &fwinfo[i];
195 
196 	return NULL;
197 }
198 
199 /*
200  * nfp_nffw_info_mip_first() - Retrieve the location of the first FW's MIP
201  * @state:	NFP FW info state
202  * @cpp_id:	Pointer to the CPP ID of the MIP
203  * @off:	Pointer to the CPP Address of the MIP
204  *
205  * Return: 0, or -ERRNO
206  */
207 int
nfp_nffw_info_mip_first(struct nfp_nffw_info * state,uint32_t * cpp_id,uint64_t * off)208 nfp_nffw_info_mip_first(struct nfp_nffw_info *state, uint32_t *cpp_id,
209 			uint64_t *off)
210 {
211 	struct nffw_fwinfo *fwinfo;
212 
213 	fwinfo = nfp_nffw_info_fwid_first(state);
214 	if (!fwinfo)
215 		return -EINVAL;
216 
217 	*cpp_id = nffw_fwinfo_mip_cppid_get(fwinfo);
218 	*off = nffw_fwinfo_mip_offset_get(fwinfo);
219 
220 	if (nffw_fwinfo_mip_mu_da_get(fwinfo)) {
221 		int locality_off;
222 
223 		if (NFP_CPP_ID_TARGET_of(*cpp_id) != NFP_CPP_TARGET_MU)
224 			return 0;
225 
226 		locality_off = nfp_mip_mu_locality_lsb(state->cpp);
227 		if (locality_off < 0)
228 			return locality_off;
229 
230 		*off &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
231 		*off |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
232 	}
233 
234 	return 0;
235 }
236