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

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

DEFINITIONS

This source file includes following definitions.
  1. nfp_cpp_resource_find
  2. nfp_resource_try_acquire
  3. nfp_resource_acquire
  4. nfp_resource_release
  5. nfp_resource_wait
  6. nfp_resource_cpp_id
  7. nfp_resource_name
  8. nfp_resource_address
  9. nfp_resource_size
  10. nfp_resource_table_init

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

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