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_ENTRY_NAME_SZ 8
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63struct nfp_resource_entry {
64 struct nfp_resource_entry_mutex {
65 u32 owner;
66 u32 key;
67 } mutex;
68 struct nfp_resource_entry_region {
69 u8 name[NFP_RESOURCE_ENTRY_NAME_SZ];
70 u8 reserved[5];
71 u8 cpp_action;
72 u8 cpp_token;
73 u8 cpp_target;
74 u32 page_offset;
75 u32 page_size;
76 } region;
77};
78
79#define NFP_RESOURCE_TBL_SIZE 4096
80#define NFP_RESOURCE_TBL_ENTRIES (NFP_RESOURCE_TBL_SIZE / \
81 sizeof(struct nfp_resource_entry))
82
83struct nfp_resource {
84 char name[NFP_RESOURCE_ENTRY_NAME_SZ + 1];
85 u32 cpp_id;
86 u64 addr;
87 u64 size;
88 struct nfp_cpp_mutex *mutex;
89};
90
91static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
92{
93 char name_pad[NFP_RESOURCE_ENTRY_NAME_SZ] = {};
94 struct nfp_resource_entry entry;
95 u32 cpp_id, key;
96 int ret, i;
97
98 cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0);
99
100 strncpy(name_pad, res->name, sizeof(name_pad));
101
102
103 key = NFP_RESOURCE_TBL_KEY;
104 if (memcmp(name_pad, NFP_RESOURCE_TBL_NAME "\0\0\0\0\0\0\0\0", 8))
105 key = crc32_posix(name_pad, sizeof(name_pad));
106
107 for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
108 u64 addr = NFP_RESOURCE_TBL_BASE +
109 sizeof(struct nfp_resource_entry) * i;
110
111 ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry));
112 if (ret != sizeof(entry))
113 return -EIO;
114
115 if (entry.mutex.key != key)
116 continue;
117
118
119 res->mutex =
120 nfp_cpp_mutex_alloc(cpp,
121 NFP_RESOURCE_TBL_TARGET, addr, key);
122 res->cpp_id = NFP_CPP_ID(entry.region.cpp_target,
123 entry.region.cpp_action,
124 entry.region.cpp_token);
125 res->addr = (u64)entry.region.page_offset << 8;
126 res->size = (u64)entry.region.page_size << 8;
127
128 return 0;
129 }
130
131 return -ENOENT;
132}
133
134static int
135nfp_resource_try_acquire(struct nfp_cpp *cpp, struct nfp_resource *res,
136 struct nfp_cpp_mutex *dev_mutex)
137{
138 int err;
139
140 if (nfp_cpp_mutex_lock(dev_mutex))
141 return -EINVAL;
142
143 err = nfp_cpp_resource_find(cpp, res);
144 if (err)
145 goto err_unlock_dev;
146
147 err = nfp_cpp_mutex_trylock(res->mutex);
148 if (err)
149 goto err_res_mutex_free;
150
151 nfp_cpp_mutex_unlock(dev_mutex);
152
153 return 0;
154
155err_res_mutex_free:
156 nfp_cpp_mutex_free(res->mutex);
157err_unlock_dev:
158 nfp_cpp_mutex_unlock(dev_mutex);
159
160 return err;
161}
162
163
164
165
166
167
168
169
170
171
172struct nfp_resource *
173nfp_resource_acquire(struct nfp_cpp *cpp, const char *name)
174{
175 unsigned long warn_at = jiffies + 15 * HZ;
176 struct nfp_cpp_mutex *dev_mutex;
177 struct nfp_resource *res;
178 int err;
179
180 res = kzalloc(sizeof(*res), GFP_KERNEL);
181 if (!res)
182 return ERR_PTR(-ENOMEM);
183
184 strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ);
185
186 dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
187 NFP_RESOURCE_TBL_BASE,
188 NFP_RESOURCE_TBL_KEY);
189 if (!dev_mutex) {
190 kfree(res);
191 return ERR_PTR(-ENOMEM);
192 }
193
194 for (;;) {
195 err = nfp_resource_try_acquire(cpp, res, dev_mutex);
196 if (!err)
197 break;
198 if (err != -EBUSY)
199 goto err_free;
200
201 err = msleep_interruptible(1);
202 if (err != 0) {
203 err = -ERESTARTSYS;
204 goto err_free;
205 }
206
207 if (time_is_before_eq_jiffies(warn_at)) {
208 warn_at = jiffies + 60 * HZ;
209 nfp_warn(cpp, "Warning: waiting for NFP resource %s\n",
210 name);
211 }
212 }
213
214 nfp_cpp_mutex_free(dev_mutex);
215
216 return res;
217
218err_free:
219 nfp_cpp_mutex_free(dev_mutex);
220 kfree(res);
221 return ERR_PTR(err);
222}
223
224
225
226
227
228
229
230void nfp_resource_release(struct nfp_resource *res)
231{
232 nfp_cpp_mutex_unlock(res->mutex);
233 nfp_cpp_mutex_free(res->mutex);
234 kfree(res);
235}
236
237
238
239
240
241
242
243u32 nfp_resource_cpp_id(struct nfp_resource *res)
244{
245 return res->cpp_id;
246}
247
248
249
250
251
252
253
254const char *nfp_resource_name(struct nfp_resource *res)
255{
256 return res->name;
257}
258
259
260
261
262
263
264
265u64 nfp_resource_address(struct nfp_resource *res)
266{
267 return res->addr;
268}
269
270
271
272
273
274
275
276u64 nfp_resource_size(struct nfp_resource *res)
277{
278 return res->size;
279}
280