X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=drivers%2Fnet%2Fnfp%2Fnfpcore%2Fnfp_nffw.c;fp=drivers%2Fnet%2Fnfp%2Fnfpcore%2Fnfp_nffw.c;h=8bec0e3c9aecd6681fb1fb479e5e35e142e30d55;hb=b63264c8342e6a1b6971c79550d2af2024b6a4de;hp=0000000000000000000000000000000000000000;hpb=ca33590b6af032bff57d9cc70455660466a654b2;p=deb_dpdk.git diff --git a/drivers/net/nfp/nfpcore/nfp_nffw.c b/drivers/net/nfp/nfpcore/nfp_nffw.c new file mode 100644 index 00000000..8bec0e3c --- /dev/null +++ b/drivers/net/nfp/nfpcore/nfp_nffw.c @@ -0,0 +1,235 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018 Netronome Systems, Inc. + * All rights reserved. + */ + +#include "nfp_cpp.h" +#include "nfp_nffw.h" +#include "nfp_mip.h" +#include "nfp6000/nfp6000.h" +#include "nfp_resource.h" + +/* + * flg_info_version = flags[0]<27:16> + * This is a small version counter intended only to detect if the current + * implementation can read the current struct. Struct changes should be very + * rare and as such a 12-bit counter should cover large spans of time. By the + * time it wraps around, we don't expect to have 4096 versions of this struct + * to be in use at the same time. + */ +static uint32_t +nffw_res_info_version_get(const struct nfp_nffw_info_data *res) +{ + return (res->flags[0] >> 16) & 0xfff; +} + +/* flg_init = flags[0]<0> */ +static uint32_t +nffw_res_flg_init_get(const struct nfp_nffw_info_data *res) +{ + return (res->flags[0] >> 0) & 1; +} + +/* loaded = loaded__mu_da__mip_off_hi<31:31> */ +static uint32_t +nffw_fwinfo_loaded_get(const struct nffw_fwinfo *fi) +{ + return (fi->loaded__mu_da__mip_off_hi >> 31) & 1; +} + +/* mip_cppid = mip_cppid */ +static uint32_t +nffw_fwinfo_mip_cppid_get(const struct nffw_fwinfo *fi) +{ + return fi->mip_cppid; +} + +/* loaded = loaded__mu_da__mip_off_hi<8:8> */ +static uint32_t +nffw_fwinfo_mip_mu_da_get(const struct nffw_fwinfo *fi) +{ + return (fi->loaded__mu_da__mip_off_hi >> 8) & 1; +} + +/* mip_offset = (loaded__mu_da__mip_off_hi<7:0> << 8) | mip_offset_lo */ +static uint64_t +nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi) +{ + uint64_t mip_off_hi = fi->loaded__mu_da__mip_off_hi; + + return (mip_off_hi & 0xFF) << 32 | fi->mip_offset_lo; +} + +#define NFP_IMB_TGTADDRESSMODECFG_MODE_of(_x) (((_x) >> 13) & 0x7) +#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE BIT(12) +#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_32_BIT 0 +#define NFP_IMB_TGTADDRESSMODECFG_ADDRMODE_40_BIT BIT(12) + +static int +nfp_mip_mu_locality_lsb(struct nfp_cpp *cpp) +{ + unsigned int mode, addr40; + uint32_t xpbaddr, imbcppat; + int err; + + /* Hardcoded XPB IMB Base, island 0 */ + xpbaddr = 0x000a0000 + NFP_CPP_TARGET_MU * 4; + err = nfp_xpb_readl(cpp, xpbaddr, &imbcppat); + if (err < 0) + return err; + + mode = NFP_IMB_TGTADDRESSMODECFG_MODE_of(imbcppat); + addr40 = !!(imbcppat & NFP_IMB_TGTADDRESSMODECFG_ADDRMODE); + + return nfp_cppat_mu_locality_lsb(mode, addr40); +} + +static unsigned int +nffw_res_fwinfos(struct nfp_nffw_info_data *fwinf, struct nffw_fwinfo **arr) +{ + /* + * For the this code, version 0 is most likely to be version 1 in this + * case. Since the kernel driver does not take responsibility for + * initialising the nfp.nffw resource, any previous code (CA firmware or + * userspace) that left the version 0 and did set the init flag is going + * to be version 1. + */ + switch (nffw_res_info_version_get(fwinf)) { + case 0: + case 1: + *arr = &fwinf->info.v1.fwinfo[0]; + return NFFW_FWINFO_CNT_V1; + case 2: + *arr = &fwinf->info.v2.fwinfo[0]; + return NFFW_FWINFO_CNT_V2; + default: + *arr = NULL; + return 0; + } +} + +/* + * nfp_nffw_info_open() - Acquire the lock on the NFFW table + * @cpp: NFP CPP handle + * + * Return: 0, or -ERRNO + */ +struct nfp_nffw_info * +nfp_nffw_info_open(struct nfp_cpp *cpp) +{ + struct nfp_nffw_info_data *fwinf; + struct nfp_nffw_info *state; + uint32_t info_ver; + int err; + + state = malloc(sizeof(*state)); + if (!state) + return NULL; + + memset(state, 0, sizeof(*state)); + + state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW); + if (!state->res) + goto err_free; + + fwinf = &state->fwinf; + + if (sizeof(*fwinf) > nfp_resource_size(state->res)) + goto err_release; + + err = nfp_cpp_read(cpp, nfp_resource_cpp_id(state->res), + nfp_resource_address(state->res), + fwinf, sizeof(*fwinf)); + if (err < (int)sizeof(*fwinf)) + goto err_release; + + if (!nffw_res_flg_init_get(fwinf)) + goto err_release; + + info_ver = nffw_res_info_version_get(fwinf); + if (info_ver > NFFW_INFO_VERSION_CURRENT) + goto err_release; + + state->cpp = cpp; + return state; + +err_release: + nfp_resource_release(state->res); +err_free: + free(state); + return NULL; +} + +/* + * nfp_nffw_info_release() - Release the lock on the NFFW table + * @state: NFP FW info state + * + * Return: 0, or -ERRNO + */ +void +nfp_nffw_info_close(struct nfp_nffw_info *state) +{ + nfp_resource_release(state->res); + free(state); +} + +/* + * nfp_nffw_info_fwid_first() - Return the first firmware ID in the NFFW + * @state: NFP FW info state + * + * Return: First NFFW firmware info, NULL on failure + */ +static struct nffw_fwinfo * +nfp_nffw_info_fwid_first(struct nfp_nffw_info *state) +{ + struct nffw_fwinfo *fwinfo; + unsigned int cnt, i; + + cnt = nffw_res_fwinfos(&state->fwinf, &fwinfo); + if (!cnt) + return NULL; + + for (i = 0; i < cnt; i++) + if (nffw_fwinfo_loaded_get(&fwinfo[i])) + return &fwinfo[i]; + + return NULL; +} + +/* + * nfp_nffw_info_mip_first() - Retrieve the location of the first FW's MIP + * @state: NFP FW info state + * @cpp_id: Pointer to the CPP ID of the MIP + * @off: Pointer to the CPP Address of the MIP + * + * Return: 0, or -ERRNO + */ +int +nfp_nffw_info_mip_first(struct nfp_nffw_info *state, uint32_t *cpp_id, + uint64_t *off) +{ + struct nffw_fwinfo *fwinfo; + + fwinfo = nfp_nffw_info_fwid_first(state); + if (!fwinfo) + return -EINVAL; + + *cpp_id = nffw_fwinfo_mip_cppid_get(fwinfo); + *off = nffw_fwinfo_mip_offset_get(fwinfo); + + if (nffw_fwinfo_mip_mu_da_get(fwinfo)) { + int locality_off; + + if (NFP_CPP_ID_TARGET_of(*cpp_id) != NFP_CPP_TARGET_MU) + return 0; + + locality_off = nfp_mip_mu_locality_lsb(state->cpp); + if (locality_off < 0) + return locality_off; + + *off &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off); + *off |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off; + } + + return 0; +}