1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
52#define NFP_RESOURCE_TBL_NAME "nfp.res"
53#define NFP_RESOURCE_TBL_KEY 0x00000000
54
55#define NFP_RESOURCE_ENTRY_NAME_SZ 8
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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);
106
107
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
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
172
173
174
175
176
177
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
239
240
241
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
252
253
254
255
256
257
258
259
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
297
298
299
300
301u32 nfp_resource_cpp_id(struct nfp_resource *res)
302{
303 return res->cpp_id;
304}
305
306
307
308
309
310
311
312const char *nfp_resource_name(struct nfp_resource *res)
313{
314 return res->name;
315}
316
317
318
319
320
321
322
323u64 nfp_resource_address(struct nfp_resource *res)
324{
325 return res->addr;
326}
327
328
329
330
331
332
333
334u64 nfp_resource_size(struct nfp_resource *res)
335{
336 return res->size;
337}
338
339
340
341
342
343
344
345
346
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
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