Branch data Line data Source code
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 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : uint64_t mip_off_hi = fi->loaded_mu_da_mip_off_hi; 124 : : 125 : 0 : 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 : 0 : switch (nffw_res_info_version_get(fwinf)) { 140 : 0 : case 0: 141 : : case 1: 142 : 0 : *arr = &fwinf->info.v1.fwinfo[0]; 143 : : return NFFW_FWINFO_CNT_V1; 144 : 0 : case 2: 145 : 0 : *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 : 0 : 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 : 0 : state = malloc(sizeof(*state)); 171 [ # # ]: 0 : if (state == NULL) 172 : : return NULL; 173 : : 174 : : memset(state, 0, sizeof(*state)); 175 : : 176 : 0 : state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW); 177 [ # # ]: 0 : if (state->res == NULL) { 178 : 0 : PMD_DRV_LOG(ERR, "NFFW - acquire resource failed"); 179 : 0 : goto err_free; 180 : : } 181 : : 182 : 0 : fwinf = &state->fwinf; 183 : : 184 [ # # ]: 0 : if (sizeof(*fwinf) > nfp_resource_size(state->res)) 185 : 0 : goto err_release; 186 : : 187 : 0 : err = nfp_cpp_read(cpp, nfp_resource_cpp_id(state->res), 188 : 0 : nfp_resource_address(state->res), 189 : : fwinf, sizeof(*fwinf)); 190 [ # # ]: 0 : if (err < (int)sizeof(*fwinf)) { 191 : 0 : PMD_DRV_LOG(ERR, "NFFW - CPP read error %d", err); 192 : 0 : goto err_release; 193 : : } 194 : : 195 [ # # ]: 0 : if (nffw_res_flg_init_get(fwinf) == 0) 196 : 0 : goto err_release; 197 : : 198 : : info_ver = nffw_res_info_version_get(fwinf); 199 [ # # ]: 0 : if (info_ver > NFFW_INFO_VERSION_CURRENT) 200 : 0 : goto err_release; 201 : : 202 : 0 : state->cpp = cpp; 203 : 0 : return state; 204 : : 205 : 0 : err_release: 206 : 0 : nfp_resource_release(state->res); 207 : 0 : err_free: 208 : 0 : free(state); 209 : 0 : 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 : 0 : nfp_nffw_info_close(struct nfp_nffw_info *state) 220 : : { 221 : 0 : nfp_resource_release(state->res); 222 : 0 : free(state); 223 : 0 : } 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 [ # # # ]: 0 : 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 [ # # ]: 0 : for (i = 0; i < cnt; i++) 246 [ # # ]: 0 : if (nffw_fwinfo_loaded_get(&fwinfo[i]) != 0) 247 : 0 : 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 : 0 : 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 : 0 : fwinfo = nfp_nffw_info_fwid_first(state); 273 [ # # ]: 0 : if (fwinfo == NULL) 274 : : return -EINVAL; 275 : : 276 : 0 : *cpp_id = nffw_fwinfo_mip_cppid_get(fwinfo); 277 : 0 : *offset = nffw_fwinfo_mip_offset_get(fwinfo); 278 : : 279 [ # # ]: 0 : if (nffw_fwinfo_mip_mu_da_get(fwinfo) != 0) { 280 : 0 : int locality_off = nfp_cpp_mu_locality_lsb(state->cpp); 281 : : 282 : 0 : *offset &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off); 283 : 0 : *offset |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off; 284 : : } 285 : : 286 : : return 0; 287 : : }