Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / drivers / net / ethernet / netronome / nfp / nfpcore / nfp_nffw.c
1 /*
2  * Copyright (C) 2015-2017 Netronome Systems, Inc.
3  *
4  * This software is dual licensed under the GNU General License Version 2,
5  * June 1991 as shown in the file COPYING in the top-level directory of this
6  * source tree or the BSD 2-Clause License provided below.  You have the
7  * option to license this software under the complete terms of either license.
8  *
9  * The BSD 2-Clause License:
10  *
11  *     Redistribution and use in source and binary forms, with or
12  *     without modification, are permitted provided that the following
13  *     conditions are met:
14  *
15  *      1. Redistributions of source code must retain the above
16  *         copyright notice, this list of conditions and the following
17  *         disclaimer.
18  *
19  *      2. Redistributions in binary form must reproduce the above
20  *         copyright notice, this list of conditions and the following
21  *         disclaimer in the documentation and/or other materials
22  *         provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  */
33
34 /*
35  * nfp_nffw.c
36  * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
37  *          Jason McMullan <jason.mcmullan@netronome.com>
38  *          Francois H. Theron <francois.theron@netronome.com>
39  */
40
41 #include <linux/kernel.h>
42 #include <linux/slab.h>
43
44 #include "nfp.h"
45 #include "nfp_cpp.h"
46 #include "nfp_nffw.h"
47 #include "nfp6000/nfp6000.h"
48
49 /* Init-CSR owner IDs for firmware map to firmware IDs which start at 4.
50  * Lower IDs are reserved for target and loader IDs.
51  */
52 #define NFFW_FWID_EXT   3 /* For active MEs that we didn't load. */
53 #define NFFW_FWID_BASE  4
54
55 #define NFFW_FWID_ALL   255
56
57 /**
58  * NFFW_INFO_VERSION history:
59  * 0: This was never actually used (before versioning), but it refers to
60  *    the previous struct which had FWINFO_CNT = MEINFO_CNT = 120 that later
61  *    changed to 200.
62  * 1: First versioned struct, with
63  *     FWINFO_CNT = 120
64  *     MEINFO_CNT = 120
65  * 2:  FWINFO_CNT = 200
66  *     MEINFO_CNT = 200
67  */
68 #define NFFW_INFO_VERSION_CURRENT 2
69
70 /* Enough for all current chip families */
71 #define NFFW_MEINFO_CNT_V1 120
72 #define NFFW_FWINFO_CNT_V1 120
73 #define NFFW_MEINFO_CNT_V2 200
74 #define NFFW_FWINFO_CNT_V2 200
75
76 /* Work in 32-bit words to make cross-platform endianness easier to handle */
77
78 /** nfp.nffw meinfo **/
79 struct nffw_meinfo {
80         __le32 ctxmask__fwid__meid;
81 };
82
83 struct nffw_fwinfo {
84         __le32 loaded__mu_da__mip_off_hi;
85         __le32 mip_cppid; /* 0 means no MIP */
86         __le32 mip_offset_lo;
87 };
88
89 struct nfp_nffw_info_v1 {
90         struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V1];
91         struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V1];
92 };
93
94 struct nfp_nffw_info_v2 {
95         struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V2];
96         struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V2];
97 };
98
99 /** Resource: nfp.nffw main **/
100 struct nfp_nffw_info_data {
101         __le32 flags[2];
102         union {
103                 struct nfp_nffw_info_v1 v1;
104                 struct nfp_nffw_info_v2 v2;
105         } info;
106 };
107
108 struct nfp_nffw_info {
109         struct nfp_cpp *cpp;
110         struct nfp_resource *res;
111
112         struct nfp_nffw_info_data fwinf;
113 };
114
115 /* flg_info_version = flags[0]<27:16>
116  * This is a small version counter intended only to detect if the current
117  * implementation can read the current struct. Struct changes should be very
118  * rare and as such a 12-bit counter should cover large spans of time. By the
119  * time it wraps around, we don't expect to have 4096 versions of this struct
120  * to be in use at the same time.
121  */
122 static u32 nffw_res_info_version_get(const struct nfp_nffw_info_data *res)
123 {
124         return (le32_to_cpu(res->flags[0]) >> 16) & 0xfff;
125 }
126
127 /* flg_init = flags[0]<0> */
128 static u32 nffw_res_flg_init_get(const struct nfp_nffw_info_data *res)
129 {
130         return (le32_to_cpu(res->flags[0]) >> 0) & 1;
131 }
132
133 /* loaded = loaded__mu_da__mip_off_hi<31:31> */
134 static u32 nffw_fwinfo_loaded_get(const struct nffw_fwinfo *fi)
135 {
136         return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 31) & 1;
137 }
138
139 /* mip_cppid = mip_cppid */
140 static u32 nffw_fwinfo_mip_cppid_get(const struct nffw_fwinfo *fi)
141 {
142         return le32_to_cpu(fi->mip_cppid);
143 }
144
145 /* loaded = loaded__mu_da__mip_off_hi<8:8> */
146 static u32 nffw_fwinfo_mip_mu_da_get(const struct nffw_fwinfo *fi)
147 {
148         return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 8) & 1;
149 }
150
151 /* mip_offset = (loaded__mu_da__mip_off_hi<7:0> << 8) | mip_offset_lo */
152 static u64 nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi)
153 {
154         u64 mip_off_hi = le32_to_cpu(fi->loaded__mu_da__mip_off_hi);
155
156         return (mip_off_hi & 0xFF) << 32 | le32_to_cpu(fi->mip_offset_lo);
157 }
158
159 #define NFP_IMB_TGTADDRESSMODECFG_MODE_of(_x)           (((_x) >> 13) & 0x7)
160 #define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE              BIT(12)
161 #define   NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_32_BIT     0
162 #define   NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_40_BIT     BIT(12)
163
164 static int nfp_mip_mu_locality_lsb(struct nfp_cpp *cpp)
165 {
166         unsigned int mode, addr40;
167         u32 xpbaddr, imbcppat;
168         int err;
169
170         /* Hardcoded XPB IMB Base, island 0 */
171         xpbaddr = 0x000a0000 + NFP_CPP_TARGET_MU * 4;
172         err = nfp_xpb_readl(cpp, xpbaddr, &imbcppat);
173         if (err < 0)
174                 return err;
175
176         mode = NFP_IMB_TGTADDRESSMODECFG_MODE_of(imbcppat);
177         addr40 = !!(imbcppat & NFP_IMB_TGTADDRESSMODECFG_ADDRMODE);
178
179         return nfp_cppat_mu_locality_lsb(mode, addr40);
180 }
181
182 static unsigned int
183 nffw_res_fwinfos(struct nfp_nffw_info_data *fwinf, struct nffw_fwinfo **arr)
184 {
185         /* For the this code, version 0 is most likely to be
186          * version 1 in this case. Since the kernel driver
187          * does not take responsibility for initialising the
188          * nfp.nffw resource, any previous code (CA firmware or
189          * userspace) that left the version 0 and did set
190          * the init flag is going to be version 1.
191          */
192         switch (nffw_res_info_version_get(fwinf)) {
193         case 0:
194         case 1:
195                 *arr = &fwinf->info.v1.fwinfo[0];
196                 return NFFW_FWINFO_CNT_V1;
197         case 2:
198                 *arr = &fwinf->info.v2.fwinfo[0];
199                 return NFFW_FWINFO_CNT_V2;
200         default:
201                 *arr = NULL;
202                 return 0;
203         }
204 }
205
206 /**
207  * nfp_nffw_info_open() - Acquire the lock on the NFFW table
208  * @cpp:        NFP CPP handle
209  *
210  * Return: 0, or -ERRNO
211  */
212 struct nfp_nffw_info *nfp_nffw_info_open(struct nfp_cpp *cpp)
213 {
214         struct nfp_nffw_info_data *fwinf;
215         struct nfp_nffw_info *state;
216         u32 info_ver;
217         int err;
218
219         state = kzalloc(sizeof(*state), GFP_KERNEL);
220         if (!state)
221                 return ERR_PTR(-ENOMEM);
222
223         state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW);
224         if (IS_ERR(state->res))
225                 goto err_free;
226
227         fwinf = &state->fwinf;
228
229         if (sizeof(*fwinf) > nfp_resource_size(state->res))
230                 goto err_release;
231
232         err = nfp_cpp_read(cpp, nfp_resource_cpp_id(state->res),
233                            nfp_resource_address(state->res),
234                            fwinf, sizeof(*fwinf));
235         if (err < (int)sizeof(*fwinf))
236                 goto err_release;
237
238         if (!nffw_res_flg_init_get(fwinf))
239                 goto err_release;
240
241         info_ver = nffw_res_info_version_get(fwinf);
242         if (info_ver > NFFW_INFO_VERSION_CURRENT)
243                 goto err_release;
244
245         state->cpp = cpp;
246         return state;
247
248 err_release:
249         nfp_resource_release(state->res);
250 err_free:
251         kfree(state);
252         return ERR_PTR(-EIO);
253 }
254
255 /**
256  * nfp_nffw_info_release() - Release the lock on the NFFW table
257  * @state:      NFP FW info state
258  *
259  * Return: 0, or -ERRNO
260  */
261 void nfp_nffw_info_close(struct nfp_nffw_info *state)
262 {
263         nfp_resource_release(state->res);
264         kfree(state);
265 }
266
267 /**
268  * nfp_nffw_info_fwid_first() - Return the first firmware ID in the NFFW
269  * @state:      NFP FW info state
270  *
271  * Return: First NFFW firmware info, NULL on failure
272  */
273 static struct nffw_fwinfo *nfp_nffw_info_fwid_first(struct nfp_nffw_info *state)
274 {
275         struct nffw_fwinfo *fwinfo;
276         unsigned int cnt, i;
277
278         cnt = nffw_res_fwinfos(&state->fwinf, &fwinfo);
279         if (!cnt)
280                 return NULL;
281
282         for (i = 0; i < cnt; i++)
283                 if (nffw_fwinfo_loaded_get(&fwinfo[i]))
284                         return &fwinfo[i];
285
286         return NULL;
287 }
288
289 /**
290  * nfp_nffw_info_mip_first() - Retrieve the location of the first FW's MIP
291  * @state:      NFP FW info state
292  * @cpp_id:     Pointer to the CPP ID of the MIP
293  * @off:        Pointer to the CPP Address of the MIP
294  *
295  * Return: 0, or -ERRNO
296  */
297 int nfp_nffw_info_mip_first(struct nfp_nffw_info *state, u32 *cpp_id, u64 *off)
298 {
299         struct nffw_fwinfo *fwinfo;
300
301         fwinfo = nfp_nffw_info_fwid_first(state);
302         if (!fwinfo)
303                 return -EINVAL;
304
305         *cpp_id = nffw_fwinfo_mip_cppid_get(fwinfo);
306         *off = nffw_fwinfo_mip_offset_get(fwinfo);
307
308         if (nffw_fwinfo_mip_mu_da_get(fwinfo)) {
309                 int locality_off;
310
311                 if (NFP_CPP_ID_TARGET_of(*cpp_id) != NFP_CPP_TARGET_MU)
312                         return 0;
313
314                 locality_off = nfp_mip_mu_locality_lsb(state->cpp);
315                 if (locality_off < 0)
316                         return locality_off;
317
318                 *off &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
319                 *off |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
320         }
321
322         return 0;
323 }