linux/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_rtsym.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015-2017 Netronome Systems, Inc.
   3 *
   4 * This software is dual licensed under the GNU General License Version 2,
   5 * June 1991 as shown in the file COPYING in the top-level directory of this
   6 * source tree or the BSD 2-Clause License provided below.  You have the
   7 * option to license this software under the complete terms of either license.
   8 *
   9 * The BSD 2-Clause License:
  10 *
  11 *     Redistribution and use in source and binary forms, with or
  12 *     without modification, are permitted provided that the following
  13 *     conditions are met:
  14 *
  15 *      1. Redistributions of source code must retain the above
  16 *         copyright notice, this list of conditions and the following
  17 *         disclaimer.
  18 *
  19 *      2. Redistributions in binary form must reproduce the above
  20 *         copyright notice, this list of conditions and the following
  21 *         disclaimer in the documentation and/or other materials
  22 *         provided with the distribution.
  23 *
  24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  31 * SOFTWARE.
  32 */
  33
  34/*
  35 * nfp_rtsym.c
  36 * Interface for accessing run-time symbol table
  37 * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
  38 *          Jason McMullan <jason.mcmullan@netronome.com>
  39 *          Espen Skoglund <espen.skoglund@netronome.com>
  40 *          Francois H. Theron <francois.theron@netronome.com>
  41 */
  42#include <linux/kernel.h>
  43#include <linux/module.h>
  44#include <linux/slab.h>
  45#include <linux/io-64-nonatomic-hi-lo.h>
  46
  47#include "nfp.h"
  48#include "nfp_cpp.h"
  49#include "nfp_nffw.h"
  50#include "nfp6000/nfp6000.h"
  51
  52/* These need to match the linker */
  53#define SYM_TGT_LMEM            0
  54#define SYM_TGT_EMU_CACHE       0x17
  55
  56struct nfp_rtsym_entry {
  57        u8      type;
  58        u8      target;
  59        u8      island;
  60        u8      addr_hi;
  61        __le32  addr_lo;
  62        __le16  name;
  63        u8      menum;
  64        u8      size_hi;
  65        __le32  size_lo;
  66};
  67
  68struct nfp_rtsym_table {
  69        struct nfp_cpp *cpp;
  70        int num;
  71        char *strtab;
  72        struct nfp_rtsym symtab[];
  73};
  74
  75static int nfp_meid(u8 island_id, u8 menum)
  76{
  77        return (island_id & 0x3F) == island_id && menum < 12 ?
  78                (island_id << 4) | (menum + 4) : -1;
  79}
  80
  81static void
  82nfp_rtsym_sw_entry_init(struct nfp_rtsym_table *cache, u32 strtab_size,
  83                        struct nfp_rtsym *sw, struct nfp_rtsym_entry *fw)
  84{
  85        sw->type = fw->type;
  86        sw->name = cache->strtab + le16_to_cpu(fw->name) % strtab_size;
  87        sw->addr = ((u64)fw->addr_hi << 32) | le32_to_cpu(fw->addr_lo);
  88        sw->size = ((u64)fw->size_hi << 32) | le32_to_cpu(fw->size_lo);
  89
  90        switch (fw->target) {
  91        case SYM_TGT_LMEM:
  92                sw->target = NFP_RTSYM_TARGET_LMEM;
  93                break;
  94        case SYM_TGT_EMU_CACHE:
  95                sw->target = NFP_RTSYM_TARGET_EMU_CACHE;
  96                break;
  97        default:
  98                sw->target = fw->target;
  99                break;
 100        }
 101
 102        if (fw->menum != 0xff)
 103                sw->domain = nfp_meid(fw->island, fw->menum);
 104        else if (fw->island != 0xff)
 105                sw->domain = fw->island;
 106        else
 107                sw->domain = -1;
 108}
 109
 110struct nfp_rtsym_table *nfp_rtsym_table_read(struct nfp_cpp *cpp)
 111{
 112        struct nfp_rtsym_table *rtbl;
 113        const struct nfp_mip *mip;
 114
 115        mip = nfp_mip_open(cpp);
 116        rtbl = __nfp_rtsym_table_read(cpp, mip);
 117        nfp_mip_close(mip);
 118
 119        return rtbl;
 120}
 121
 122struct nfp_rtsym_table *
 123__nfp_rtsym_table_read(struct nfp_cpp *cpp, const struct nfp_mip *mip)
 124{
 125        const u32 dram = NFP_CPP_ID(NFP_CPP_TARGET_MU, NFP_CPP_ACTION_RW, 0) |
 126                NFP_ISL_EMEM0;
 127        u32 strtab_addr, symtab_addr, strtab_size, symtab_size;
 128        struct nfp_rtsym_entry *rtsymtab;
 129        struct nfp_rtsym_table *cache;
 130        int err, n, size;
 131
 132        if (!mip)
 133                return NULL;
 134
 135        nfp_mip_strtab(mip, &strtab_addr, &strtab_size);
 136        nfp_mip_symtab(mip, &symtab_addr, &symtab_size);
 137
 138        if (!symtab_size || !strtab_size || symtab_size % sizeof(*rtsymtab))
 139                return NULL;
 140
 141        /* Align to 64 bits */
 142        symtab_size = round_up(symtab_size, 8);
 143        strtab_size = round_up(strtab_size, 8);
 144
 145        rtsymtab = kmalloc(symtab_size, GFP_KERNEL);
 146        if (!rtsymtab)
 147                return NULL;
 148
 149        size = sizeof(*cache);
 150        size += symtab_size / sizeof(*rtsymtab) * sizeof(struct nfp_rtsym);
 151        size += strtab_size + 1;
 152        cache = kmalloc(size, GFP_KERNEL);
 153        if (!cache)
 154                goto exit_free_rtsym_raw;
 155
 156        cache->cpp = cpp;
 157        cache->num = symtab_size / sizeof(*rtsymtab);
 158        cache->strtab = (void *)&cache->symtab[cache->num];
 159
 160        err = nfp_cpp_read(cpp, dram, symtab_addr, rtsymtab, symtab_size);
 161        if (err != symtab_size)
 162                goto exit_free_cache;
 163
 164        err = nfp_cpp_read(cpp, dram, strtab_addr, cache->strtab, strtab_size);
 165        if (err != strtab_size)
 166                goto exit_free_cache;
 167        cache->strtab[strtab_size] = '\0';
 168
 169        for (n = 0; n < cache->num; n++)
 170                nfp_rtsym_sw_entry_init(cache, strtab_size,
 171                                        &cache->symtab[n], &rtsymtab[n]);
 172
 173        kfree(rtsymtab);
 174
 175        return cache;
 176
 177exit_free_cache:
 178        kfree(cache);
 179exit_free_rtsym_raw:
 180        kfree(rtsymtab);
 181        return NULL;
 182}
 183
 184/**
 185 * nfp_rtsym_count() - Get the number of RTSYM descriptors
 186 * @rtbl:       NFP RTsym table
 187 *
 188 * Return: Number of RTSYM descriptors
 189 */
 190int nfp_rtsym_count(struct nfp_rtsym_table *rtbl)
 191{
 192        if (!rtbl)
 193                return -EINVAL;
 194        return rtbl->num;
 195}
 196
 197/**
 198 * nfp_rtsym_get() - Get the Nth RTSYM descriptor
 199 * @rtbl:       NFP RTsym table
 200 * @idx:        Index (0-based) of the RTSYM descriptor
 201 *
 202 * Return: const pointer to a struct nfp_rtsym descriptor, or NULL
 203 */
 204const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx)
 205{
 206        if (!rtbl)
 207                return NULL;
 208        if (idx >= rtbl->num)
 209                return NULL;
 210
 211        return &rtbl->symtab[idx];
 212}
 213
 214/**
 215 * nfp_rtsym_lookup() - Return the RTSYM descriptor for a symbol name
 216 * @rtbl:       NFP RTsym table
 217 * @name:       Symbol name
 218 *
 219 * Return: const pointer to a struct nfp_rtsym descriptor, or NULL
 220 */
 221const struct nfp_rtsym *
 222nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name)
 223{
 224        int n;
 225
 226        if (!rtbl)
 227                return NULL;
 228
 229        for (n = 0; n < rtbl->num; n++)
 230                if (strcmp(name, rtbl->symtab[n].name) == 0)
 231                        return &rtbl->symtab[n];
 232
 233        return NULL;
 234}
 235
 236/**
 237 * nfp_rtsym_read_le() - Read a simple unsigned scalar value from symbol
 238 * @rtbl:       NFP RTsym table
 239 * @name:       Symbol name
 240 * @error:      Poniter to error code (optional)
 241 *
 242 * Lookup a symbol, map, read it and return it's value. Value of the symbol
 243 * will be interpreted as a simple little-endian unsigned value. Symbol can
 244 * be 4 or 8 bytes in size.
 245 *
 246 * Return: value read, on error sets the error and returns ~0ULL.
 247 */
 248u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name,
 249                      int *error)
 250{
 251        const struct nfp_rtsym *sym;
 252        u32 val32, id;
 253        u64 val;
 254        int err;
 255
 256        sym = nfp_rtsym_lookup(rtbl, name);
 257        if (!sym) {
 258                err = -ENOENT;
 259                goto exit;
 260        }
 261
 262        id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, sym->domain);
 263
 264        switch (sym->size) {
 265        case 4:
 266                err = nfp_cpp_readl(rtbl->cpp, id, sym->addr, &val32);
 267                val = val32;
 268                break;
 269        case 8:
 270                err = nfp_cpp_readq(rtbl->cpp, id, sym->addr, &val);
 271                break;
 272        default:
 273                nfp_err(rtbl->cpp,
 274                        "rtsym '%s' unsupported or non-scalar size: %lld\n",
 275                        name, sym->size);
 276                err = -EINVAL;
 277                break;
 278        }
 279
 280exit:
 281        if (error)
 282                *error = err;
 283
 284        if (err)
 285                return ~0ULL;
 286        return val;
 287}
 288
 289u8 __iomem *
 290nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id,
 291              unsigned int min_size, struct nfp_cpp_area **area)
 292{
 293        const struct nfp_rtsym *sym;
 294        u8 __iomem *mem;
 295
 296        sym = nfp_rtsym_lookup(rtbl, name);
 297        if (!sym)
 298                return (u8 __iomem *)ERR_PTR(-ENOENT);
 299
 300        if (sym->size < min_size) {
 301                nfp_err(rtbl->cpp, "Symbol %s too small\n", name);
 302                return (u8 __iomem *)ERR_PTR(-EINVAL);
 303        }
 304
 305        mem = nfp_cpp_map_area(rtbl->cpp, id, sym->domain, sym->target,
 306                               sym->addr, sym->size, area);
 307        if (IS_ERR(mem)) {
 308                nfp_err(rtbl->cpp, "Failed to map symbol %s: %ld\n",
 309                        name, PTR_ERR(mem));
 310                return mem;
 311        }
 312
 313        return mem;
 314}
 315