// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_nffw . c
* Authors : Jakub Kicinski < jakub . kicinski @ netronome . com >
* Jason McMullan < jason . mcmullan @ netronome . com >
* Francois H . Theron < francois . theron @ netronome . com >
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include "nfp.h"
#include "nfp_cpp.h"
#include "nfp_nffw.h"
#include "nfp6000/nfp6000.h"
/* Init-CSR owner IDs for firmware map to firmware IDs which start at 4.
* Lower IDs are reserved for target and loader IDs .
*/
#define NFFW_FWID_EXT 3 /* For active MEs that we didn't load. */
#define NFFW_FWID_BASE 4
#define NFFW_FWID_ALL 255
/*
* NFFW_INFO_VERSION history :
* 0 : This was never actually used ( before versioning ) , but it refers to
* the previous struct which had FWINFO_CNT = MEINFO_CNT = 120 that later
* changed to 200 .
* 1 : First versioned struct , with
* FWINFO_CNT = 120
* MEINFO_CNT = 120
* 2 : FWINFO_CNT = 200
* MEINFO_CNT = 200
*/
#define NFFW_INFO_VERSION_CURRENT 2
/* Enough for all current chip families */
#define NFFW_MEINFO_CNT_V1 120
#define NFFW_FWINFO_CNT_V1 120
#define NFFW_MEINFO_CNT_V2 200
#define NFFW_FWINFO_CNT_V2 200
/* Work in 32-bit words to make cross-platform endianness easier to handle */
/** nfp.nffw meinfo **/
struct nffw_meinfo {
__le32 ctxmask__fwid__meid;
};
struct nffw_fwinfo {
__le32 loaded__mu_da__mip_off_hi;
__le32 mip_cppid; /* 0 means no MIP */
__le32 mip_offset_lo;
};
struct nfp_nffw_info_v1 {
struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V1];
struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V1];
};
struct nfp_nffw_info_v2 {
struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V2];
struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V2];
};
/** Resource: nfp.nffw main **/
struct nfp_nffw_info_data {
__le32 flags[2 ];
union {
struct nfp_nffw_info_v1 v1;
struct nfp_nffw_info_v2 v2;
} info;
};
struct nfp_nffw_info {
struct nfp_cpp *cpp;
struct nfp_resource *res;
struct nfp_nffw_info_data fwinf;
};
/* 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 u32 nffw_res_info_version_get(const struct nfp_nffw_info_data *res)
{
return (le32_to_cpu(res->flags[0 ]) >> 16 ) & 0 xfff;
}
/* flg_init = flags[0]<0> */
static u32 nffw_res_flg_init_get(const struct nfp_nffw_info_data *res)
{
return (le32_to_cpu(res->flags[0 ]) >> 0 ) & 1 ;
}
/* loaded = loaded__mu_da__mip_off_hi<31:31> */
static u32 nffw_fwinfo_loaded_get(const struct nffw_fwinfo *fi)
{
return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 31 ) & 1 ;
}
/* mip_cppid = mip_cppid */
static u32 nffw_fwinfo_mip_cppid_get(const struct nffw_fwinfo *fi)
{
return le32_to_cpu(fi->mip_cppid);
}
/* loaded = loaded__mu_da__mip_off_hi<8:8> */
static u32 nffw_fwinfo_mip_mu_da_get(const struct nffw_fwinfo *fi)
{
return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 8 ) & 1 ;
}
/* mip_offset = (loaded__mu_da__mip_off_hi<7:0> << 8) | mip_offset_lo */
static u64 nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi)
{
u64 mip_off_hi = le32_to_cpu(fi->loaded__mu_da__mip_off_hi);
return (mip_off_hi & 0 xFF) << 32 | le32_to_cpu(fi->mip_offset_lo);
}
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 : pointer to nfp_nffw_info object or ERR_PTR ( )
*/
struct nfp_nffw_info *nfp_nffw_info_open(struct nfp_cpp *cpp)
{
struct nfp_nffw_info_data *fwinf;
struct nfp_nffw_info *state;
u32 info_ver;
int err;
state = kzalloc(sizeof (*state), GFP_KERNEL);
if (!state)
return ERR_PTR(-ENOMEM);
state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW);
if (IS_ERR(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:
kfree(state);
return ERR_PTR(-EIO);
}
/**
* nfp_nffw_info_close ( ) - Release the lock on the NFFW table and free state
* @ state : NFP FW info state
*/
void nfp_nffw_info_close(struct nfp_nffw_info *state)
{
nfp_resource_release(state->res);
kfree(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, u32 *cpp_id, u64 *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 = nfp_cpp_mu_locality_lsb(state->cpp);
*off &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
*off |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
}
return 0 ;
}
Messung V0.5 in Prozent C=92 H=88 G=89
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-10-12)
¤
*© Formatika GbR, Deutschland