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