0001
0002
0003
0004
0005
0006
0007
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
0022 #define NFP_RESOURCE_TBL_NAME "nfp.res"
0023 #define NFP_RESOURCE_TBL_KEY 0x00000000
0024
0025 #define NFP_RESOURCE_ENTRY_NAME_SZ 8
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
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);
0076
0077
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
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
0142
0143
0144
0145
0146
0147
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
0209
0210
0211
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
0222
0223
0224
0225
0226
0227
0228
0229
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
0267
0268
0269
0270
0271 u32 nfp_resource_cpp_id(struct nfp_resource *res)
0272 {
0273 return res->cpp_id;
0274 }
0275
0276
0277
0278
0279
0280
0281
0282 const char *nfp_resource_name(struct nfp_resource *res)
0283 {
0284 return res->name;
0285 }
0286
0287
0288
0289
0290
0291
0292
0293 u64 nfp_resource_address(struct nfp_resource *res)
0294 {
0295 return res->addr;
0296 }
0297
0298
0299
0300
0301
0302
0303
0304 u64 nfp_resource_size(struct nfp_resource *res)
0305 {
0306 return res->size;
0307 }
0308
0309
0310
0311
0312
0313
0314
0315
0316
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
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 }