root/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nffw_res_info_version_get
  2. nffw_res_flg_init_get
  3. nffw_fwinfo_loaded_get
  4. nffw_fwinfo_mip_cppid_get
  5. nffw_fwinfo_mip_mu_da_get
  6. nffw_fwinfo_mip_offset_get
  7. nffw_res_fwinfos
  8. nfp_nffw_info_open
  9. nfp_nffw_info_close
  10. nfp_nffw_info_fwid_first
  11. nfp_nffw_info_mip_first

   1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
   2 /* Copyright (C) 2015-2018 Netronome Systems, Inc. */
   3 
   4 /*
   5  * nfp_nffw.c
   6  * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
   7  *          Jason McMullan <jason.mcmullan@netronome.com>
   8  *          Francois H. Theron <francois.theron@netronome.com>
   9  */
  10 
  11 #include <linux/kernel.h>
  12 #include <linux/slab.h>
  13 
  14 #include "nfp.h"
  15 #include "nfp_cpp.h"
  16 #include "nfp_nffw.h"
  17 #include "nfp6000/nfp6000.h"
  18 
  19 /* Init-CSR owner IDs for firmware map to firmware IDs which start at 4.
  20  * Lower IDs are reserved for target and loader IDs.
  21  */
  22 #define NFFW_FWID_EXT   3 /* For active MEs that we didn't load. */
  23 #define NFFW_FWID_BASE  4
  24 
  25 #define NFFW_FWID_ALL   255
  26 
  27 /**
  28  * NFFW_INFO_VERSION history:
  29  * 0: This was never actually used (before versioning), but it refers to
  30  *    the previous struct which had FWINFO_CNT = MEINFO_CNT = 120 that later
  31  *    changed to 200.
  32  * 1: First versioned struct, with
  33  *     FWINFO_CNT = 120
  34  *     MEINFO_CNT = 120
  35  * 2:  FWINFO_CNT = 200
  36  *     MEINFO_CNT = 200
  37  */
  38 #define NFFW_INFO_VERSION_CURRENT 2
  39 
  40 /* Enough for all current chip families */
  41 #define NFFW_MEINFO_CNT_V1 120
  42 #define NFFW_FWINFO_CNT_V1 120
  43 #define NFFW_MEINFO_CNT_V2 200
  44 #define NFFW_FWINFO_CNT_V2 200
  45 
  46 /* Work in 32-bit words to make cross-platform endianness easier to handle */
  47 
  48 /** nfp.nffw meinfo **/
  49 struct nffw_meinfo {
  50         __le32 ctxmask__fwid__meid;
  51 };
  52 
  53 struct nffw_fwinfo {
  54         __le32 loaded__mu_da__mip_off_hi;
  55         __le32 mip_cppid; /* 0 means no MIP */
  56         __le32 mip_offset_lo;
  57 };
  58 
  59 struct nfp_nffw_info_v1 {
  60         struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V1];
  61         struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V1];
  62 };
  63 
  64 struct nfp_nffw_info_v2 {
  65         struct nffw_meinfo meinfo[NFFW_MEINFO_CNT_V2];
  66         struct nffw_fwinfo fwinfo[NFFW_FWINFO_CNT_V2];
  67 };
  68 
  69 /** Resource: nfp.nffw main **/
  70 struct nfp_nffw_info_data {
  71         __le32 flags[2];
  72         union {
  73                 struct nfp_nffw_info_v1 v1;
  74                 struct nfp_nffw_info_v2 v2;
  75         } info;
  76 };
  77 
  78 struct nfp_nffw_info {
  79         struct nfp_cpp *cpp;
  80         struct nfp_resource *res;
  81 
  82         struct nfp_nffw_info_data fwinf;
  83 };
  84 
  85 /* flg_info_version = flags[0]<27:16>
  86  * This is a small version counter intended only to detect if the current
  87  * implementation can read the current struct. Struct changes should be very
  88  * rare and as such a 12-bit counter should cover large spans of time. By the
  89  * time it wraps around, we don't expect to have 4096 versions of this struct
  90  * to be in use at the same time.
  91  */
  92 static u32 nffw_res_info_version_get(const struct nfp_nffw_info_data *res)
  93 {
  94         return (le32_to_cpu(res->flags[0]) >> 16) & 0xfff;
  95 }
  96 
  97 /* flg_init = flags[0]<0> */
  98 static u32 nffw_res_flg_init_get(const struct nfp_nffw_info_data *res)
  99 {
 100         return (le32_to_cpu(res->flags[0]) >> 0) & 1;
 101 }
 102 
 103 /* loaded = loaded__mu_da__mip_off_hi<31:31> */
 104 static u32 nffw_fwinfo_loaded_get(const struct nffw_fwinfo *fi)
 105 {
 106         return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 31) & 1;
 107 }
 108 
 109 /* mip_cppid = mip_cppid */
 110 static u32 nffw_fwinfo_mip_cppid_get(const struct nffw_fwinfo *fi)
 111 {
 112         return le32_to_cpu(fi->mip_cppid);
 113 }
 114 
 115 /* loaded = loaded__mu_da__mip_off_hi<8:8> */
 116 static u32 nffw_fwinfo_mip_mu_da_get(const struct nffw_fwinfo *fi)
 117 {
 118         return (le32_to_cpu(fi->loaded__mu_da__mip_off_hi) >> 8) & 1;
 119 }
 120 
 121 /* mip_offset = (loaded__mu_da__mip_off_hi<7:0> << 8) | mip_offset_lo */
 122 static u64 nffw_fwinfo_mip_offset_get(const struct nffw_fwinfo *fi)
 123 {
 124         u64 mip_off_hi = le32_to_cpu(fi->loaded__mu_da__mip_off_hi);
 125 
 126         return (mip_off_hi & 0xFF) << 32 | le32_to_cpu(fi->mip_offset_lo);
 127 }
 128 
 129 static unsigned int
 130 nffw_res_fwinfos(struct nfp_nffw_info_data *fwinf, struct nffw_fwinfo **arr)
 131 {
 132         /* For the this code, version 0 is most likely to be
 133          * version 1 in this case. Since the kernel driver
 134          * does not take responsibility for initialising the
 135          * nfp.nffw resource, any previous code (CA firmware or
 136          * userspace) that left the version 0 and did set
 137          * the init flag is going to be version 1.
 138          */
 139         switch (nffw_res_info_version_get(fwinf)) {
 140         case 0:
 141         case 1:
 142                 *arr = &fwinf->info.v1.fwinfo[0];
 143                 return NFFW_FWINFO_CNT_V1;
 144         case 2:
 145                 *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  * nfp_nffw_info_open() - Acquire the lock on the NFFW table
 155  * @cpp:        NFP CPP handle
 156  *
 157  * Return: pointer to nfp_nffw_info object or ERR_PTR()
 158  */
 159 struct nfp_nffw_info *nfp_nffw_info_open(struct nfp_cpp *cpp)
 160 {
 161         struct nfp_nffw_info_data *fwinf;
 162         struct nfp_nffw_info *state;
 163         u32 info_ver;
 164         int err;
 165 
 166         state = kzalloc(sizeof(*state), GFP_KERNEL);
 167         if (!state)
 168                 return ERR_PTR(-ENOMEM);
 169 
 170         state->res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_NFFW);
 171         if (IS_ERR(state->res))
 172                 goto err_free;
 173 
 174         fwinf = &state->fwinf;
 175 
 176         if (sizeof(*fwinf) > nfp_resource_size(state->res))
 177                 goto err_release;
 178 
 179         err = nfp_cpp_read(cpp, nfp_resource_cpp_id(state->res),
 180                            nfp_resource_address(state->res),
 181                            fwinf, sizeof(*fwinf));
 182         if (err < (int)sizeof(*fwinf))
 183                 goto err_release;
 184 
 185         if (!nffw_res_flg_init_get(fwinf))
 186                 goto err_release;
 187 
 188         info_ver = nffw_res_info_version_get(fwinf);
 189         if (info_ver > NFFW_INFO_VERSION_CURRENT)
 190                 goto err_release;
 191 
 192         state->cpp = cpp;
 193         return state;
 194 
 195 err_release:
 196         nfp_resource_release(state->res);
 197 err_free:
 198         kfree(state);
 199         return ERR_PTR(-EIO);
 200 }
 201 
 202 /**
 203  * nfp_nffw_info_close() - Release the lock on the NFFW table and free state
 204  * @state:      NFP FW info state
 205  */
 206 void nfp_nffw_info_close(struct nfp_nffw_info *state)
 207 {
 208         nfp_resource_release(state->res);
 209         kfree(state);
 210 }
 211 
 212 /**
 213  * nfp_nffw_info_fwid_first() - Return the first firmware ID in the NFFW
 214  * @state:      NFP FW info state
 215  *
 216  * Return: First NFFW firmware info, NULL on failure
 217  */
 218 static struct nffw_fwinfo *nfp_nffw_info_fwid_first(struct nfp_nffw_info *state)
 219 {
 220         struct nffw_fwinfo *fwinfo;
 221         unsigned int cnt, i;
 222 
 223         cnt = nffw_res_fwinfos(&state->fwinf, &fwinfo);
 224         if (!cnt)
 225                 return NULL;
 226 
 227         for (i = 0; i < cnt; i++)
 228                 if (nffw_fwinfo_loaded_get(&fwinfo[i]))
 229                         return &fwinfo[i];
 230 
 231         return NULL;
 232 }
 233 
 234 /**
 235  * nfp_nffw_info_mip_first() - Retrieve the location of the first FW's MIP
 236  * @state:      NFP FW info state
 237  * @cpp_id:     Pointer to the CPP ID of the MIP
 238  * @off:        Pointer to the CPP Address of the MIP
 239  *
 240  * Return: 0, or -ERRNO
 241  */
 242 int nfp_nffw_info_mip_first(struct nfp_nffw_info *state, u32 *cpp_id, u64 *off)
 243 {
 244         struct nffw_fwinfo *fwinfo;
 245 
 246         fwinfo = nfp_nffw_info_fwid_first(state);
 247         if (!fwinfo)
 248                 return -EINVAL;
 249 
 250         *cpp_id = nffw_fwinfo_mip_cppid_get(fwinfo);
 251         *off = nffw_fwinfo_mip_offset_get(fwinfo);
 252 
 253         if (nffw_fwinfo_mip_mu_da_get(fwinfo)) {
 254                 int locality_off = nfp_cpp_mu_locality_lsb(state->cpp);
 255 
 256                 *off &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
 257                 *off |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
 258         }
 259 
 260         return 0;
 261 }

/* [<][>][^][v][top][bottom][index][help] */