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