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_TBL_TARGET         NFP_CPP_TARGET_MU
  49#define NFP_RESOURCE_TBL_BASE           0x8100000000ULL
  50
  51/* NFP Resource Table self-identifier */
  52#define NFP_RESOURCE_TBL_NAME           "nfp.res"
  53#define NFP_RESOURCE_TBL_KEY            0x00000000 /* Special key for entry 0 */
  54
  55#define NFP_RESOURCE_ENTRY_NAME_SZ      8
  56
  57/**
  58 * struct nfp_resource_entry - Resource table entry
  59 * @mutex:      NFP CPP Lock
  60 * @mutex.owner:        NFP CPP Lock, interface owner
  61 * @mutex.key:          NFP CPP Lock, posix_crc32(name, 8)
  62 * @region:     Memory region descriptor
  63 * @region.name:        ASCII, zero padded name
  64 * @region.reserved:    padding
  65 * @region.cpp_action:  CPP Action
  66 * @region.cpp_token:   CPP Token
  67 * @region.cpp_target:  CPP Target ID
  68 * @region.page_offset: 256-byte page offset into target's CPP address
  69 * @region.page_size:   size, in 256-byte pages
  70 */
  71struct nfp_resource_entry {
  72        struct nfp_resource_entry_mutex {
  73                u32 owner;
  74                u32 key;
  75        } mutex;
  76        struct nfp_resource_entry_region {
  77                u8  name[NFP_RESOURCE_ENTRY_NAME_SZ];
  78                u8  reserved[5];
  79                u8  cpp_action;
  80                u8  cpp_token;
  81                u8  cpp_target;
  82                u32 page_offset;
  83                u32 page_size;
  84        } region;
  85};
  86
  87#define NFP_RESOURCE_TBL_SIZE           4096
  88#define NFP_RESOURCE_TBL_ENTRIES        (NFP_RESOURCE_TBL_SIZE /        \
  89                                         sizeof(struct nfp_resource_entry))
  90
  91struct nfp_resource {
  92        char name[NFP_RESOURCE_ENTRY_NAME_SZ + 1];
  93        u32 cpp_id;
  94        u64 addr;
  95        u64 size;
  96        struct nfp_cpp_mutex *mutex;
  97};
  98
  99static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
 100{
 101        struct nfp_resource_entry entry;
 102        u32 cpp_id, key;
 103        int ret, i;
 104
 105        cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0);  /* Atomic read */
 106
 107        /* Search for a matching entry */
 108        if (!strcmp(res->name, NFP_RESOURCE_TBL_NAME)) {
 109                nfp_err(cpp, "Grabbing device lock not supported\n");
 110                return -EOPNOTSUPP;
 111        }
 112        key = crc32_posix(res->name, NFP_RESOURCE_ENTRY_NAME_SZ);
 113
 114        for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
 115                u64 addr = NFP_RESOURCE_TBL_BASE +
 116                        sizeof(struct nfp_resource_entry) * i;
 117
 118                ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry));
 119                if (ret != sizeof(entry))
 120                        return -EIO;
 121
 122                if (entry.mutex.key != key)
 123                        continue;
 124
 125                /* Found key! */
 126                res->mutex =
 127                        nfp_cpp_mutex_alloc(cpp,
 128                                            NFP_RESOURCE_TBL_TARGET, addr, key);
 129                res->cpp_id = NFP_CPP_ID(entry.region.cpp_target,
 130                                         entry.region.cpp_action,
 131                                         entry.region.cpp_token);
 132                res->addr = (u64)entry.region.page_offset << 8;
 133                res->size = (u64)entry.region.page_size << 8;
 134
 135                return 0;
 136        }
 137
 138        return -ENOENT;
 139}
 140
 141static int
 142nfp_resource_try_acquire(struct nfp_cpp *cpp, struct nfp_resource *res,
 143                         struct nfp_cpp_mutex *dev_mutex)
 144{
 145        int err;
 146
 147        if (nfp_cpp_mutex_lock(dev_mutex))
 148                return -EINVAL;
 149
 150        err = nfp_cpp_resource_find(cpp, res);
 151        if (err)
 152                goto err_unlock_dev;
 153
 154        err = nfp_cpp_mutex_trylock(res->mutex);
 155        if (err)
 156                goto err_res_mutex_free;
 157
 158        nfp_cpp_mutex_unlock(dev_mutex);
 159
 160        return 0;
 161
 162err_res_mutex_free:
 163        nfp_cpp_mutex_free(res->mutex);
 164err_unlock_dev:
 165        nfp_cpp_mutex_unlock(dev_mutex);
 166
 167        return err;
 168}
 169
 170/**
 171 * nfp_resource_acquire() - Acquire a resource handle
 172 * @cpp:        NFP CPP handle
 173 * @name:       Name of the resource
 174 *
 175 * NOTE: This function locks the acquired resource
 176 *
 177 * Return: NFP Resource handle, or ERR_PTR()
 178 */
 179struct nfp_resource *
 180nfp_resource_acquire(struct nfp_cpp *cpp, const char *name)
 181{
 182        unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
 183        unsigned long err_at = jiffies + NFP_MUTEX_WAIT_ERROR * HZ;
 184        struct nfp_cpp_mutex *dev_mutex;
 185        struct nfp_resource *res;
 186        int err;
 187
 188        res = kzalloc(sizeof(*res), GFP_KERNEL);
 189        if (!res)
 190                return ERR_PTR(-ENOMEM);
 191
 192        strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ);
 193
 194        dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
 195                                        NFP_RESOURCE_TBL_BASE,
 196                                        NFP_RESOURCE_TBL_KEY);
 197        if (!dev_mutex) {
 198                kfree(res);
 199                return ERR_PTR(-ENOMEM);
 200        }
 201
 202        for (;;) {
 203                err = nfp_resource_try_acquire(cpp, res, dev_mutex);
 204                if (!err)
 205                        break;
 206                if (err != -EBUSY)
 207                        goto err_free;
 208
 209                err = msleep_interruptible(1);
 210                if (err != 0) {
 211                        err = -ERESTARTSYS;
 212                        goto err_free;
 213                }
 214
 215                if (time_is_before_eq_jiffies(warn_at)) {
 216                        warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
 217                        nfp_warn(cpp, "Warning: waiting for NFP resource %s\n",
 218                                 name);
 219                }
 220                if (time_is_before_eq_jiffies(err_at)) {
 221                        nfp_err(cpp, "Error: resource %s timed out\n", name);
 222                        err = -EBUSY;
 223                        goto err_free;
 224                }
 225        }
 226
 227        nfp_cpp_mutex_free(dev_mutex);
 228
 229        return res;
 230
 231err_free:
 232        nfp_cpp_mutex_free(dev_mutex);
 233        kfree(res);
 234        return ERR_PTR(err);
 235}
 236
 237/**
 238 * nfp_resource_release() - Release a NFP Resource handle
 239 * @res:        NFP Resource handle
 240 *
 241 * NOTE: This function implictly unlocks the resource handle
 242 */
 243void nfp_resource_release(struct nfp_resource *res)
 244{
 245        nfp_cpp_mutex_unlock(res->mutex);
 246        nfp_cpp_mutex_free(res->mutex);
 247        kfree(res);
 248}
 249
 250/**
 251 * nfp_resource_wait() - Wait for resource to appear
 252 * @cpp:        NFP CPP handle
 253 * @name:       Name of the resource
 254 * @secs:       Number of seconds to wait
 255 *
 256 * Wait for resource to appear in the resource table, grab and release
 257 * its lock.  The wait is jiffies-based, don't expect fine granularity.
 258 *
 259 * Return: 0 on success, errno otherwise.
 260 */
 261int nfp_resource_wait(struct nfp_cpp *cpp, const char *name, unsigned int secs)
 262{
 263        unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
 264        unsigned long err_at = jiffies + secs * HZ;
 265        struct nfp_resource *res;
 266
 267        while (true) {
 268                res = nfp_resource_acquire(cpp, name);
 269                if (!IS_ERR(res)) {
 270                        nfp_resource_release(res);
 271                        return 0;
 272                }
 273
 274                if (PTR_ERR(res) != -ENOENT) {
 275                        nfp_err(cpp, "error waiting for resource %s: %ld\n",
 276                                name, PTR_ERR(res));
 277                        return PTR_ERR(res);
 278                }
 279                if (time_is_before_eq_jiffies(err_at)) {
 280                        nfp_err(cpp, "timeout waiting for resource %s\n", name);
 281                        return -ETIMEDOUT;
 282                }
 283                if (time_is_before_eq_jiffies(warn_at)) {
 284                        warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
 285                        nfp_info(cpp, "waiting for NFP resource %s\n", name);
 286                }
 287                if (msleep_interruptible(10)) {
 288                        nfp_err(cpp, "wait for resource %s interrupted\n",
 289                                name);
 290                        return -ERESTARTSYS;
 291                }
 292        }
 293}
 294
 295/**
 296 * nfp_resource_cpp_id() - Return the cpp_id of a resource handle
 297 * @res:        NFP Resource handle
 298 *
 299 * Return: NFP CPP ID
 300 */
 301u32 nfp_resource_cpp_id(struct nfp_resource *res)
 302{
 303        return res->cpp_id;
 304}
 305
 306/**
 307 * nfp_resource_name() - Return the name of a resource handle
 308 * @res:        NFP Resource handle
 309 *
 310 * Return: const char pointer to the name of the resource
 311 */
 312const char *nfp_resource_name(struct nfp_resource *res)
 313{
 314        return res->name;
 315}
 316
 317/**
 318 * nfp_resource_address() - Return the address of a resource handle
 319 * @res:        NFP Resource handle
 320 *
 321 * Return: Address of the resource
 322 */
 323u64 nfp_resource_address(struct nfp_resource *res)
 324{
 325        return res->addr;
 326}
 327
 328/**
 329 * nfp_resource_size() - Return the size in bytes of a resource handle
 330 * @res:        NFP Resource handle
 331 *
 332 * Return: Size of the resource in bytes
 333 */
 334u64 nfp_resource_size(struct nfp_resource *res)
 335{
 336        return res->size;
 337}
 338
 339/**
 340 * nfp_resource_table_init() - Run initial checks on the resource table
 341 * @cpp:        NFP CPP handle
 342 *
 343 * Start-of-day init procedure for resource table.  Must be called before
 344 * any local resource table users may exist.
 345 *
 346 * Return: 0 on success, -errno on failure
 347 */
 348int nfp_resource_table_init(struct nfp_cpp *cpp)
 349{
 350        struct nfp_cpp_mutex *dev_mutex;
 351        int i, err;
 352
 353        err = nfp_cpp_mutex_reclaim(cpp, NFP_RESOURCE_TBL_TARGET,
 354                                    NFP_RESOURCE_TBL_BASE);
 355        if (err < 0) {
 356                nfp_err(cpp, "Error: failed to reclaim resource table mutex\n");
 357                return err;
 358        }
 359        if (err)
 360                nfp_warn(cpp, "Warning: busted main resource table mutex\n");
 361
 362        dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
 363                                        NFP_RESOURCE_TBL_BASE,
 364                                        NFP_RESOURCE_TBL_KEY);
 365        if (!dev_mutex)
 366                return -ENOMEM;
 367
 368        if (nfp_cpp_mutex_lock(dev_mutex)) {
 369                nfp_err(cpp, "Error: failed to claim resource table mutex\n");
 370                nfp_cpp_mutex_free(dev_mutex);
 371                return -EINVAL;
 372        }
 373
 374        /* Resource 0 is the dev_mutex, start from 1 */
 375        for (i = 1; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
 376                u64 addr = NFP_RESOURCE_TBL_BASE +
 377                        sizeof(struct nfp_resource_entry) * i;
 378
 379                err = nfp_cpp_mutex_reclaim(cpp, NFP_RESOURCE_TBL_TARGET, addr);
 380                if (err < 0) {
 381                        nfp_err(cpp,
 382                                "Error: failed to reclaim resource %d mutex\n",
 383                                i);
 384                        goto err_unlock;
 385                }
 386                if (err)
 387                        nfp_warn(cpp, "Warning: busted resource %d mutex\n", i);
 388        }
 389
 390        err = 0;
 391err_unlock:
 392        nfp_cpp_mutex_unlock(dev_mutex);
 393        nfp_cpp_mutex_free(dev_mutex);
 394
 395        return err;
 396}
 397