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