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