linux/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.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_resource.c
  36 * Author: Jakub Kicinski <jakub.kicinski@netronome.com>
  37 *         Jason McMullan <jason.mcmullan@netronome.com>
  38 */
  39#include <linux/delay.h>
  40#include <linux/kernel.h>
  41#include <linux/slab.h>
  42
  43#include "crc32.h"
  44#include "nfp.h"
  45#include "nfp_cpp.h"
  46#include "nfp6000/nfp6000.h"
  47
  48#define NFP_RESOURCE_ENTRY_NAME_SZ      8
  49
  50/**
  51 * struct nfp_resource_entry - Resource table entry
  52 * @owner:              NFP CPP Lock, interface owner
  53 * @key:                NFP CPP Lock, posix_crc32(name, 8)
  54 * @region:             Memory region descriptor
  55 * @name:               ASCII, zero padded name
  56 * @reserved
  57 * @cpp_action:         CPP Action
  58 * @cpp_token:          CPP Token
  59 * @cpp_target:         CPP Target ID
  60 * @page_offset:        256-byte page offset into target's CPP address
  61 * @page_size:          size, in 256-byte pages
  62 */
  63struct nfp_resource_entry {
  64        struct nfp_resource_entry_mutex {
  65                u32 owner;
  66                u32 key;
  67        } mutex;
  68        struct nfp_resource_entry_region {
  69                u8  name[NFP_RESOURCE_ENTRY_NAME_SZ];
  70                u8  reserved[5];
  71                u8  cpp_action;
  72                u8  cpp_token;
  73                u8  cpp_target;
  74                u32 page_offset;
  75                u32 page_size;
  76        } region;
  77};
  78
  79#define NFP_RESOURCE_TBL_SIZE           4096
  80#define NFP_RESOURCE_TBL_ENTRIES        (NFP_RESOURCE_TBL_SIZE /        \
  81                                         sizeof(struct nfp_resource_entry))
  82
  83struct nfp_resource {
  84        char name[NFP_RESOURCE_ENTRY_NAME_SZ + 1];
  85        u32 cpp_id;
  86        u64 addr;
  87        u64 size;
  88        struct nfp_cpp_mutex *mutex;
  89};
  90
  91static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
  92{
  93        char name_pad[NFP_RESOURCE_ENTRY_NAME_SZ] = {};
  94        struct nfp_resource_entry entry;
  95        u32 cpp_id, key;
  96        int ret, i;
  97
  98        cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0);  /* Atomic read */
  99
 100        strncpy(name_pad, res->name, sizeof(name_pad));
 101
 102        /* Search for a matching entry */
 103        key = NFP_RESOURCE_TBL_KEY;
 104        if (memcmp(name_pad, NFP_RESOURCE_TBL_NAME "\0\0\0\0\0\0\0\0", 8))
 105                key = crc32_posix(name_pad, sizeof(name_pad));
 106
 107        for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
 108                u64 addr = NFP_RESOURCE_TBL_BASE +
 109                        sizeof(struct nfp_resource_entry) * i;
 110
 111                ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry));
 112                if (ret != sizeof(entry))
 113                        return -EIO;
 114
 115                if (entry.mutex.key != key)
 116                        continue;
 117
 118                /* Found key! */
 119                res->mutex =
 120                        nfp_cpp_mutex_alloc(cpp,
 121                                            NFP_RESOURCE_TBL_TARGET, addr, key);
 122                res->cpp_id = NFP_CPP_ID(entry.region.cpp_target,
 123                                         entry.region.cpp_action,
 124                                         entry.region.cpp_token);
 125                res->addr = (u64)entry.region.page_offset << 8;
 126                res->size = (u64)entry.region.page_size << 8;
 127
 128                return 0;
 129        }
 130
 131        return -ENOENT;
 132}
 133
 134static int
 135nfp_resource_try_acquire(struct nfp_cpp *cpp, struct nfp_resource *res,
 136                         struct nfp_cpp_mutex *dev_mutex)
 137{
 138        int err;
 139
 140        if (nfp_cpp_mutex_lock(dev_mutex))
 141                return -EINVAL;
 142
 143        err = nfp_cpp_resource_find(cpp, res);
 144        if (err)
 145                goto err_unlock_dev;
 146
 147        err = nfp_cpp_mutex_trylock(res->mutex);
 148        if (err)
 149                goto err_res_mutex_free;
 150
 151        nfp_cpp_mutex_unlock(dev_mutex);
 152
 153        return 0;
 154
 155err_res_mutex_free:
 156        nfp_cpp_mutex_free(res->mutex);
 157err_unlock_dev:
 158        nfp_cpp_mutex_unlock(dev_mutex);
 159
 160        return err;
 161}
 162
 163/**
 164 * nfp_resource_acquire() - Acquire a resource handle
 165 * @cpp:        NFP CPP handle
 166 * @name:       Name of the resource
 167 *
 168 * NOTE: This function locks the acquired resource
 169 *
 170 * Return: NFP Resource handle, or ERR_PTR()
 171 */
 172struct nfp_resource *
 173nfp_resource_acquire(struct nfp_cpp *cpp, const char *name)
 174{
 175        unsigned long warn_at = jiffies + 15 * HZ;
 176        struct nfp_cpp_mutex *dev_mutex;
 177        struct nfp_resource *res;
 178        int err;
 179
 180        res = kzalloc(sizeof(*res), GFP_KERNEL);
 181        if (!res)
 182                return ERR_PTR(-ENOMEM);
 183
 184        strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ);
 185
 186        dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
 187                                        NFP_RESOURCE_TBL_BASE,
 188                                        NFP_RESOURCE_TBL_KEY);
 189        if (!dev_mutex) {
 190                kfree(res);
 191                return ERR_PTR(-ENOMEM);
 192        }
 193
 194        for (;;) {
 195                err = nfp_resource_try_acquire(cpp, res, dev_mutex);
 196                if (!err)
 197                        break;
 198                if (err != -EBUSY)
 199                        goto err_free;
 200
 201                err = msleep_interruptible(1);
 202                if (err != 0) {
 203                        err = -ERESTARTSYS;
 204                        goto err_free;
 205                }
 206
 207                if (time_is_before_eq_jiffies(warn_at)) {
 208                        warn_at = jiffies + 60 * HZ;
 209                        nfp_warn(cpp, "Warning: waiting for NFP resource %s\n",
 210                                 name);
 211                }
 212        }
 213
 214        nfp_cpp_mutex_free(dev_mutex);
 215
 216        return res;
 217
 218err_free:
 219        nfp_cpp_mutex_free(dev_mutex);
 220        kfree(res);
 221        return ERR_PTR(err);
 222}
 223
 224/**
 225 * nfp_resource_release() - Release a NFP Resource handle
 226 * @res:        NFP Resource handle
 227 *
 228 * NOTE: This function implictly unlocks the resource handle
 229 */
 230void nfp_resource_release(struct nfp_resource *res)
 231{
 232        nfp_cpp_mutex_unlock(res->mutex);
 233        nfp_cpp_mutex_free(res->mutex);
 234        kfree(res);
 235}
 236
 237/**
 238 * nfp_resource_cpp_id() - Return the cpp_id of a resource handle
 239 * @res:        NFP Resource handle
 240 *
 241 * Return: NFP CPP ID
 242 */
 243u32 nfp_resource_cpp_id(struct nfp_resource *res)
 244{
 245        return res->cpp_id;
 246}
 247
 248/**
 249 * nfp_resource_name() - Return the name of a resource handle
 250 * @res:        NFP Resource handle
 251 *
 252 * Return: const char pointer to the name of the resource
 253 */
 254const char *nfp_resource_name(struct nfp_resource *res)
 255{
 256        return res->name;
 257}
 258
 259/**
 260 * nfp_resource_address() - Return the address of a resource handle
 261 * @res:        NFP Resource handle
 262 *
 263 * Return: Address of the resource
 264 */
 265u64 nfp_resource_address(struct nfp_resource *res)
 266{
 267        return res->addr;
 268}
 269
 270/**
 271 * nfp_resource_size() - Return the size in bytes of a resource handle
 272 * @res:        NFP Resource handle
 273 *
 274 * Return: Size of the resource in bytes
 275 */
 276u64 nfp_resource_size(struct nfp_resource *res)
 277{
 278        return res->size;
 279}
 280