1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2015-2018 Netronome Systems, Inc. */
6 * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
7 * Jason McMullan <jason.mcmullan@netronome.com>
8 * Francois H. Theron <francois.theron@netronome.com>
11 #include <linux/kernel.h>
12 #include <linux/slab.h>
17 #include "nfp6000/nfp6000.h"
19 /* Init-CSR owner IDs for firmware map to firmware IDs which start at 4.
20 * Lower IDs are reserved for target and loader IDs.
22 #define NFFW_FWID_EXT 3 /* For active MEs that we didn't load. */
23 #define NFFW_FWID_BASE 4
25 #define NFFW_FWID_ALL 255
28 * NFFW_INFO_VERSION history:
29 * 0: This was never actually used (before versioning), but it refers to
30 * the previous struct which had FWINFO_CNT = MEINFO_CNT = 120 that later
32 * 1: First versioned struct, with
38 #define NFFW_INFO_VERSION_CURRENT 2
40 /* Enough for all current chip families */
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
46 /* Work in 32-bit words to make cross-platform endianness easier to handle */
48 /** nfp.nffw meinfo **/
50 __le32 ctxmask__fwid__meid;
54 __le32 loaded__mu_da__mip_off_hi;
55 __le32 mip_cppid; /* 0 means no MIP */
59 struct nfp_nffw_info_v1 {
60 struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V1];
61 struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V1];
64 struct nfp_nffw_info_v2 {
65 struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V2];
66 struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V2];
69 /** Resource: nfp.nffw main **/
70 struct nfp_nffw_info_data {
73 struct nfp_nffw_info_v1 v1;
74 struct nfp_nffw_info_v2 v2;
78 struct nfp_nffw_info {
80 struct nfp_resource *res;
82 struct nfp_nffw_info_data fwinf;
85 /* flg_info_version = flags[0]<27:16>
86 * This is a small version counter intended only to detect if the current
87 * implementation can read the current struct. Struct changes should be very
88 * rare and as such a 12-bit counter should cover large spans of time. By the
89 * time it wraps around, we don't expect to have 4096 versions of this struct
90 * to be in use at the same time.
92 static u32 nffw_res_info_version_get(const struct nfp_nffw_info_data *res)
94 return (le32_to_cpu(res->flags[0]) >> 16) & 0xfff;
97 /* flg_init = flags[0]<0> */
98 static u32 nffw_res_flg_init_get(const struct nfp_nffw_info_data *res)
100 return (le32_to_cpu(res->flags[0]) >> 0) & 1;
103 /* loaded = loaded__mu_da__mip_off_hi<31:31> */
104 static u32 nffw_fwinfo_loaded_get(const struct nffw_fwinfo *fi)
106 return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 31) & 1;
109 /* mip_cppid = mip_cppid */
110 static u32 nffw_fwinfo_mip_cppid_get(const struct nffw_fwinfo *fi)
112 return le32_to_cpu(fi->mip_cppid);
115 /* loaded = loaded__mu_da__mip_off_hi<8:8> */
116 static u32 nffw_fwinfo_mip_mu_da_get(const struct nffw_fwinfo *fi)
118 return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 8) & 1;
121 /* mip_offset = (loaded__mu_da__mip_off_hi<7:0> << 8) | mip_offset_lo */
122 static u64 nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi)
124 u64 mip_off_hi = le32_to_cpu(fi->loaded__mu_da__mip_off_hi);
126 return (mip_off_hi & 0xFF) << 32 | le32_to_cpu(fi->mip_offset_lo);
130 nffw_res_fwinfos(struct nfp_nffw_info_data *fwinf, struct nffw_fwinfo **arr)
132 /* For the this code, version 0 is most likely to be
133 * version 1 in this case. Since the kernel driver
134 * does not take responsibility for initialising the
135 * nfp.nffw resource, any previous code (CA firmware or
136 * userspace) that left the version 0 and did set
137 * the init flag is going to be version 1.
139 switch (nffw_res_info_version_get(fwinf)) {
142 *arr = &fwinf->info.v1.fwinfo[0];
143 return NFFW_FWINFO_CNT_V1;
145 *arr = &fwinf->info.v2.fwinfo[0];
146 return NFFW_FWINFO_CNT_V2;
154 * nfp_nffw_info_open() - Acquire the lock on the NFFW table
155 * @cpp: NFP CPP handle
157 * Return: pointer to nfp_nffw_info object or ERR_PTR()
159 struct nfp_nffw_info *nfp_nffw_info_open(struct nfp_cpp *cpp)
161 struct nfp_nffw_info_data *fwinf;
162 struct nfp_nffw_info *state;
166 state = kzalloc(sizeof(*state), GFP_KERNEL);
168 return ERR_PTR(-ENOMEM);
170 state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW);
171 if (IS_ERR(state->res))
174 fwinf = &state->fwinf;
176 if (sizeof(*fwinf) > nfp_resource_size(state->res))
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))
185 if (!nffw_res_flg_init_get(fwinf))
188 info_ver = nffw_res_info_version_get(fwinf);
189 if (info_ver > NFFW_INFO_VERSION_CURRENT)
196 nfp_resource_release(state->res);
199 return ERR_PTR(-EIO);
203 * nfp_nffw_info_close() - Release the lock on the NFFW table and free state
204 * @state: NFP FW info state
206 void nfp_nffw_info_close(struct nfp_nffw_info *state)
208 nfp_resource_release(state->res);
213 * nfp_nffw_info_fwid_first() - Return the first firmware ID in the NFFW
214 * @state: NFP FW info state
216 * Return: First NFFW firmware info, NULL on failure
218 static struct nffw_fwinfo *nfp_nffw_info_fwid_first(struct nfp_nffw_info *state)
220 struct nffw_fwinfo *fwinfo;
223 cnt = nffw_res_fwinfos(&state->fwinf, &fwinfo);
227 for (i = 0; i < cnt; i++)
228 if (nffw_fwinfo_loaded_get(&fwinfo[i]))
235 * nfp_nffw_info_mip_first() - Retrieve the location of the first FW's MIP
236 * @state: NFP FW info state
237 * @cpp_id: Pointer to the CPP ID of the MIP
238 * @off: Pointer to the CPP Address of the MIP
240 * Return: 0, or -ERRNO
242 int nfp_nffw_info_mip_first(struct nfp_nffw_info *state, u32 *cpp_id, u64 *off)
244 struct nffw_fwinfo *fwinfo;
246 fwinfo = nfp_nffw_info_fwid_first(state);
250 *cpp_id = nffw_fwinfo_mip_cppid_get(fwinfo);
251 *off = nffw_fwinfo_mip_offset_get(fwinfo);
253 if (nffw_fwinfo_mip_mu_da_get(fwinfo)) {
254 int locality_off = nfp_cpp_mu_locality_lsb(state->cpp);
256 *off &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
257 *off |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;