Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /* Copyright (C) 2015-2018 Netronome Systems, Inc. */
0003 
0004 /*
0005  * nfp_resource.c
0006  * Author: Jakub Kicinski <jakub.kicinski@netronome.com>
0007  *         Jason McMullan <jason.mcmullan@netronome.com>
0008  */
0009 #include <linux/delay.h>
0010 #include <linux/kernel.h>
0011 #include <linux/slab.h>
0012 
0013 #include "crc32.h"
0014 #include "nfp.h"
0015 #include "nfp_cpp.h"
0016 #include "nfp6000/nfp6000.h"
0017 
0018 #define NFP_RESOURCE_TBL_TARGET     NFP_CPP_TARGET_MU
0019 #define NFP_RESOURCE_TBL_BASE       0x8100000000ULL
0020 
0021 /* NFP Resource Table self-identifier */
0022 #define NFP_RESOURCE_TBL_NAME       "nfp.res"
0023 #define NFP_RESOURCE_TBL_KEY        0x00000000 /* Special key for entry 0 */
0024 
0025 #define NFP_RESOURCE_ENTRY_NAME_SZ  8
0026 
0027 /**
0028  * struct nfp_resource_entry - Resource table entry
0029  * @mutex:  NFP CPP Lock
0030  * @mutex.owner:    NFP CPP Lock, interface owner
0031  * @mutex.key:      NFP CPP Lock, posix_crc32(name, 8)
0032  * @region: Memory region descriptor
0033  * @region.name:    ASCII, zero padded name
0034  * @region.reserved:    padding
0035  * @region.cpp_action:  CPP Action
0036  * @region.cpp_token:   CPP Token
0037  * @region.cpp_target:  CPP Target ID
0038  * @region.page_offset: 256-byte page offset into target's CPP address
0039  * @region.page_size:   size, in 256-byte pages
0040  */
0041 struct nfp_resource_entry {
0042     struct nfp_resource_entry_mutex {
0043         u32 owner;
0044         u32 key;
0045     } mutex;
0046     struct nfp_resource_entry_region {
0047         u8  name[NFP_RESOURCE_ENTRY_NAME_SZ];
0048         u8  reserved[5];
0049         u8  cpp_action;
0050         u8  cpp_token;
0051         u8  cpp_target;
0052         u32 page_offset;
0053         u32 page_size;
0054     } region;
0055 };
0056 
0057 #define NFP_RESOURCE_TBL_SIZE       4096
0058 #define NFP_RESOURCE_TBL_ENTRIES    (NFP_RESOURCE_TBL_SIZE /    \
0059                      sizeof(struct nfp_resource_entry))
0060 
0061 struct nfp_resource {
0062     char name[NFP_RESOURCE_ENTRY_NAME_SZ + 1];
0063     u32 cpp_id;
0064     u64 addr;
0065     u64 size;
0066     struct nfp_cpp_mutex *mutex;
0067 };
0068 
0069 static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
0070 {
0071     struct nfp_resource_entry entry;
0072     u32 cpp_id, key;
0073     int ret, i;
0074 
0075     cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0);  /* Atomic read */
0076 
0077     /* Search for a matching entry */
0078     if (!strcmp(res->name, NFP_RESOURCE_TBL_NAME)) {
0079         nfp_err(cpp, "Grabbing device lock not supported\n");
0080         return -EOPNOTSUPP;
0081     }
0082     key = crc32_posix(res->name, NFP_RESOURCE_ENTRY_NAME_SZ);
0083 
0084     for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
0085         u64 addr = NFP_RESOURCE_TBL_BASE +
0086             sizeof(struct nfp_resource_entry) * i;
0087 
0088         ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry));
0089         if (ret != sizeof(entry))
0090             return -EIO;
0091 
0092         if (entry.mutex.key != key)
0093             continue;
0094 
0095         /* Found key! */
0096         res->mutex =
0097             nfp_cpp_mutex_alloc(cpp,
0098                         NFP_RESOURCE_TBL_TARGET, addr, key);
0099         res->cpp_id = NFP_CPP_ID(entry.region.cpp_target,
0100                      entry.region.cpp_action,
0101                      entry.region.cpp_token);
0102         res->addr = (u64)entry.region.page_offset << 8;
0103         res->size = (u64)entry.region.page_size << 8;
0104 
0105         return 0;
0106     }
0107 
0108     return -ENOENT;
0109 }
0110 
0111 static int
0112 nfp_resource_try_acquire(struct nfp_cpp *cpp, struct nfp_resource *res,
0113              struct nfp_cpp_mutex *dev_mutex)
0114 {
0115     int err;
0116 
0117     if (nfp_cpp_mutex_lock(dev_mutex))
0118         return -EINVAL;
0119 
0120     err = nfp_cpp_resource_find(cpp, res);
0121     if (err)
0122         goto err_unlock_dev;
0123 
0124     err = nfp_cpp_mutex_trylock(res->mutex);
0125     if (err)
0126         goto err_res_mutex_free;
0127 
0128     nfp_cpp_mutex_unlock(dev_mutex);
0129 
0130     return 0;
0131 
0132 err_res_mutex_free:
0133     nfp_cpp_mutex_free(res->mutex);
0134 err_unlock_dev:
0135     nfp_cpp_mutex_unlock(dev_mutex);
0136 
0137     return err;
0138 }
0139 
0140 /**
0141  * nfp_resource_acquire() - Acquire a resource handle
0142  * @cpp:    NFP CPP handle
0143  * @name:   Name of the resource
0144  *
0145  * NOTE: This function locks the acquired resource
0146  *
0147  * Return: NFP Resource handle, or ERR_PTR()
0148  */
0149 struct nfp_resource *
0150 nfp_resource_acquire(struct nfp_cpp *cpp, const char *name)
0151 {
0152     unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
0153     unsigned long err_at = jiffies + NFP_MUTEX_WAIT_ERROR * HZ;
0154     struct nfp_cpp_mutex *dev_mutex;
0155     struct nfp_resource *res;
0156     int err;
0157 
0158     res = kzalloc(sizeof(*res), GFP_KERNEL);
0159     if (!res)
0160         return ERR_PTR(-ENOMEM);
0161 
0162     strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ);
0163 
0164     dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
0165                     NFP_RESOURCE_TBL_BASE,
0166                     NFP_RESOURCE_TBL_KEY);
0167     if (!dev_mutex) {
0168         kfree(res);
0169         return ERR_PTR(-ENOMEM);
0170     }
0171 
0172     for (;;) {
0173         err = nfp_resource_try_acquire(cpp, res, dev_mutex);
0174         if (!err)
0175             break;
0176         if (err != -EBUSY)
0177             goto err_free;
0178 
0179         err = msleep_interruptible(1);
0180         if (err != 0) {
0181             err = -ERESTARTSYS;
0182             goto err_free;
0183         }
0184 
0185         if (time_is_before_eq_jiffies(warn_at)) {
0186             warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
0187             nfp_warn(cpp, "Warning: waiting for NFP resource %s\n",
0188                  name);
0189         }
0190         if (time_is_before_eq_jiffies(err_at)) {
0191             nfp_err(cpp, "Error: resource %s timed out\n", name);
0192             err = -EBUSY;
0193             goto err_free;
0194         }
0195     }
0196 
0197     nfp_cpp_mutex_free(dev_mutex);
0198 
0199     return res;
0200 
0201 err_free:
0202     nfp_cpp_mutex_free(dev_mutex);
0203     kfree(res);
0204     return ERR_PTR(err);
0205 }
0206 
0207 /**
0208  * nfp_resource_release() - Release a NFP Resource handle
0209  * @res:    NFP Resource handle
0210  *
0211  * NOTE: This function implictly unlocks the resource handle
0212  */
0213 void nfp_resource_release(struct nfp_resource *res)
0214 {
0215     nfp_cpp_mutex_unlock(res->mutex);
0216     nfp_cpp_mutex_free(res->mutex);
0217     kfree(res);
0218 }
0219 
0220 /**
0221  * nfp_resource_wait() - Wait for resource to appear
0222  * @cpp:    NFP CPP handle
0223  * @name:   Name of the resource
0224  * @secs:   Number of seconds to wait
0225  *
0226  * Wait for resource to appear in the resource table, grab and release
0227  * its lock.  The wait is jiffies-based, don't expect fine granularity.
0228  *
0229  * Return: 0 on success, errno otherwise.
0230  */
0231 int nfp_resource_wait(struct nfp_cpp *cpp, const char *name, unsigned int secs)
0232 {
0233     unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
0234     unsigned long err_at = jiffies + secs * HZ;
0235     struct nfp_resource *res;
0236 
0237     while (true) {
0238         res = nfp_resource_acquire(cpp, name);
0239         if (!IS_ERR(res)) {
0240             nfp_resource_release(res);
0241             return 0;
0242         }
0243 
0244         if (PTR_ERR(res) != -ENOENT) {
0245             nfp_err(cpp, "error waiting for resource %s: %ld\n",
0246                 name, PTR_ERR(res));
0247             return PTR_ERR(res);
0248         }
0249         if (time_is_before_eq_jiffies(err_at)) {
0250             nfp_err(cpp, "timeout waiting for resource %s\n", name);
0251             return -ETIMEDOUT;
0252         }
0253         if (time_is_before_eq_jiffies(warn_at)) {
0254             warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
0255             nfp_info(cpp, "waiting for NFP resource %s\n", name);
0256         }
0257         if (msleep_interruptible(10)) {
0258             nfp_err(cpp, "wait for resource %s interrupted\n",
0259                 name);
0260             return -ERESTARTSYS;
0261         }
0262     }
0263 }
0264 
0265 /**
0266  * nfp_resource_cpp_id() - Return the cpp_id of a resource handle
0267  * @res:    NFP Resource handle
0268  *
0269  * Return: NFP CPP ID
0270  */
0271 u32 nfp_resource_cpp_id(struct nfp_resource *res)
0272 {
0273     return res->cpp_id;
0274 }
0275 
0276 /**
0277  * nfp_resource_name() - Return the name of a resource handle
0278  * @res:    NFP Resource handle
0279  *
0280  * Return: const char pointer to the name of the resource
0281  */
0282 const char *nfp_resource_name(struct nfp_resource *res)
0283 {
0284     return res->name;
0285 }
0286 
0287 /**
0288  * nfp_resource_address() - Return the address of a resource handle
0289  * @res:    NFP Resource handle
0290  *
0291  * Return: Address of the resource
0292  */
0293 u64 nfp_resource_address(struct nfp_resource *res)
0294 {
0295     return res->addr;
0296 }
0297 
0298 /**
0299  * nfp_resource_size() - Return the size in bytes of a resource handle
0300  * @res:    NFP Resource handle
0301  *
0302  * Return: Size of the resource in bytes
0303  */
0304 u64 nfp_resource_size(struct nfp_resource *res)
0305 {
0306     return res->size;
0307 }
0308 
0309 /**
0310  * nfp_resource_table_init() - Run initial checks on the resource table
0311  * @cpp:    NFP CPP handle
0312  *
0313  * Start-of-day init procedure for resource table.  Must be called before
0314  * any local resource table users may exist.
0315  *
0316  * Return: 0 on success, -errno on failure
0317  */
0318 int nfp_resource_table_init(struct nfp_cpp *cpp)
0319 {
0320     struct nfp_cpp_mutex *dev_mutex;
0321     int i, err;
0322 
0323     err = nfp_cpp_mutex_reclaim(cpp, NFP_RESOURCE_TBL_TARGET,
0324                     NFP_RESOURCE_TBL_BASE);
0325     if (err < 0) {
0326         nfp_err(cpp, "Error: failed to reclaim resource table mutex\n");
0327         return err;
0328     }
0329     if (err)
0330         nfp_warn(cpp, "Warning: busted main resource table mutex\n");
0331 
0332     dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
0333                     NFP_RESOURCE_TBL_BASE,
0334                     NFP_RESOURCE_TBL_KEY);
0335     if (!dev_mutex)
0336         return -ENOMEM;
0337 
0338     if (nfp_cpp_mutex_lock(dev_mutex)) {
0339         nfp_err(cpp, "Error: failed to claim resource table mutex\n");
0340         nfp_cpp_mutex_free(dev_mutex);
0341         return -EINVAL;
0342     }
0343 
0344     /* Resource 0 is the dev_mutex, start from 1 */
0345     for (i = 1; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
0346         u64 addr = NFP_RESOURCE_TBL_BASE +
0347             sizeof(struct nfp_resource_entry) * i;
0348 
0349         err = nfp_cpp_mutex_reclaim(cpp, NFP_RESOURCE_TBL_TARGET, addr);
0350         if (err < 0) {
0351             nfp_err(cpp,
0352                 "Error: failed to reclaim resource %d mutex\n",
0353                 i);
0354             goto err_unlock;
0355         }
0356         if (err)
0357             nfp_warn(cpp, "Warning: busted resource %d mutex\n", i);
0358     }
0359 
0360     err = 0;
0361 err_unlock:
0362     nfp_cpp_mutex_unlock(dev_mutex);
0363     nfp_cpp_mutex_free(dev_mutex);
0364 
0365     return err;
0366 }