1
2
3
4
5
6
7
8
9
10
11#include <linux/kernel.h>
12#include <linux/slab.h>
13
14#include "nfp.h"
15#include "nfp_cpp.h"
16#include "nfp_nffw.h"
17#include "nfp6000/nfp6000.h"
18
19
20
21
22#define NFFW_FWID_EXT 3
23#define NFFW_FWID_BASE 4
24
25#define NFFW_FWID_ALL 255
26
27
28
29
30
31
32
33
34
35
36
37
38#define NFFW_INFO_VERSION_CURRENT 2
39
40
41#define NFFW_MEINFO_CNT_V1 120
42#define NFFW_FWINFO_CNT_V1 120
43#define NFFW_MEINFO_CNT_V2 200
44#define NFFW_FWINFO_CNT_V2 200
45
46
47
48
49struct nffw_meinfo {
50 __le32 ctxmask__fwid__meid;
51};
52
53struct nffw_fwinfo {
54 __le32 loaded__mu_da__mip_off_hi;
55 __le32 mip_cppid;
56 __le32 mip_offset_lo;
57};
58
59struct nfp_nffw_info_v1 {
60 struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V1];
61 struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V1];
62};
63
64struct nfp_nffw_info_v2 {
65 struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V2];
66 struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V2];
67};
68
69
70struct nfp_nffw_info_data {
71 __le32 flags[2];
72 union {
73 struct nfp_nffw_info_v1 v1;
74 struct nfp_nffw_info_v2 v2;
75 } info;
76};
77
78struct nfp_nffw_info {
79 struct nfp_cpp *cpp;
80 struct nfp_resource *res;
81
82 struct nfp_nffw_info_data fwinf;
83};
84
85
86
87
88
89
90
91
92static u32 nffw_res_info_version_get(const struct nfp_nffw_info_data *res)
93{
94 return (le32_to_cpu(res->flags[0]) >> 16) & 0xfff;
95}
96
97
98static u32 nffw_res_flg_init_get(const struct nfp_nffw_info_data *res)
99{
100 return (le32_to_cpu(res->flags[0]) >> 0) & 1;
101}
102
103
104static u32 nffw_fwinfo_loaded_get(const struct nffw_fwinfo *fi)
105{
106 return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 31) & 1;
107}
108
109
110static u32 nffw_fwinfo_mip_cppid_get(const struct nffw_fwinfo *fi)
111{
112 return le32_to_cpu(fi->mip_cppid);
113}
114
115
116static u32 nffw_fwinfo_mip_mu_da_get(const struct nffw_fwinfo *fi)
117{
118 return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 8) & 1;
119}
120
121
122static u64 nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi)
123{
124 u64 mip_off_hi = le32_to_cpu(fi->loaded__mu_da__mip_off_hi);
125
126 return (mip_off_hi & 0xFF) << 32 | le32_to_cpu(fi->mip_offset_lo);
127}
128
129static unsigned int
130nffw_res_fwinfos(struct nfp_nffw_info_data *fwinf, struct nffw_fwinfo **arr)
131{
132
133
134
135
136
137
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
155
156
157
158
159struct nfp_nffw_info *nfp_nffw_info_open(struct nfp_cpp *cpp)
160{
161 struct nfp_nffw_info_data *fwinf;
162 struct nfp_nffw_info *state;
163 u32 info_ver;
164 int err;
165
166 state = kzalloc(sizeof(*state), GFP_KERNEL);
167 if (!state)
168 return ERR_PTR(-ENOMEM);
169
170 state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW);
171 if (IS_ERR(state->res))
172 goto err_free;
173
174 fwinf = &state->fwinf;
175
176 if (sizeof(*fwinf) > nfp_resource_size(state->res))
177 goto err_release;
178
179 err = nfp_cpp_read(cpp, nfp_resource_cpp_id(state->res),
180 nfp_resource_address(state->res),
181 fwinf, sizeof(*fwinf));
182 if (err < (int)sizeof(*fwinf))
183 goto err_release;
184
185 if (!nffw_res_flg_init_get(fwinf))
186 goto err_release;
187
188 info_ver = nffw_res_info_version_get(fwinf);
189 if (info_ver > NFFW_INFO_VERSION_CURRENT)
190 goto err_release;
191
192 state->cpp = cpp;
193 return state;
194
195err_release:
196 nfp_resource_release(state->res);
197err_free:
198 kfree(state);
199 return ERR_PTR(-EIO);
200}
201
202
203
204
205
206void nfp_nffw_info_close(struct nfp_nffw_info *state)
207{
208 nfp_resource_release(state->res);
209 kfree(state);
210}
211
212
213
214
215
216
217
218static struct nffw_fwinfo *nfp_nffw_info_fwid_first(struct nfp_nffw_info *state)
219{
220 struct nffw_fwinfo *fwinfo;
221 unsigned int cnt, i;
222
223 cnt = nffw_res_fwinfos(&state->fwinf, &fwinfo);
224 if (!cnt)
225 return NULL;
226
227 for (i = 0; i < cnt; i++)
228 if (nffw_fwinfo_loaded_get(&fwinfo[i]))
229 return &fwinfo[i];
230
231 return NULL;
232}
233
234
235
236
237
238
239
240
241
242int nfp_nffw_info_mip_first(struct nfp_nffw_info *state, u32 *cpp_id, u64 *off)
243{
244 struct nffw_fwinfo *fwinfo;
245
246 fwinfo = nfp_nffw_info_fwid_first(state);
247 if (!fwinfo)
248 return -EINVAL;
249
250 *cpp_id = nffw_fwinfo_mip_cppid_get(fwinfo);
251 *off = nffw_fwinfo_mip_offset_get(fwinfo);
252
253 if (nffw_fwinfo_mip_mu_da_get(fwinfo)) {
254 int locality_off = nfp_cpp_mu_locality_lsb(state->cpp);
255
256 *off &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
257 *off |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
258 }
259
260 return 0;
261}
262