Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /* Copyright (C) 2015-2018 Netronome Systems, Inc. */
0003 
0004 /*
0005  * nfp_nffw.c
0006  * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
0007  *          Jason McMullan <jason.mcmullan@netronome.com>
0008  *          Francois H. Theron <francois.theron@netronome.com>
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/slab.h>
0013 
0014 #include "nfp.h"
0015 #include "nfp_cpp.h"
0016 #include "nfp_nffw.h"
0017 #include "nfp6000/nfp6000.h"
0018 
0019 /* Init-CSR owner IDs for firmware map to firmware IDs which start at 4.
0020  * Lower IDs are reserved for target and loader IDs.
0021  */
0022 #define NFFW_FWID_EXT   3 /* For active MEs that we didn't load. */
0023 #define NFFW_FWID_BASE  4
0024 
0025 #define NFFW_FWID_ALL   255
0026 
0027 /*
0028  * NFFW_INFO_VERSION history:
0029  * 0: This was never actually used (before versioning), but it refers to
0030  *    the previous struct which had FWINFO_CNT = MEINFO_CNT = 120 that later
0031  *    changed to 200.
0032  * 1: First versioned struct, with
0033  *     FWINFO_CNT = 120
0034  *     MEINFO_CNT = 120
0035  * 2:  FWINFO_CNT = 200
0036  *     MEINFO_CNT = 200
0037  */
0038 #define NFFW_INFO_VERSION_CURRENT 2
0039 
0040 /* Enough for all current chip families */
0041 #define NFFW_MEINFO_CNT_V1 120
0042 #define NFFW_FWINFO_CNT_V1 120
0043 #define NFFW_MEINFO_CNT_V2 200
0044 #define NFFW_FWINFO_CNT_V2 200
0045 
0046 /* Work in 32-bit words to make cross-platform endianness easier to handle */
0047 
0048 /** nfp.nffw meinfo **/
0049 struct nffw_meinfo {
0050     __le32 ctxmask__fwid__meid;
0051 };
0052 
0053 struct nffw_fwinfo {
0054     __le32 loaded__mu_da__mip_off_hi;
0055     __le32 mip_cppid; /* 0 means no MIP */
0056     __le32 mip_offset_lo;
0057 };
0058 
0059 struct nfp_nffw_info_v1 {
0060     struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V1];
0061     struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V1];
0062 };
0063 
0064 struct nfp_nffw_info_v2 {
0065     struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V2];
0066     struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V2];
0067 };
0068 
0069 /** Resource: nfp.nffw main **/
0070 struct nfp_nffw_info_data {
0071     __le32 flags[2];
0072     union {
0073         struct nfp_nffw_info_v1 v1;
0074         struct nfp_nffw_info_v2 v2;
0075     } info;
0076 };
0077 
0078 struct nfp_nffw_info {
0079     struct nfp_cpp *cpp;
0080     struct nfp_resource *res;
0081 
0082     struct nfp_nffw_info_data fwinf;
0083 };
0084 
0085 /* flg_info_version = flags[0]<27:16>
0086  * This is a small version counter intended only to detect if the current
0087  * implementation can read the current struct. Struct changes should be very
0088  * rare and as such a 12-bit counter should cover large spans of time. By the
0089  * time it wraps around, we don't expect to have 4096 versions of this struct
0090  * to be in use at the same time.
0091  */
0092 static u32 nffw_res_info_version_get(const struct nfp_nffw_info_data *res)
0093 {
0094     return (le32_to_cpu(res->flags[0]) >> 16) & 0xfff;
0095 }
0096 
0097 /* flg_init = flags[0]<0> */
0098 static u32 nffw_res_flg_init_get(const struct nfp_nffw_info_data *res)
0099 {
0100     return (le32_to_cpu(res->flags[0]) >> 0) & 1;
0101 }
0102 
0103 /* loaded = loaded__mu_da__mip_off_hi<31:31> */
0104 static u32 nffw_fwinfo_loaded_get(const struct nffw_fwinfo *fi)
0105 {
0106     return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 31) & 1;
0107 }
0108 
0109 /* mip_cppid = mip_cppid */
0110 static u32 nffw_fwinfo_mip_cppid_get(const struct nffw_fwinfo *fi)
0111 {
0112     return le32_to_cpu(fi->mip_cppid);
0113 }
0114 
0115 /* loaded = loaded__mu_da__mip_off_hi<8:8> */
0116 static u32 nffw_fwinfo_mip_mu_da_get(const struct nffw_fwinfo *fi)
0117 {
0118     return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 8) & 1;
0119 }
0120 
0121 /* mip_offset = (loaded__mu_da__mip_off_hi<7:0> << 8) | mip_offset_lo */
0122 static u64 nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi)
0123 {
0124     u64 mip_off_hi = le32_to_cpu(fi->loaded__mu_da__mip_off_hi);
0125 
0126     return (mip_off_hi & 0xFF) << 32 | le32_to_cpu(fi->mip_offset_lo);
0127 }
0128 
0129 static unsigned int
0130 nffw_res_fwinfos(struct nfp_nffw_info_data *fwinf, struct nffw_fwinfo **arr)
0131 {
0132     /* For the this code, version 0 is most likely to be
0133      * version 1 in this case. Since the kernel driver
0134      * does not take responsibility for initialising the
0135      * nfp.nffw resource, any previous code (CA firmware or
0136      * userspace) that left the version 0 and did set
0137      * the init flag is going to be version 1.
0138      */
0139     switch (nffw_res_info_version_get(fwinf)) {
0140     case 0:
0141     case 1:
0142         *arr = &fwinf->info.v1.fwinfo[0];
0143         return NFFW_FWINFO_CNT_V1;
0144     case 2:
0145         *arr = &fwinf->info.v2.fwinfo[0];
0146         return NFFW_FWINFO_CNT_V2;
0147     default:
0148         *arr = NULL;
0149         return 0;
0150     }
0151 }
0152 
0153 /**
0154  * nfp_nffw_info_open() - Acquire the lock on the NFFW table
0155  * @cpp:    NFP CPP handle
0156  *
0157  * Return: pointer to nfp_nffw_info object or ERR_PTR()
0158  */
0159 struct nfp_nffw_info *nfp_nffw_info_open(struct nfp_cpp *cpp)
0160 {
0161     struct nfp_nffw_info_data *fwinf;
0162     struct nfp_nffw_info *state;
0163     u32 info_ver;
0164     int err;
0165 
0166     state = kzalloc(sizeof(*state), GFP_KERNEL);
0167     if (!state)
0168         return ERR_PTR(-ENOMEM);
0169 
0170     state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW);
0171     if (IS_ERR(state->res))
0172         goto err_free;
0173 
0174     fwinf = &state->fwinf;
0175 
0176     if (sizeof(*fwinf) > nfp_resource_size(state->res))
0177         goto err_release;
0178 
0179     err = nfp_cpp_read(cpp, nfp_resource_cpp_id(state->res),
0180                nfp_resource_address(state->res),
0181                fwinf, sizeof(*fwinf));
0182     if (err < (int)sizeof(*fwinf))
0183         goto err_release;
0184 
0185     if (!nffw_res_flg_init_get(fwinf))
0186         goto err_release;
0187 
0188     info_ver = nffw_res_info_version_get(fwinf);
0189     if (info_ver > NFFW_INFO_VERSION_CURRENT)
0190         goto err_release;
0191 
0192     state->cpp = cpp;
0193     return state;
0194 
0195 err_release:
0196     nfp_resource_release(state->res);
0197 err_free:
0198     kfree(state);
0199     return ERR_PTR(-EIO);
0200 }
0201 
0202 /**
0203  * nfp_nffw_info_close() - Release the lock on the NFFW table and free state
0204  * @state:  NFP FW info state
0205  */
0206 void nfp_nffw_info_close(struct nfp_nffw_info *state)
0207 {
0208     nfp_resource_release(state->res);
0209     kfree(state);
0210 }
0211 
0212 /**
0213  * nfp_nffw_info_fwid_first() - Return the first firmware ID in the NFFW
0214  * @state:  NFP FW info state
0215  *
0216  * Return: First NFFW firmware info, NULL on failure
0217  */
0218 static struct nffw_fwinfo *nfp_nffw_info_fwid_first(struct nfp_nffw_info *state)
0219 {
0220     struct nffw_fwinfo *fwinfo;
0221     unsigned int cnt, i;
0222 
0223     cnt = nffw_res_fwinfos(&state->fwinf, &fwinfo);
0224     if (!cnt)
0225         return NULL;
0226 
0227     for (i = 0; i < cnt; i++)
0228         if (nffw_fwinfo_loaded_get(&fwinfo[i]))
0229             return &fwinfo[i];
0230 
0231     return NULL;
0232 }
0233 
0234 /**
0235  * nfp_nffw_info_mip_first() - Retrieve the location of the first FW's MIP
0236  * @state:  NFP FW info state
0237  * @cpp_id: Pointer to the CPP ID of the MIP
0238  * @off:    Pointer to the CPP Address of the MIP
0239  *
0240  * Return: 0, or -ERRNO
0241  */
0242 int nfp_nffw_info_mip_first(struct nfp_nffw_info *state, u32 *cpp_id, u64 *off)
0243 {
0244     struct nffw_fwinfo *fwinfo;
0245 
0246     fwinfo = nfp_nffw_info_fwid_first(state);
0247     if (!fwinfo)
0248         return -EINVAL;
0249 
0250     *cpp_id = nffw_fwinfo_mip_cppid_get(fwinfo);
0251     *off = nffw_fwinfo_mip_offset_get(fwinfo);
0252 
0253     if (nffw_fwinfo_mip_mu_da_get(fwinfo)) {
0254         int locality_off = nfp_cpp_mu_locality_lsb(state->cpp);
0255 
0256         *off &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
0257         *off |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
0258     }
0259 
0260     return 0;
0261 }