0001
0002
0003
0004 #include <linux/delay.h>
0005 #include <linux/device.h>
0006 #include <linux/jiffies.h>
0007 #include <linux/types.h>
0008 #include <linux/slab.h>
0009 #include <linux/wait.h>
0010
0011 #include "nfp_cpp.h"
0012 #include "nfp6000/nfp6000.h"
0013
0014 struct nfp_cpp_mutex {
0015 struct nfp_cpp *cpp;
0016 int target;
0017 u16 depth;
0018 unsigned long long address;
0019 u32 key;
0020 };
0021
0022 static u32 nfp_mutex_locked(u16 interface)
0023 {
0024 return (u32)interface << 16 | 0x000f;
0025 }
0026
0027 static u32 nfp_mutex_unlocked(u16 interface)
0028 {
0029 return (u32)interface << 16 | 0x0000;
0030 }
0031
0032 static u32 nfp_mutex_owner(u32 val)
0033 {
0034 return val >> 16;
0035 }
0036
0037 static bool nfp_mutex_is_locked(u32 val)
0038 {
0039 return (val & 0xffff) == 0x000f;
0040 }
0041
0042 static bool nfp_mutex_is_unlocked(u32 val)
0043 {
0044 return (val & 0xffff) == 0000;
0045 }
0046
0047
0048 #define NFP_MUTEX_DEPTH_MAX 0xffff
0049
0050 static int
0051 nfp_cpp_mutex_validate(u16 interface, int *target, unsigned long long address)
0052 {
0053
0054 if (NFP_CPP_INTERFACE_TYPE_of(interface) ==
0055 NFP_CPP_INTERFACE_TYPE_INVALID)
0056 return -EINVAL;
0057
0058
0059 if (address & 7)
0060 return -EINVAL;
0061
0062 if (*target != NFP_CPP_TARGET_MU)
0063 return -EINVAL;
0064
0065 return 0;
0066 }
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086 int nfp_cpp_mutex_init(struct nfp_cpp *cpp,
0087 int target, unsigned long long address, u32 key)
0088 {
0089 const u32 muw = NFP_CPP_ID(target, 4, 0);
0090 u16 interface = nfp_cpp_interface(cpp);
0091 int err;
0092
0093 err = nfp_cpp_mutex_validate(interface, &target, address);
0094 if (err)
0095 return err;
0096
0097 err = nfp_cpp_writel(cpp, muw, address + 4, key);
0098 if (err)
0099 return err;
0100
0101 err = nfp_cpp_writel(cpp, muw, address, nfp_mutex_locked(interface));
0102 if (err)
0103 return err;
0104
0105 return 0;
0106 }
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123 struct nfp_cpp_mutex *nfp_cpp_mutex_alloc(struct nfp_cpp *cpp, int target,
0124 unsigned long long address, u32 key)
0125 {
0126 const u32 mur = NFP_CPP_ID(target, 3, 0);
0127 u16 interface = nfp_cpp_interface(cpp);
0128 struct nfp_cpp_mutex *mutex;
0129 int err;
0130 u32 tmp;
0131
0132 err = nfp_cpp_mutex_validate(interface, &target, address);
0133 if (err)
0134 return NULL;
0135
0136 err = nfp_cpp_readl(cpp, mur, address + 4, &tmp);
0137 if (err < 0)
0138 return NULL;
0139
0140 if (tmp != key)
0141 return NULL;
0142
0143 mutex = kzalloc(sizeof(*mutex), GFP_KERNEL);
0144 if (!mutex)
0145 return NULL;
0146
0147 mutex->cpp = cpp;
0148 mutex->target = target;
0149 mutex->address = address;
0150 mutex->key = key;
0151 mutex->depth = 0;
0152
0153 return mutex;
0154 }
0155
0156
0157
0158
0159
0160 void nfp_cpp_mutex_free(struct nfp_cpp_mutex *mutex)
0161 {
0162 kfree(mutex);
0163 }
0164
0165
0166
0167
0168
0169
0170
0171 int nfp_cpp_mutex_lock(struct nfp_cpp_mutex *mutex)
0172 {
0173 unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
0174 unsigned long err_at = jiffies + NFP_MUTEX_WAIT_ERROR * HZ;
0175 unsigned int timeout_ms = 1;
0176 int err;
0177
0178
0179
0180
0181
0182
0183 for (;;) {
0184 err = nfp_cpp_mutex_trylock(mutex);
0185 if (err != -EBUSY)
0186 break;
0187
0188 err = msleep_interruptible(timeout_ms);
0189 if (err != 0) {
0190 nfp_info(mutex->cpp,
0191 "interrupted waiting for NFP mutex\n");
0192 return -ERESTARTSYS;
0193 }
0194
0195 if (time_is_before_eq_jiffies(warn_at)) {
0196 warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
0197 nfp_warn(mutex->cpp,
0198 "Warning: waiting for NFP mutex [depth:%hd target:%d addr:%llx key:%08x]\n",
0199 mutex->depth,
0200 mutex->target, mutex->address, mutex->key);
0201 }
0202 if (time_is_before_eq_jiffies(err_at)) {
0203 nfp_err(mutex->cpp, "Error: mutex wait timed out\n");
0204 return -EBUSY;
0205 }
0206 }
0207
0208 return err;
0209 }
0210
0211
0212
0213
0214
0215
0216
0217 int nfp_cpp_mutex_unlock(struct nfp_cpp_mutex *mutex)
0218 {
0219 const u32 muw = NFP_CPP_ID(mutex->target, 4, 0);
0220 const u32 mur = NFP_CPP_ID(mutex->target, 3, 0);
0221 struct nfp_cpp *cpp = mutex->cpp;
0222 u32 key, value;
0223 u16 interface;
0224 int err;
0225
0226 interface = nfp_cpp_interface(cpp);
0227
0228 if (mutex->depth > 1) {
0229 mutex->depth--;
0230 return 0;
0231 }
0232
0233 err = nfp_cpp_readl(mutex->cpp, mur, mutex->address + 4, &key);
0234 if (err < 0)
0235 return err;
0236
0237 if (key != mutex->key)
0238 return -EPERM;
0239
0240 err = nfp_cpp_readl(mutex->cpp, mur, mutex->address, &value);
0241 if (err < 0)
0242 return err;
0243
0244 if (value != nfp_mutex_locked(interface))
0245 return -EACCES;
0246
0247 err = nfp_cpp_writel(cpp, muw, mutex->address,
0248 nfp_mutex_unlocked(interface));
0249 if (err < 0)
0250 return err;
0251
0252 mutex->depth = 0;
0253 return 0;
0254 }
0255
0256
0257
0258
0259
0260
0261
0262 int nfp_cpp_mutex_trylock(struct nfp_cpp_mutex *mutex)
0263 {
0264 const u32 muw = NFP_CPP_ID(mutex->target, 4, 0);
0265 const u32 mus = NFP_CPP_ID(mutex->target, 5, 3);
0266 const u32 mur = NFP_CPP_ID(mutex->target, 3, 0);
0267 struct nfp_cpp *cpp = mutex->cpp;
0268 u32 key, value, tmp;
0269 int err;
0270
0271 if (mutex->depth > 0) {
0272 if (mutex->depth == NFP_MUTEX_DEPTH_MAX)
0273 return -E2BIG;
0274 mutex->depth++;
0275 return 0;
0276 }
0277
0278
0279 err = nfp_cpp_readl(cpp, mur, mutex->address + 4, &key);
0280 if (err < 0)
0281 return err;
0282
0283 if (key != mutex->key)
0284 return -EPERM;
0285
0286
0287
0288
0289
0290 value = nfp_mutex_locked(nfp_cpp_interface(cpp));
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304 err = nfp_cpp_readl(cpp, mus, mutex->address, &tmp);
0305 if (err < 0)
0306 return err;
0307
0308
0309 if (nfp_mutex_is_unlocked(tmp)) {
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319 err = nfp_cpp_writel(cpp, muw, mutex->address, value);
0320 if (err < 0)
0321 return err;
0322
0323 mutex->depth = 1;
0324 return 0;
0325 }
0326
0327 return nfp_mutex_is_locked(tmp) ? -EBUSY : -EINVAL;
0328 }
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341 int nfp_cpp_mutex_reclaim(struct nfp_cpp *cpp, int target,
0342 unsigned long long address)
0343 {
0344 const u32 mur = NFP_CPP_ID(target, 3, 0);
0345 const u32 muw = NFP_CPP_ID(target, 4, 0);
0346 u16 interface = nfp_cpp_interface(cpp);
0347 int err;
0348 u32 tmp;
0349
0350 err = nfp_cpp_mutex_validate(interface, &target, address);
0351 if (err)
0352 return err;
0353
0354
0355 err = nfp_cpp_readl(cpp, mur, address, &tmp);
0356 if (err < 0)
0357 return err;
0358
0359 if (nfp_mutex_is_unlocked(tmp) || nfp_mutex_owner(tmp) != interface)
0360 return 0;
0361
0362
0363 err = nfp_cpp_writel(cpp, muw, address, nfp_mutex_unlocked(interface));
0364 if (err < 0)
0365 return err;
0366
0367 return 1;
0368 }