0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/kernel.h>
0012 #include <linux/slab.h>
0013
0014 #include "nfp.h"
0015 #include "nfp_cpp.h"
0016 #include "nfp_nffw.h"
0017 #include "nfp6000/nfp6000.h"
0018
0019
0020
0021
0022 #define NFFW_FWID_EXT 3
0023 #define NFFW_FWID_BASE 4
0024
0025 #define NFFW_FWID_ALL 255
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 #define NFFW_INFO_VERSION_CURRENT 2
0039
0040
0041 #define NFFW_MEINFO_CNT_V1 120
0042 #define NFFW_FWINFO_CNT_V1 120
0043 #define NFFW_MEINFO_CNT_V2 200
0044 #define NFFW_FWINFO_CNT_V2 200
0045
0046
0047
0048
0049 struct nffw_meinfo {
0050 __le32 ctxmask__fwid__meid;
0051 };
0052
0053 struct nffw_fwinfo {
0054 __le32 loaded__mu_da__mip_off_hi;
0055 __le32 mip_cppid;
0056 __le32 mip_offset_lo;
0057 };
0058
0059 struct nfp_nffw_info_v1 {
0060 struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V1];
0061 struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V1];
0062 };
0063
0064 struct nfp_nffw_info_v2 {
0065 struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V2];
0066 struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V2];
0067 };
0068
0069
0070 struct nfp_nffw_info_data {
0071 __le32 flags[2];
0072 union {
0073 struct nfp_nffw_info_v1 v1;
0074 struct nfp_nffw_info_v2 v2;
0075 } info;
0076 };
0077
0078 struct nfp_nffw_info {
0079 struct nfp_cpp *cpp;
0080 struct nfp_resource *res;
0081
0082 struct nfp_nffw_info_data fwinf;
0083 };
0084
0085
0086
0087
0088
0089
0090
0091
0092 static u32 nffw_res_info_version_get(const struct nfp_nffw_info_data *res)
0093 {
0094 return (le32_to_cpu(res->flags[0]) >> 16) & 0xfff;
0095 }
0096
0097
0098 static u32 nffw_res_flg_init_get(const struct nfp_nffw_info_data *res)
0099 {
0100 return (le32_to_cpu(res->flags[0]) >> 0) & 1;
0101 }
0102
0103
0104 static u32 nffw_fwinfo_loaded_get(const struct nffw_fwinfo *fi)
0105 {
0106 return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 31) & 1;
0107 }
0108
0109
0110 static u32 nffw_fwinfo_mip_cppid_get(const struct nffw_fwinfo *fi)
0111 {
0112 return le32_to_cpu(fi->mip_cppid);
0113 }
0114
0115
0116 static u32 nffw_fwinfo_mip_mu_da_get(const struct nffw_fwinfo *fi)
0117 {
0118 return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 8) & 1;
0119 }
0120
0121
0122 static u64 nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi)
0123 {
0124 u64 mip_off_hi = le32_to_cpu(fi->loaded__mu_da__mip_off_hi);
0125
0126 return (mip_off_hi & 0xFF) << 32 | le32_to_cpu(fi->mip_offset_lo);
0127 }
0128
0129 static unsigned int
0130 nffw_res_fwinfos(struct nfp_nffw_info_data *fwinf, struct nffw_fwinfo **arr)
0131 {
0132
0133
0134
0135
0136
0137
0138
0139 switch (nffw_res_info_version_get(fwinf)) {
0140 case 0:
0141 case 1:
0142 *arr = &fwinf->info.v1.fwinfo[0];
0143 return NFFW_FWINFO_CNT_V1;
0144 case 2:
0145 *arr = &fwinf->info.v2.fwinfo[0];
0146 return NFFW_FWINFO_CNT_V2;
0147 default:
0148 *arr = NULL;
0149 return 0;
0150 }
0151 }
0152
0153
0154
0155
0156
0157
0158
0159 struct nfp_nffw_info *nfp_nffw_info_open(struct nfp_cpp *cpp)
0160 {
0161 struct nfp_nffw_info_data *fwinf;
0162 struct nfp_nffw_info *state;
0163 u32 info_ver;
0164 int err;
0165
0166 state = kzalloc(sizeof(*state), GFP_KERNEL);
0167 if (!state)
0168 return ERR_PTR(-ENOMEM);
0169
0170 state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW);
0171 if (IS_ERR(state->res))
0172 goto err_free;
0173
0174 fwinf = &state->fwinf;
0175
0176 if (sizeof(*fwinf) > nfp_resource_size(state->res))
0177 goto err_release;
0178
0179 err = nfp_cpp_read(cpp, nfp_resource_cpp_id(state->res),
0180 nfp_resource_address(state->res),
0181 fwinf, sizeof(*fwinf));
0182 if (err < (int)sizeof(*fwinf))
0183 goto err_release;
0184
0185 if (!nffw_res_flg_init_get(fwinf))
0186 goto err_release;
0187
0188 info_ver = nffw_res_info_version_get(fwinf);
0189 if (info_ver > NFFW_INFO_VERSION_CURRENT)
0190 goto err_release;
0191
0192 state->cpp = cpp;
0193 return state;
0194
0195 err_release:
0196 nfp_resource_release(state->res);
0197 err_free:
0198 kfree(state);
0199 return ERR_PTR(-EIO);
0200 }
0201
0202
0203
0204
0205
0206 void nfp_nffw_info_close(struct nfp_nffw_info *state)
0207 {
0208 nfp_resource_release(state->res);
0209 kfree(state);
0210 }
0211
0212
0213
0214
0215
0216
0217
0218 static struct nffw_fwinfo *nfp_nffw_info_fwid_first(struct nfp_nffw_info *state)
0219 {
0220 struct nffw_fwinfo *fwinfo;
0221 unsigned int cnt, i;
0222
0223 cnt = nffw_res_fwinfos(&state->fwinf, &fwinfo);
0224 if (!cnt)
0225 return NULL;
0226
0227 for (i = 0; i < cnt; i++)
0228 if (nffw_fwinfo_loaded_get(&fwinfo[i]))
0229 return &fwinfo[i];
0230
0231 return NULL;
0232 }
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242 int nfp_nffw_info_mip_first(struct nfp_nffw_info *state, u32 *cpp_id, u64 *off)
0243 {
0244 struct nffw_fwinfo *fwinfo;
0245
0246 fwinfo = nfp_nffw_info_fwid_first(state);
0247 if (!fwinfo)
0248 return -EINVAL;
0249
0250 *cpp_id = nffw_fwinfo_mip_cppid_get(fwinfo);
0251 *off = nffw_fwinfo_mip_offset_get(fwinfo);
0252
0253 if (nffw_fwinfo_mip_mu_da_get(fwinfo)) {
0254 int locality_off = nfp_cpp_mu_locality_lsb(state->cpp);
0255
0256 *off &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
0257 *off |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
0258 }
0259
0260 return 0;
0261 }