1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2018 Netronome Systems, Inc. 3 * All rights reserved. 4 */ 5 6 #include "nfp_nffw.h" 7 8 #include "../nfp_logs.h" 9 #include "nfp_mip.h" 10 #include "nfp_resource.h" 11 #include "nfp6000/nfp6000.h" 12 13 /* 14 * Init-CSR owner IDs for firmware map to firmware IDs which start at 4. 15 * Lower IDs are reserved for target and loader IDs. 16 */ 17 #define NFFW_FWID_EXT 3 /* For active MEs that we didn't load. */ 18 #define NFFW_FWID_BASE 4 19 20 #define NFFW_FWID_ALL 255 21 22 /* 23 * NFFW_INFO_VERSION history: 24 * 0: This was never actually used (before versioning), but it refers to 25 * the previous struct which had FWINFO_CNT = MEINFO_CNT = 120 that later 26 * changed to 200. 27 * 1: First versioned struct, with 28 * FWINFO_CNT = 120 29 * MEINFO_CNT = 120 30 * 2: FWINFO_CNT = 200 31 * MEINFO_CNT = 200 32 */ 33 #define NFFW_INFO_VERSION_CURRENT 2 34 35 /* Enough for all current chip families */ 36 #define NFFW_MEINFO_CNT_V1 120 37 #define NFFW_FWINFO_CNT_V1 120 38 #define NFFW_MEINFO_CNT_V2 200 39 #define NFFW_FWINFO_CNT_V2 200 40 41 /* nfp.nffw meinfo */ 42 struct nffw_meinfo { 43 uint32_t ctxmask_fwid_meid; 44 }; 45 46 struct nffw_fwinfo { 47 uint32_t loaded_mu_da_mip_off_hi; 48 uint32_t mip_cppid; /**< 0 means no MIP */ 49 uint32_t mip_offset_lo; 50 }; 51 52 struct nfp_nffw_info_v1 { 53 struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V1]; 54 struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V1]; 55 }; 56 57 struct nfp_nffw_info_v2 { 58 struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V2]; 59 struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V2]; 60 }; 61 62 struct nfp_nffw_info_data { 63 uint32_t flags[2]; 64 union { 65 struct nfp_nffw_info_v1 v1; 66 struct nfp_nffw_info_v2 v2; 67 } info; 68 }; 69 70 struct nfp_nffw_info { 71 struct nfp_cpp *cpp; 72 struct nfp_resource *res; 73 74 struct nfp_nffw_info_data fwinf; 75 }; 76 77 /* 78 * flg_info_version = flags[0]<27:16> 79 * This is a small version counter intended only to detect if the current 80 * implementation can read the current struct. Struct changes should be very 81 * rare and as such a 12-bit counter should cover large spans of time. By the 82 * time it wraps around, we don't expect to have 4096 versions of this struct 83 * to be in use at the same time. 84 */ 85 static uint32_t 86 nffw_res_info_version_get(const struct nfp_nffw_info_data *res) 87 { 88 return (res->flags[0] >> 16) & 0xfff; 89 } 90 91 /* flg_init = flags[0]<0> */ 92 static uint32_t 93 nffw_res_flg_init_get(const struct nfp_nffw_info_data *res) 94 { 95 return (res->flags[0] >> 0) & 1; 96 } 97 98 /* loaded = loaded_mu_da_mip_off_hi<31:31> */ 99 static uint32_t 100 nffw_fwinfo_loaded_get(const struct nffw_fwinfo *fi) 101 { 102 return (fi->loaded_mu_da_mip_off_hi >> 31) & 1; 103 } 104 105 /* mip_cppid = mip_cppid */ 106 static uint32_t 107 nffw_fwinfo_mip_cppid_get(const struct nffw_fwinfo *fi) 108 { 109 return fi->mip_cppid; 110 } 111 112 /* loaded = loaded_mu_da_mip_off_hi<8:8> */ 113 static uint32_t 114 nffw_fwinfo_mip_mu_da_get(const struct nffw_fwinfo *fi) 115 { 116 return (fi->loaded_mu_da_mip_off_hi >> 8) & 1; 117 } 118 119 /* mip_offset = (loaded_mu_da_mip_off_hi<7:0> << 32) | mip_offset_lo */ 120 static uint64_t 121 nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi) 122 { 123 uint64_t mip_off_hi = fi->loaded_mu_da_mip_off_hi; 124 125 return (mip_off_hi & 0xFF) << 32 | fi->mip_offset_lo; 126 } 127 128 static uint32_t 129 nffw_res_fwinfos(struct nfp_nffw_info_data *fwinf, 130 struct nffw_fwinfo **arr) 131 { 132 /* 133 * For the this code, version 0 is most likely to be version 1 in this 134 * case. Since the kernel driver does not take responsibility for 135 * initialising the nfp.nffw resource, any previous code (CA firmware or 136 * userspace) that left the version 0 and did set the init flag is going 137 * to be version 1. 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 * Acquire the lock on the NFFW table 155 * 156 * @param cpp 157 * NFP CPP handle 158 * 159 * @return 160 * NFFW info pointer, or NULL on failure 161 */ 162 struct nfp_nffw_info * 163 nfp_nffw_info_open(struct nfp_cpp *cpp) 164 { 165 int err; 166 uint32_t info_ver; 167 struct nfp_nffw_info *state; 168 struct nfp_nffw_info_data *fwinf; 169 170 state = malloc(sizeof(*state)); 171 if (state == NULL) 172 return NULL; 173 174 memset(state, 0, sizeof(*state)); 175 176 state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW); 177 if (state->res == NULL) { 178 PMD_DRV_LOG(ERR, "NFFW - acquire resource failed."); 179 goto err_free; 180 } 181 182 fwinf = &state->fwinf; 183 184 if (sizeof(*fwinf) > nfp_resource_size(state->res)) 185 goto err_release; 186 187 err = nfp_cpp_read(cpp, nfp_resource_cpp_id(state->res), 188 nfp_resource_address(state->res), 189 fwinf, sizeof(*fwinf)); 190 if (err < (int)sizeof(*fwinf)) { 191 PMD_DRV_LOG(ERR, "NFFW - CPP read error %d.", err); 192 goto err_release; 193 } 194 195 if (nffw_res_flg_init_get(fwinf) == 0) 196 goto err_release; 197 198 info_ver = nffw_res_info_version_get(fwinf); 199 if (info_ver > NFFW_INFO_VERSION_CURRENT) 200 goto err_release; 201 202 state->cpp = cpp; 203 return state; 204 205 err_release: 206 nfp_resource_release(state->res); 207 err_free: 208 free(state); 209 return NULL; 210 } 211 212 /** 213 * Release the lock on the NFFW table 214 * 215 * @param state 216 * NFFW info pointer 217 */ 218 void 219 nfp_nffw_info_close(struct nfp_nffw_info *state) 220 { 221 nfp_resource_release(state->res); 222 free(state); 223 } 224 225 /** 226 * Return the first firmware ID in the NFFW 227 * 228 * @param state 229 * NFFW info pointer 230 * 231 * @return: 232 * First NFFW firmware info, NULL on failure 233 */ 234 static struct nffw_fwinfo * 235 nfp_nffw_info_fwid_first(struct nfp_nffw_info *state) 236 { 237 uint32_t i; 238 uint32_t cnt; 239 struct nffw_fwinfo *fwinfo; 240 241 cnt = nffw_res_fwinfos(&state->fwinf, &fwinfo); 242 if (cnt == 0) 243 return NULL; 244 245 for (i = 0; i < cnt; i++) 246 if (nffw_fwinfo_loaded_get(&fwinfo[i]) != 0) 247 return &fwinfo[i]; 248 249 return NULL; 250 } 251 252 /** 253 * Retrieve the location of the first FW's MIP 254 * 255 * @param state 256 * NFFW info pointer 257 * @param cpp_id 258 * Pointer to the CPP ID of the MIP 259 * @param off 260 * Pointer to the CPP Address of the MIP 261 * 262 * @return 263 * 0, or -ERRNO 264 */ 265 int 266 nfp_nffw_info_mip_first(struct nfp_nffw_info *state, 267 uint32_t *cpp_id, 268 uint64_t *offset) 269 { 270 struct nffw_fwinfo *fwinfo; 271 272 fwinfo = nfp_nffw_info_fwid_first(state); 273 if (fwinfo == NULL) 274 return -EINVAL; 275 276 *cpp_id = nffw_fwinfo_mip_cppid_get(fwinfo); 277 *offset = nffw_fwinfo_mip_offset_get(fwinfo); 278 279 if (nffw_fwinfo_mip_mu_da_get(fwinfo) != 0) { 280 int locality_off = nfp_cpp_mu_locality_lsb(state->cpp); 281 282 *offset &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off); 283 *offset |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off; 284 } 285 286 return 0; 287 } 288