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
70struct nfp_resource_entry {
71 struct nfp_resource_entry_mutex {
72 u32 owner;
73 u32 key;
74 } mutex;
75 struct nfp_resource_entry_region {
76 u8 name[NFP_RESOURCE_ENTRY_NAME_SZ];
77 u8 reserved[5];
78 u8 cpp_action;
79 u8 cpp_token;
80 u8 cpp_target;
81 u32 page_offset;
82 u32 page_size;
83 } region;
84};
85
86#define NFP_RESOURCE_TBL_SIZE 4096
87#define NFP_RESOURCE_TBL_ENTRIES (NFP_RESOURCE_TBL_SIZE / \
88 sizeof(struct nfp_resource_entry))
89
90struct nfp_resource {
91 char name[NFP_RESOURCE_ENTRY_NAME_SZ + 1];
92 u32 cpp_id;
93 u64 addr;
94 u64 size;
95 struct nfp_cpp_mutex *mutex;
96};
97
98static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
99{
100 char name_pad[NFP_RESOURCE_ENTRY_NAME_SZ] = {};
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 strncpy(name_pad, res->name, sizeof(name_pad));
108
109
110 if (!memcmp(name_pad, NFP_RESOURCE_TBL_NAME "\0\0\0\0\0\0\0\0", 8)) {
111 nfp_err(cpp, "Grabbing device lock not supported\n");
112 return -EOPNOTSUPP;
113 }
114 key = crc32_posix(name_pad, sizeof(name_pad));
115
116 for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
117 u64 addr = NFP_RESOURCE_TBL_BASE +
118 sizeof(struct nfp_resource_entry) * i;
119
120 ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry));
121 if (ret != sizeof(entry))
122 return -EIO;
123
124 if (entry.mutex.key != key)
125 continue;
126
127
128 res->mutex =
129 nfp_cpp_mutex_alloc(cpp,
130 NFP_RESOURCE_TBL_TARGET, addr, key);
131 res->cpp_id = NFP_CPP_ID(entry.region.cpp_target,
132 entry.region.cpp_action,
133 entry.region.cpp_token);
134 res->addr = (u64)entry.region.page_offset << 8;
135 res->size = (u64)entry.region.page_size << 8;
136
137 return 0;
138 }
139
140 return -ENOENT;
141}
142
143static int
144nfp_resource_try_acquire(struct nfp_cpp *cpp, struct nfp_resource *res,
145 struct nfp_cpp_mutex *dev_mutex)
146{
147 int err;
148
149 if (nfp_cpp_mutex_lock(dev_mutex))
150 return -EINVAL;
151
152 err = nfp_cpp_resource_find(cpp, res);
153 if (err)
154 goto err_unlock_dev;
155
156 err = nfp_cpp_mutex_trylock(res->mutex);
157 if (err)
158 goto err_res_mutex_free;
159
160 nfp_cpp_mutex_unlock(dev_mutex);
161
162 return 0;
163
164err_res_mutex_free:
165 nfp_cpp_mutex_free(res->mutex);
166err_unlock_dev:
167 nfp_cpp_mutex_unlock(dev_mutex);
168
169 return err;
170}
171
172
173
174
175
176
177
178
179
180
181struct nfp_resource *
182nfp_resource_acquire(struct nfp_cpp *cpp, const char *name)
183{
184 unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
185 unsigned long err_at = jiffies + NFP_MUTEX_WAIT_ERROR * HZ;
186 struct nfp_cpp_mutex *dev_mutex;
187 struct nfp_resource *res;
188 int err;
189
190 res = kzalloc(sizeof(*res), GFP_KERNEL);
191 if (!res)
192 return ERR_PTR(-ENOMEM);
193
194 strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ);
195
196 dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
197 NFP_RESOURCE_TBL_BASE,
198 NFP_RESOURCE_TBL_KEY);
199 if (!dev_mutex) {
200 kfree(res);
201 return ERR_PTR(-ENOMEM);
202 }
203
204 for (;;) {
205 err = nfp_resource_try_acquire(cpp, res, dev_mutex);
206 if (!err)
207 break;
208 if (err != -EBUSY)
209 goto err_free;
210
211 err = msleep_interruptible(1);
212 if (err != 0) {
213 err = -ERESTARTSYS;
214 goto err_free;
215 }
216
217 if (time_is_before_eq_jiffies(warn_at)) {
218 warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
219 nfp_warn(cpp, "Warning: waiting for NFP resource %s\n",
220 name);
221 }
222 if (time_is_before_eq_jiffies(err_at)) {
223 nfp_err(cpp, "Error: resource %s timed out\n", name);
224 err = -EBUSY;
225 goto err_free;
226 }
227 }
228
229 nfp_cpp_mutex_free(dev_mutex);
230
231 return res;
232
233err_free:
234 nfp_cpp_mutex_free(dev_mutex);
235 kfree(res);
236 return ERR_PTR(err);
237}
238
239
240
241
242
243
244
245void nfp_resource_release(struct nfp_resource *res)
246{
247 nfp_cpp_mutex_unlock(res->mutex);
248 nfp_cpp_mutex_free(res->mutex);
249 kfree(res);
250}
251
252
253
254
255
256
257
258
259
260
261
262
263int nfp_resource_wait(struct nfp_cpp *cpp, const char *name, unsigned int secs)
264{
265 unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
266 unsigned long err_at = jiffies + secs * HZ;
267 struct nfp_resource *res;
268
269 while (true) {
270 res = nfp_resource_acquire(cpp, name);
271 if (!IS_ERR(res)) {
272 nfp_resource_release(res);
273 return 0;
274 }
275
276 if (PTR_ERR(res) != -ENOENT) {
277 nfp_err(cpp, "error waiting for resource %s: %ld\n",
278 name, PTR_ERR(res));
279 return PTR_ERR(res);
280 }
281 if (time_is_before_eq_jiffies(err_at)) {
282 nfp_err(cpp, "timeout waiting for resource %s\n", name);
283 return -ETIMEDOUT;
284 }
285 if (time_is_before_eq_jiffies(warn_at)) {
286 warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
287 nfp_info(cpp, "waiting for NFP resource %s\n", name);
288 }
289 if (msleep_interruptible(10)) {
290 nfp_err(cpp, "wait for resource %s interrupted\n",
291 name);
292 return -ERESTARTSYS;
293 }
294 }
295}
296
297
298
299
300
301
302
303u32 nfp_resource_cpp_id(struct nfp_resource *res)
304{
305 return res->cpp_id;
306}
307
308
309
310
311
312
313
314const char *nfp_resource_name(struct nfp_resource *res)
315{
316 return res->name;
317}
318
319
320
321
322
323
324
325u64 nfp_resource_address(struct nfp_resource *res)
326{
327 return res->addr;
328}
329
330
331
332
333
334
335
336u64 nfp_resource_size(struct nfp_resource *res)
337{
338 return res->size;
339}
340