xref: /dpdk/drivers/net/nfp/nfpcore/nfp_resource.c (revision b6de43530dfa30cbf6b70857e3835099701063d4)
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 		PMD_DRV_LOG(ERR, "RESOURCE - Malloc NSP memory failed.");
166 		return NULL;
167 	}
168 
169 	memset(res, 0, sizeof(*res));
170 
171 	strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ);
172 
173 	dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
174 			NFP_RESOURCE_TBL_BASE, NFP_RESOURCE_TBL_KEY);
175 	if (dev_mutex == NULL) {
176 		PMD_DRV_LOG(ERR, "RESOURCE - CPP mutex alloc failed.");
177 		goto err_free;
178 	}
179 
180 	wait.tv_sec = 0;
181 	wait.tv_nsec = 1000000;    /* 1ms */
182 
183 	for (;;) {
184 		err = nfp_resource_try_acquire(cpp, res, dev_mutex);
185 		if (err == 0)
186 			break;
187 		if (err != -EBUSY) {
188 			PMD_DRV_LOG(ERR, "RESOURCE - try acquire failed.");
189 			goto mutex_free;
190 		}
191 
192 		if (count++ > 1000) {    /* 1ms * 1000 = 1s */
193 			PMD_DRV_LOG(ERR, "Error: resource %s timed out.", name);
194 			goto mutex_free;
195 		}
196 
197 		nanosleep(&wait, NULL);
198 	}
199 
200 	nfp_cpp_mutex_free(dev_mutex);
201 
202 	return res;
203 
204 mutex_free:
205 	nfp_cpp_mutex_free(dev_mutex);
206 err_free:
207 	free(res);
208 	return NULL;
209 }
210 
211 /**
212  * Release a NFP Resource handle
213  *
214  * NOTE: This function implicitly unlocks the resource handle.
215  *
216  * @param res
217  *   NFP Resource handle
218  */
219 void
220 nfp_resource_release(struct nfp_resource *res)
221 {
222 	nfp_cpp_mutex_unlock(res->mutex);
223 	nfp_cpp_mutex_free(res->mutex);
224 	free(res);
225 }
226 
227 /**
228  * Return the cpp_id of a resource handle
229  *
230  * @param res
231  *   NFP Resource handle
232  *
233  * @return
234  *   NFP CPP ID
235  */
236 uint32_t
237 nfp_resource_cpp_id(const struct nfp_resource *res)
238 {
239 	return res->cpp_id;
240 }
241 
242 /**
243  * Return the name of a resource handle
244  *
245  * @param res
246  *   NFP Resource handle
247  *
248  * @return
249  *   Const char pointer to the name of the resource
250  */
251 const char *
252 nfp_resource_name(const struct nfp_resource *res)
253 {
254 	return res->name;
255 }
256 
257 /**
258  * Return the address of a resource handle
259  *
260  * @param res
261  *   NFP Resource handle
262  *
263  * @return
264  *   Address of the resource
265  */
266 uint64_t
267 nfp_resource_address(const struct nfp_resource *res)
268 {
269 	return res->addr;
270 }
271 
272 /**
273  * Return the size in bytes of a resource handle
274  *
275  * @param res
276  *   NFP Resource handle
277  *
278  * @return
279  *   Size of the resource in bytes
280  */
281 uint64_t
282 nfp_resource_size(const struct nfp_resource *res)
283 {
284 	return res->size;
285 }
286