e1df2b2e1b643eeae141fbc5b306608ce6f78556
[dpdk.git] / drivers / net / nfp / nfpcore / nfp_resource.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Netronome Systems, Inc.
3  * All rights reserved.
4  */
5
6 #include <stdio.h>
7 #include <time.h>
8 #include <endian.h>
9
10 #include "nfp_cpp.h"
11 #include "nfp6000/nfp6000.h"
12 #include "nfp_resource.h"
13 #include "nfp_crc.h"
14
15 #define NFP_RESOURCE_TBL_TARGET         NFP_CPP_TARGET_MU
16 #define NFP_RESOURCE_TBL_BASE           0x8100000000ULL
17
18 /* NFP Resource Table self-identifier */
19 #define NFP_RESOURCE_TBL_NAME           "nfp.res"
20 #define NFP_RESOURCE_TBL_KEY            0x00000000 /* Special key for entry 0 */
21
22 #define NFP_RESOURCE_ENTRY_NAME_SZ      8
23
24 /*
25  * struct nfp_resource_entry - Resource table entry
26  * @owner:              NFP CPP Lock, interface owner
27  * @key:                NFP CPP Lock, posix_crc32(name, 8)
28  * @region:             Memory region descriptor
29  * @name:               ASCII, zero padded name
30  * @reserved
31  * @cpp_action:         CPP Action
32  * @cpp_token:          CPP Token
33  * @cpp_target:         CPP Target ID
34  * @page_offset:        256-byte page offset into target's CPP address
35  * @page_size:          size, in 256-byte pages
36  */
37 struct nfp_resource_entry {
38         struct nfp_resource_entry_mutex {
39                 uint32_t owner;
40                 uint32_t key;
41         } mutex;
42         struct nfp_resource_entry_region {
43                 uint8_t  name[NFP_RESOURCE_ENTRY_NAME_SZ];
44                 uint8_t  reserved[5];
45                 uint8_t  cpp_action;
46                 uint8_t  cpp_token;
47                 uint8_t  cpp_target;
48                 uint32_t page_offset;
49                 uint32_t page_size;
50         } region;
51 };
52
53 #define NFP_RESOURCE_TBL_SIZE           4096
54 #define NFP_RESOURCE_TBL_ENTRIES        (int)(NFP_RESOURCE_TBL_SIZE /   \
55                                          sizeof(struct nfp_resource_entry))
56
57 struct nfp_resource {
58         char name[NFP_RESOURCE_ENTRY_NAME_SZ + 1];
59         uint32_t cpp_id;
60         uint64_t addr;
61         uint64_t size;
62         struct nfp_cpp_mutex *mutex;
63 };
64
65 static int
66 nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
67 {
68         char name_pad[NFP_RESOURCE_ENTRY_NAME_SZ] = {};
69         struct nfp_resource_entry entry;
70         uint32_t cpp_id, key;
71         int ret, i;
72
73         cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0);  /* Atomic read */
74
75         memset(name_pad, 0, NFP_RESOURCE_ENTRY_NAME_SZ);
76         strncpy(name_pad, res->name, sizeof(name_pad));
77
78         /* Search for a matching entry */
79         if (!memcmp(name_pad, NFP_RESOURCE_TBL_NAME "\0\0\0\0\0\0\0\0", 8)) {
80                 printf("Grabbing device lock not supported\n");
81                 return -EOPNOTSUPP;
82         }
83         key = nfp_crc32_posix(name_pad, sizeof(name_pad));
84
85         for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
86                 uint64_t addr = NFP_RESOURCE_TBL_BASE +
87                         sizeof(struct nfp_resource_entry) * i;
88
89                 ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry));
90                 if (ret != sizeof(entry))
91                         return -EIO;
92
93                 if (entry.mutex.key != key)
94                         continue;
95
96                 /* Found key! */
97                 res->mutex =
98                         nfp_cpp_mutex_alloc(cpp,
99                                             NFP_RESOURCE_TBL_TARGET, addr, key);
100                 res->cpp_id = NFP_CPP_ID(entry.region.cpp_target,
101                                          entry.region.cpp_action,
102                                          entry.region.cpp_token);
103                 res->addr = ((uint64_t)entry.region.page_offset) << 8;
104                 res->size = (uint64_t)entry.region.page_size << 8;
105                 return 0;
106         }
107
108         return -ENOENT;
109 }
110
111 static int
112 nfp_resource_try_acquire(struct nfp_cpp *cpp, struct nfp_resource *res,
113                          struct nfp_cpp_mutex *dev_mutex)
114 {
115         int err;
116
117         if (nfp_cpp_mutex_lock(dev_mutex))
118                 return -EINVAL;
119
120         err = nfp_cpp_resource_find(cpp, res);
121         if (err)
122                 goto err_unlock_dev;
123
124         err = nfp_cpp_mutex_trylock(res->mutex);
125         if (err)
126                 goto err_res_mutex_free;
127
128         nfp_cpp_mutex_unlock(dev_mutex);
129
130         return 0;
131
132 err_res_mutex_free:
133         nfp_cpp_mutex_free(res->mutex);
134 err_unlock_dev:
135         nfp_cpp_mutex_unlock(dev_mutex);
136
137         return err;
138 }
139
140 /*
141  * nfp_resource_acquire() - Acquire a resource handle
142  * @cpp:        NFP CPP handle
143  * @name:       Name of the resource
144  *
145  * NOTE: This function locks the acquired resource
146  *
147  * Return: NFP Resource handle, or ERR_PTR()
148  */
149 struct nfp_resource *
150 nfp_resource_acquire(struct nfp_cpp *cpp, const char *name)
151 {
152         struct nfp_cpp_mutex *dev_mutex;
153         struct nfp_resource *res;
154         int err;
155         struct timespec wait;
156         int count;
157
158         res = malloc(sizeof(*res));
159         if (!res)
160                 return NULL;
161
162         memset(res, 0, sizeof(*res));
163
164         strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ);
165
166         dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
167                                         NFP_RESOURCE_TBL_BASE,
168                                         NFP_RESOURCE_TBL_KEY);
169         if (!dev_mutex) {
170                 free(res);
171                 return NULL;
172         }
173
174         wait.tv_sec = 0;
175         wait.tv_nsec = 1000000;
176         count = 0;
177
178         for (;;) {
179                 err = nfp_resource_try_acquire(cpp, res, dev_mutex);
180                 if (!err)
181                         break;
182                 if (err != -EBUSY)
183                         goto err_free;
184
185                 if (count++ > 1000) {
186                         printf("Error: resource %s timed out\n", name);
187                         err = -EBUSY;
188                         goto err_free;
189                 }
190
191                 nanosleep(&wait, NULL);
192         }
193
194         nfp_cpp_mutex_free(dev_mutex);
195
196         return res;
197
198 err_free:
199         nfp_cpp_mutex_free(dev_mutex);
200         free(res);
201         return NULL;
202 }
203
204 /*
205  * nfp_resource_release() - Release a NFP Resource handle
206  * @res:        NFP Resource handle
207  *
208  * NOTE: This function implictly unlocks the resource handle
209  */
210 void
211 nfp_resource_release(struct nfp_resource *res)
212 {
213         nfp_cpp_mutex_unlock(res->mutex);
214         nfp_cpp_mutex_free(res->mutex);
215         free(res);
216 }
217
218 /*
219  * nfp_resource_cpp_id() - Return the cpp_id of a resource handle
220  * @res:        NFP Resource handle
221  *
222  * Return: NFP CPP ID
223  */
224 uint32_t
225 nfp_resource_cpp_id(const struct nfp_resource *res)
226 {
227         return res->cpp_id;
228 }
229
230 /*
231  * nfp_resource_name() - Return the name of a resource handle
232  * @res:        NFP Resource handle
233  *
234  * Return: const char pointer to the name of the resource
235  */
236 const char
237 *nfp_resource_name(const struct nfp_resource *res)
238 {
239         return res->name;
240 }
241
242 /*
243  * nfp_resource_address() - Return the address of a resource handle
244  * @res:        NFP Resource handle
245  *
246  * Return: Address of the resource
247  */
248 uint64_t
249 nfp_resource_address(const struct nfp_resource *res)
250 {
251         return res->addr;
252 }
253
254 /*
255  * nfp_resource_size() - Return the size in bytes of a resource handle
256  * @res:        NFP Resource handle
257  *
258  * Return: Size of the resource in bytes
259  */
260 uint64_t
261 nfp_resource_size(const struct nfp_resource *res)
262 {
263         return res->size;
264 }